# Ventia CRM API > # First steps Welcome to the documentation for the public API of Ventia CRM module. Ventia has differents module and the module who have available API are: - CRM - Sales Manager - People ## Authentication All request on Ventia require a valid API Key passed as query string on the request. Example: `https://api.getventia.com/api/v1.0/contact?api-key=AAAAAAA-BBBBBBB-CCCCCCC-DDDDDDD` ### Authentication error response If an API key is missing, malformed, or invalid, you will receive an HTTP 401 Unauthorized response code. ## Rate and usage limits To ensure the best possible performance and availability for all our users, we have implemented rate and usage limits on our API. These limits are designed to prevent any single user from consuming excessive resources and negatively impacting the experience for others. ### Maximum Requests Per Minute Our API enforces a maximum limit of **200 requests per minute (RPM)**. This means that you can make up to 200 requests within a one-minute time frame. If you exceed this limit, your requests will be throttled, and you will receive an HTTP 429 "Too Many Requests" response. Please note that the rate limit is applied on a per-account basis, so all API keys associated with a single account will share the same limit. ## Pagination When fetching a endpoint who has a list, pagination is used by default. To controll the pagination use on the url on the querystring : `?page=1` to controll the page you'r viewing (1-indexed; the first page is `1`) `?limit=100` to controll the page size (default `10`) Paginated responses include the following headers: - `X-Total-Count` — total number of records matching the query - `X-Total-Pages` — total number of pages - `X-Current-Page` — page returned - `X-Per-Page` — page size ### **Need some help?** If you need support you can use our support via email or support chat on Ventia - **Base URL:** `https://api.getventia.com/api/v1.0` - **Authentication:** API Key via query string (`?api-key=YOUR_API_KEY`) - **Rate limit:** 200 requests per minute - **Docs site:** https://developer.getventia.com This document contains the complete Ventia CRM public API reference in Markdown. ## Contact ### GET `/contacts` — List contacts _Operation ID: `Listcontacts`_ **Query parameters:** - `page`: integer — Page number to return (1-indexed). Defaults to `1`. - `limit`: integer — Number of contacts to return per page. Defaults to `10`. - `search`: string — Case-insensitive substring to match against the contact field specified by `field`. Must be used together with `field`. - `field`: string — Contact field to apply `search` against. Supports top-level fields (e.g. `firstName`, `lastName`, `emails`, `phones`) and custom fields via `additionalData.`. The `company` field is not allowed. - `campaignId`: string — Filter contacts associated with the given Ventia campaign id. Must be a valid ObjectId; matches contacts whose `campaigns` array contains this id. - `agent`: string — Filter contacts assigned to the specified agent. Must be a valid ObjectId; returns only contacts associated with this agent. - `firstAgent`: string — Filter contacts that were initially assigned to the specified seller. Must be a valid ObjectId; returns only contacts whose first assigned seller matches this id. - `sort`: enum("+createdAt" | "-createdAt" | "+lastInteraction" | "-lastInteraction" | "+lastInteractionDate" | "-lastInteractionDate") — Sort the results by one of the allowed fields. Prefix with `+` for ascending or `-` for descending (default is ascending). Allowed fields: `createdAt`, `lastInteraction`, `lastInteractionDate`. - `gteCreatedAt`: string — Return contacts created on or after this date (ISO 8601). Date filters can be combined with their `lte`/`lt`/`gt` counterparts to build a range. - `lteCreatedAt`: string — Return contacts created on or before this date (ISO 8601). - `gtCreatedAt`: string — Return contacts created strictly after this date (ISO 8601). - `ltCreatedAt`: string — Return contacts created strictly before this date (ISO 8601). - `gteLastInteractionDate`: string — Return contacts whose last interaction is on or after this date (ISO 8601). - `lteLastInteractionDate`: string — Return contacts whose last interaction is on or before this date (ISO 8601). - `gtLastInteractionDate`: string — Return contacts whose last interaction is strictly after this date (ISO 8601). - `ltLastInteractionDate`: string — Return contacts whose last interaction is strictly before this date (ISO 8601). **Responses:** - `200`: OK - array of objects: - `_id`: string (required) - `company`: string (required) - `firstName`: string (required) - `lastName`: string (required) - `origin`: string (required) - `phones`: string[] (required) - `agent`: string (required) - `agentAssigned`: string (required) - `archivingReason`: string (required) - `status`: string (required) - `emails`: string[] (required) - `detail`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) - `lastInteraction`: string (required) - `archivingReasonText`: string (required) - `agentFullName`: string (required) Example response: ```json [ { "_id": "621e8a5463c02a8bd532ff8c", "company": "609b3cff61ffd5f1e446d234", "firstName": "Agustin", "lastName": "Suarez", "origin": "local", "phones": [ "+59897123678" ], "agent": "6234da84259c59d9a555c498", "firstAgent": "6234da84259c59d9a555c498", "agentAssigned": "2022-03-01T21:04:20.611Z", "archivingReason": "", "status": "closed", "emails": [], "detail": "", "createdAt": "2022-03-01T21:04:20.617Z", "updatedAt": "2022-05-20T16:00:00.004Z", "__v": 0, "lastInteraction": "2022-05-20T16:00:00.004Z", "archivingReasonText": "", "agentFullName": "Agente Uno" } ] ``` --- ### GET `/contact/{idcontact}` — Get one contact _Operation ID: `Getonecontact`_ **Path parameters:** - `idcontact`: string (required) **Responses:** - `200`: OK - `_id`: string (required) - `company`: string (required) - `firstName`: string (required) - `lastName`: string (required) - `origin`: string (required) - `phones`: string[] (required) - `agent`: string (required) - `agentAssigned`: string (required) - `archivingReason`: string (required) - `status`: string (required) - `emails`: string[] (required) - `detail`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) - `lastInteraction`: string (required) - `archivingReasonText`: string (required) - `agentFullName`: string (required) Example response: ```json { "_id": "621e8a5463c02a8bd532ff8c", "company": "609b3cff61ffd5f1e446d234", "firstName": "Agustin", "lastName": "Suarez", "origin": "local", "phones": [ "+59897123456" ], "agent": "6234da84259c59d9a555c498", "firstAgent": "6234da84259c59d9a555c498", "agentAssigned": "2022-03-01T21:04:20.611Z", "archivingReason": "", "status": "closed", "emails": [], "detail": "", "createdAt": "2022-03-01T21:04:20.617Z", "updatedAt": "2022-05-20T16:00:00.004Z", "__v": 0, "lastInteraction": "2022-05-20T16:00:00.004Z", "archivingReasonText": "", "agentFullName": "Agente" } ``` --- ### PATCH `/contact/{idcontact}` — Modify contact _Operation ID: `Modifycontact`_ **Path parameters:** - `idcontact`: string (required) **Request body:** - `firstName`: string (required) - `lastName`: string (required) - `emails`: string[] (required) - `phones`: string[] (required) - `detail`: string (required) - `origin`: string (required) **Responses:** - `200`: OK - `_id`: string (required) - `company`: string (required) - `firstName`: string (required) - `lastName`: string (required) - `origin`: string (required) - `phones`: string[] (required) - `archivingReason`: string (required) - `status`: string (required) - `emails`: string[] (required) - `detail`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) - `lastInteraction`: string (required) - `archivingReasonText`: string (required) - `assignedGroups`: string[] (required) - `attention`: string (required) - `channels`: string[] (required) - `databaseUploded`: boolean (required) - `reminder`: string (required) Example response: ```json { "_id": "621e8a5463c02a8bd532ff8c", "company": "609b3cff61ffd5f1e446d234", "firstName": "Agustin", "lastName": "Perez", "origin": "local", "phones": [ "+59897444666" ], "archivingReason": "", "status": "new", "emails": [ "agustin@example.com" ], "detail": "", "createdAt": "2022-03-01T21:04:20.617Z", "updatedAt": "2023-05-23T20:20:25.420Z", "__v": 1, "lastInteraction": "2023-05-23T20:20:25.418Z", "archivingReasonText": "", "assignedGroups": [], "attention": "not_actions", "channels": [], "databaseUploded": false, "reminder": "2023-05-23T20:25:02.561Z" } ``` --- ### GET `/contacts/findone` — Search one contact _Operation ID: `Searchonecontact`_ **Query parameters:** - `q`: string (required) — Search term. Can be contact _id, phone number or email. **Responses:** - `200`: OK - `_id`: string (required) - `company`: string (required) - `firstName`: string (required) - `lastName`: string (required) - `origin`: string (required) - `phones`: string[] (required) - `agent`: string (required) - `agentAssigned`: string (required) - `archivingReason`: string (required) - `status`: string (required) - `emails`: string[] (required) - `detail`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) - `lastInteraction`: string (required) - `archivingReasonText`: string (required) - `agentFullName`: string (required) Example response: ```json { "_id": "621e8a5463c02a8bd532ff8c", "company": "609b3cff61ffd5f1e446d234", "firstName": "Agustin", "lastName": "Suarez", "origin": "local", "phones": [ "+59897123456" ], "agent": "6234da84259c59d9a555c498", "firstAgent": "6234da84259c59d9a555c498", "agentAssigned": "2022-03-01T21:04:20.611Z", "archivingReason": "", "status": "closed", "emails": [], "detail": "", "createdAt": "2022-03-01T21:04:20.617Z", "updatedAt": "2022-05-20T16:00:00.004Z", "__v": 0, "lastInteraction": "2022-05-20T16:00:00.004Z", "archivingReasonText": "", "agentFullName": "Agente" } ``` --- ### GET `/contact/{idcontact}/interactions` — List interactions from one contact _Operation ID: `Listinteractionsfromonecontact`_ **Path parameters:** - `idcontact`: string (required) **Responses:** - `200`: OK - array of objects: - `_id`: string (required) - `content`: object (required) - `reminderDate`: string (required) - `company`: string (required) - `contact`: string (required) - `status`: string (required) - `via`: string (required) - `type`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) Example response: ```json [ { "_id": "6287bb00d81dc586b61dc64f", "content": { "reminderDate": null }, "company": "609b3cff61ffd5f1e446d234", "contact": "621e8a5463c02a8bd532ff8c", "status": "started", "via": "server", "type": "reminder", "createdAt": "2022-05-20T16:00:00.006Z", "updatedAt": "2022-05-20T16:00:00.006Z", "__v": 0 } ] ``` --- ### POST `/contact` — Create contact _Operation ID: `Createcontact`_ **Query parameters:** - `skipValidations`: string — Allows skipping required field validations. **Request body:** - string **Responses:** - `200`: OK - `company`: string (required) - `firstName`: string (required) - `lastName`: string (required) - `origin`: string (required) - `originText`: string (required) - `phones`: string[] (required) - `agent`: string (required) - `agentFullName`: string (required) - `firstAgent`: string (required) - `firstAgentFullName`: string (required) - `agentAssigned`: string (required) - `archivingReason`: string (required) - `archivingReasonText`: string (required) - `status`: string (required) - `attention`: string (required) - `emails`: string[] (required) - `detail`: string (required) - `stats`: object (required) - `visits`: integer (required) - `createdCoords`: object (required) - `active`: boolean (required) - `contactLocation`: object (required) - `location`: boolean (required) - `databaseUploded`: boolean (required) - `channels`: string[] (required) - `assignedGroups`: string[] (required) - `_id`: string (required) - `lastInteraction`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) Example response: ```json { "company": "609b3cff61ffd5f1e446d234", "firstName": "Agustin", "lastName": "Suarez", "origin": "local", "originText": "Local", "phones": [ "+59894444666" ], "agent": "609d8512ee84d2388bde2353", "agentFullName": "Agent Name", "firstAgent": "609d8512ee84d2388bde2353", "firstAgentFullName": "Agent Name", "agentAssigned": "2023-05-18T17:55:17.559Z", "archivingReason": "", "archivingReasonText": "", "status": "new", "attention": "not_actions", "emails": [ "agustin@example.com" ], "detail": "", "stats": { "visits": 0 }, "createdCoords": { "active": false }, "contactLocation": { "location": false }, "databaseUploded": false, "channels": [], "assignedGroups": [], "_id": "64666685696358053f46c33a", "lastInteraction": "2023-05-18T17:55:17.560Z", "createdAt": "2023-05-18T17:55:17.561Z", "updatedAt": "2023-05-18T17:55:17.561Z", "__v": 0 } ``` --- ### POST `/lead` — Create lead _Operation ID: `Createlead`_ ### Add Lead This endpoint allows you to create campaing leads. Campaing leads are created as contacts if they dosen't exist on the database, but if it exists, ventia notifiys the agent owner of the contact with a note. **Request body:** - `firstName`: string (required) - `lastName`: string (required) - `emails`: string[] (required) - `phones`: string[] (required) - `detail`: string (required) - `origin`: string (required) - `agent`: string (required) **Responses:** - `200`: OK - `company`: string (required) - `firstName`: string (required) - `lastName`: string (required) - `origin`: string (required) - `originText`: string (required) - `phones`: string[] (required) - `agent`: string (required) - `agentFullName`: string (required) - `firstAgent`: string (required) - `firstAgentFullName`: string (required) - `agentAssigned`: string (required) - `archivingReason`: string (required) - `archivingReasonText`: string (required) - `status`: string (required) - `attention`: string (required) - `emails`: string[] (required) - `detail`: string (required) - `stats`: object (required) - `visits`: integer (required) - `createdCoords`: object (required) - `active`: boolean (required) - `contactLocation`: object (required) - `location`: boolean (required) - `databaseUploded`: boolean (required) - `channels`: string[] (required) - `assignedGroups`: string[] (required) - `_id`: string (required) - `lastInteraction`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) Example response: ```json { "company": "609b3cff61ffd5f1e446d234", "firstName": "Agustin", "lastName": "Suarez", "origin": "local", "originText": "Local", "phones": [ "+59894444666" ], "agent": "609d8512ee84d2388bde2353", "agentFullName": "Agent Name", "firstAgent": "609d8512ee84d2388bde2353", "firstAgentFullName": "Agent Name", "agentAssigned": "2023-05-18T17:55:17.559Z", "archivingReason": "", "archivingReasonText": "", "status": "new", "attention": "not_actions", "emails": [ "agustin@example.com" ], "detail": "", "stats": { "visits": 0 }, "createdCoords": { "active": false }, "contactLocation": { "location": false }, "databaseUploded": false, "channels": [], "assignedGroups": [], "_id": "64666685696358053f46c33a", "lastInteraction": "2023-05-18T17:55:17.560Z", "createdAt": "2023-05-18T17:55:17.561Z", "updatedAt": "2023-05-18T17:55:17.561Z", "__v": 0 } ``` --- ## Interactions ### GET `/interactions` — List interactions _Operation ID: `Listinteractions`_ **Responses:** - `200`: OK - array of objects: - `_id`: string (required) - `content`: object (required) - `body`: string (required) - `company`: string (required) - `agent`: string (required) - `contact`: string (required) - `status`: string (required) - `via`: string (required) - `type`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) Example response: ```json [ { "_id": "624b480631ea46a2248a85ad", "content": { "body": "this is a note" }, "company": "609b3cff61ffd5f1e446d234", "agent": "6234da84259c59d9a555c498", "contact": "624b2c9631ea46a22486c6a6", "status": "started", "via": "web", "type": "note", "createdAt": "2022-04-04T19:33:26.303Z", "updatedAt": "2022-04-04T19:33:26.303Z", "__v": 0 } ] ``` --- ### POST `/contact/{idcontact}/note` — Create note _Operation ID: `Createnote`_ **Path parameters:** - `idcontact`: string (required) **Request body:** - `body`: string (required) - `title`: string **Responses:** - `200`: OK - `interactionId`: string (required) - `message`: string (required) - `success`: boolean (required) Example response: ```json { "interactionId": "69a20fc26c9dcd1f79205a74", "message": "Note created...", "success": true } ``` --- ### POST `/contact/{idcontact}/archive` — Archive contact _Operation ID: `Archivecontact`_ **Path parameters:** - `idcontact`: string (required) **Request body:** - `reason`: string (required) **Responses:** - `200`: OK - `archive`: object (required) - `content`: object (required) - `from`: string (required) - `to`: string (required) - `_id`: string (required) - `company`: string (required) - `agent`: string (required) - `contact`: string (required) - `status`: string (required) - `via`: string (required) - `createdCoords`: object (required) - `active`: boolean (required) - `type`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) Example response: ```json { "archive": { "content": { "from": "", "to": "notclient" }, "_id": "646d13f254f8f1d196927794", "company": "609b3cff61ffd5f1e446d234", "agent": "6234da84259c59d9a555c498", "contact": "621e8a5463c02a8bd532ff8c", "status": "started", "via": "api", "createdCoords": { "active": false }, "type": "archiving", "createdAt": "2023-05-23T19:28:50.867Z", "updatedAt": "2023-05-23T19:28:50.867Z", "__v": 0 } } ``` --- ### POST `/contact/{idcontact}/transfer` — Transfer contact _Operation ID: `Transfercontact`_ **Path parameters:** - `idcontact`: string (required) **Request body:** - `to`: string (required) - `description`: string **Responses:** - `200`: OK - `success`: boolean - `message`: string Example response: ```json { "message": "The contact was successfully transfered...", "success": true } ``` --- ### POST `/contact/{idcontact}/message` — Create message _Operation ID: `Createmessage`_ Sends an outgoing message to a contact through any supported channel or personal WhatsApp session. Exactly one send-target must be provided in the body: - `channelId` — send through a shared channel (`unofficial_wpp`, `whatsapp_business`, `fb`, or `ig`). - `userId` + `medium` — send through a user's personal WhatsApp session. `medium: "unofficial_wpp"` uses the agent's Baileys session; `medium: "whatsapp_business"` uses their active Meta Cloud (WhatsApp Business) integration. - `userIntegrationId` — send through a specific WhatsApp Business personal integration by ID (shortcut for `userId` + `medium: "whatsapp_business"` when the integration is already known). The message content itself is one of: plain `text`, media (`mediaType` + `mediaUrl`), or an approved WhatsApp Business `template` ID. Templates are only supported on `whatsapp_business` channels and on personal WhatsApp Business integrations — they are rejected on unofficial (Baileys) sessions. The legacy `whatsapp_360_dialog` channel type is no longer supported. **Path parameters:** - `idcontact`: string (required) — Unique identifier of the recipient contact as registered on the Ventia platform. **Request body:** - `channelId`: string — ID of a shared channel to send through. Must belong to the authenticated company. The channel's type (`unofficial_wpp`, `whatsapp_business`, `fb`, or `ig`) determines which provider is invoked. Mutually exclusive with `userId` and `userIntegrationId`. - `userId`: string — ID of a user whose personal WhatsApp session will send the message. Requires `medium` to disambiguate between the user's Baileys (`unofficial_wpp`) and Meta Cloud (`whatsapp_business`) integrations. Mutually exclusive with `channelId` and `userIntegrationId`. - `medium`: enum("unofficial_wpp" | "whatsapp_business") — Required when `userId` is used. Selects which of the user's personal WhatsApp integrations to send through. - `userIntegrationId`: string — ID of a specific personal WhatsApp Business integration (Meta Cloud) to send through. Shortcut for `userId` + `medium: "whatsapp_business"` when the integration is already known. Mutually exclusive with `channelId` and `userId`. - `text`: string — Plain-text body of the message. Required unless `mediaType` or `template` is provided. - `mediaType`: enum("image" | "audio" | "video" | "file") — Type of attached media. When set, `mediaUrl` is required. - `mediaUrl`: string — Publicly accessible URL of the media file. Required when `mediaType` is set. - `mimetype`: string — MIME type of the media file (e.g. `image/jpeg`, `application/pdf`). Useful when the URL does not advertise it. - `fileName`: string — Original filename for media sent as a document. - `caption`: string — Optional caption for media messages. Also used as the message body when `text` is absent. - `template`: string — ID of a pre-approved WhatsApp Business template to send. Only supported on `whatsapp_business` channels and on personal WhatsApp Business integrations (`userId` + `medium: "whatsapp_business"` or `userIntegrationId`). Requests combining `template` with unofficial WhatsApp or other media types are rejected. - `replyMessage`: string — ID of a prior message this one replies to (when the channel supports quoted replies). - `localId`: string — Client-supplied temporary ID echoed back for optimistic UIs. Optional. **Responses:** - `200`: Message was accepted and delivered to the underlying channel. Returned for WhatsApp (official, unofficial, channel, and personal) sends where the dispatch is synchronous. - `success`: boolean - `interactionId`: string — ID of the interaction record created for this outgoing message. - `202`: Message was queued for delivery. Returned for Facebook and Instagram channels, which dispatch asynchronously. - `success`: boolean - `queued`: boolean - `400`: Request could not be parsed: malformed JSON, failing Zod validation, ambiguous or missing send-target, or invalid ObjectId in the URL path. - `success`: boolean - `error`: string - `details`: string - `401`: Missing or invalid API key. - `success`: boolean - `error`: string - `409`: The send-target exists but could not dispatch right now — e.g. the Baileys session is offline, or the downstream provider returned a transient error. - `success`: boolean - `error`: string - `422`: Body was syntactically valid but references a resource that doesn't exist or isn't usable in the current configuration — contact not found, channel not in company, deprecated channel type, template on wrong medium, user without a personal session, missing personal WhatsApp Business integration, `TEMPLATE_NOT_FOUND`, or `CONTACT_WITHOUT_PHONE_NUMBER`. - `success`: boolean - `error`: string - `500`: Unexpected server error while processing the send. - `success`: boolean - `error`: string - `details`: string --- ### POST `/contact/{idcontact}/reminder` — Create reminder _Operation ID: `Createreminder`_ **Path parameters:** - `idcontact`: string (required) **Request body:** - `reminderDate`: string (required) **Responses:** - `200`: OK - `message`: string (required) - `reminder`: object (required) - `content`: object (required) - `reminderDate`: string (required) - `_id`: string (required) - `company`: string (required) - `agent`: string (required) - `contact`: string (required) - `status`: string (required) - `via`: string (required) - `createdCoords`: object (required) - `active`: boolean (required) - `type`: string (required) - `createdAt`: string (required) - `updatedAt`: string (required) - `__v`: integer (required) Example response: ```json { "message": "Reminder created", "reminder": { "content": { "reminderDate": "2023-05-23T20:25:02.561Z" }, "_id": "646d13b754f8f1d196927187", "company": "609b3cff61ffd5f1e446d234", "agent": "6234da84259c59d9a555c498", "contact": "621e8a5463c02a8bd532ff8c", "status": "started", "via": "api", "createdCoords": { "active": false }, "type": "reminder", "createdAt": "2023-05-23T19:27:51.406Z", "updatedAt": "2023-05-23T19:27:51.406Z", "__v": 0 } } ``` --- ## Users ### GET `/users` — Get users _Operation ID: `Getusers`_ **Responses:** - `200`: OK - array of objects: - `_id`: string (required) - `roles`: string[] (required) - `name`: string (required) - `lastname`: string (required) - `email`: string (required) - `phone_work`: string (required) - `group`: string (required) - `firstLogin`: boolean (required) Example response: ```json [ { "_id": "609d8512ee84d2388bde2353", "roles": [ "user" ], "name": "Agustin", "lastname": "Suarez", "email": "agustin@example.com", "phone_work": "097123456", "group": "609b3cff61ffd5f1e446d234", "firstLogin": true } ] ``` --- ### POST `/users` — Create user Creates a new user in the system with the provided details. **Request body:** - `name`: string (required) — The user's first name - `lastname`: string (required) — The user's last name - `email`: string (required) — The user's email address - `password`: string (required) — The user's password - `phone_work`: string — The user's work phone number - `roles`: enum("user" | "comercial" | "super")[] — The user's roles **Responses:** - `200`: User successfully created - `_id`: string — User ID - `name`: string — The user's first name - `lastname`: string — The user's last name - `email`: string — The user's email address - `phone_work`: string — The user's work phone number - `group`: string — The user's group ID - `roles`: string[] — The user's roles - `firstLogin`: boolean — User is logging in for the first time Example response: ```json { "_id": "64b7654c3f3ae9b9d1e7c5d8", "name": "John", "lastname": "Doe", "email": "john.doe@example.com", "phone_work": "+1234567890", "group": "64b7654c3f3ae9b9d1e7c5d7", "roles": [ "user", "comercial" ], "firstLogin": true } ``` - `400`: Invalid request parameters - `401`: Unauthorized - `500`: Internal server error --- ### GET `/users/{id}` — Get a user by ID Retrieves a user by the `id` parameter. Only active users belonging to the authenticated group or its descendant groups are returned. **Path parameters:** - `id`: string (required) **Header parameters:** - `X-API-KEY`: string (required) **Responses:** - `200`: User retrieved successfully - `_id`: string — User ID - `name`: string — The user's first name - `lastname`: string — The user's last name - `email`: string — The user's email address - `phone_work`: string — The user's work phone number - `firstLogin`: string — The date of the user's first login - `group`: string — The ID of the group to which the user belongs - `roles`: string[] — The roles assigned to the user Example response: ```json { "_id": "64b7654c3f3ae9b9d1e7c5d8", "name": "John", "lastname": "Doe", "email": "john.doe@example.com", "phone_work": "+1234567890", "firstLogin": "2024-01-01T12:00:00Z", "group": "64b7654c3f3ae9b9d1e7c5d7", "roles": [ "user", "super" ] } ``` - `400`: Invalid user ID - `error`: string - `401`: Unauthorized, invalid API key or group - `error`: string - `404`: User not found - `error`: string - `500`: Internal server error --- ### PUT `/users/{id}` — Fully update or replace an existing user Replaces the entire user identified by the `id` parameter. **Path parameters:** - `id`: string (required) — The ID of the user to be updated **Request body:** - `name`: string — The user's first name - `lastname`: string — The user's last name - `email`: string — The user's email address - `phone_work`: string — The user's work phone number - `roles`: enum("user" | "comercial" | "super")[] — The user's roles **Responses:** - `200`: User successfully updated - `_id`: string — User ID - `name`: string — The user's first name - `lastname`: string — The user's last name - `email`: string — The user's email address - `phone_work`: string — The user's work phone number - `group`: string — The user's group ID - `roles`: string[] — The user's roles Example response: ```json { "_id": "64b7654c3f3ae9b9d1e7c5d8", "name": "John", "lastname": "Doe", "email": "john.doe@example.com", "phone_work": "+1234567890", "group": "64b7654c3f3ae9b9d1e7c5d7", "roles": [ "user", "super" ] } ``` - `400`: Invalid user ID or validation error - `401`: Unauthorized - `404`: User not found - `500`: Internal server error --- ### PATCH `/users/{id}` — Partially update an existing user Updates one or more fields of a user identified by the `id` parameter. **Path parameters:** - `id`: string (required) — The ID of the user to be updated **Request body:** - `name`: string — The user's first name - `lastname`: string — The user's last name - `email`: string — The user's email address - `phone_work`: string — The user's work phone number - `roles`: enum("user" | "comercial" | "super")[] — The user's roles **Responses:** - `200`: User successfully updated - `_id`: string — User ID - `name`: string — The user's first name - `lastname`: string — The user's last name - `email`: string — The user's email address - `phone_work`: string — The user's work phone number - `group`: string — The user's group ID - `roles`: string[] — The user's roles Example response: ```json { "_id": "64b7654c3f3ae9b9d1e7c5d8", "name": "Jane", "lastname": "Doe", "email": "jane.doe@example.com", "phone_work": "+9876543210", "group": "64b7654c3f3ae9b9d1e7c5d7", "roles": [ "comercial" ] } ``` - `400`: Invalid user ID or validation error - `401`: Unauthorized - `404`: User not found - `500`: Internal server error --- ## Groups ### GET `/groups` — Get groups _Operation ID: `Getgroups`_ **Responses:** - `200`: OK - array of objects: - `_id`: string (required) - `descendants`: string[] (required) - `ancestors`: string[] (required) - `name`: string (required) - `displayName`: string (required) - `businessName`: string (required) - `country`: string (required) - `archivingReasons`: object[] (required) - array of objects: - `name`: string (required) - `code`: string (required) - `active`: boolean (required) - `type`: string (required) - `_id`: string (required) - `origins`: object[] (required) - array of objects: - `name`: string (required) - `code`: string (required) - `active`: boolean (required) - `ghost`: boolean (required) - `_id`: string (required) - `visitResults`: object[] (required) - array of objects: - `name`: string (required) - `code`: string (required) - `type`: string (required) - `active`: boolean (required) - `ghost`: boolean (required) - `group`: string (required) - `_id`: string (required) - `additionalDataFields`: object[] (required) - array of objects: - `name`: string (required) - `code`: string (required) - `type`: string (required) - `active`: boolean (required) - `required`: boolean (required) - `ghost`: boolean (required) - `group`: string (required) - `options`: string[] (required) - `_id`: string (required) - `statusTags`: string[] (required) Example response: ```json [ { "_id": "609b3cff61ffd5f1e446d234", "descendants": [ "609ecaec8e2966c543cce9d0" ], "ancestors": [], "name": "Company Amazing", "displayName": "Amazing", "businessName": "Amazing SAS", "country": "uy", "archivingReasons": [ { "name": "Not work", "code": "notwork", "active": true, "type": "normal", "_id": "62a8e944ce93810e2941ceee" } ], "origins": [ { "name": "Store", "code": "store", "active": false, "ghost": false, "_id": "6369166819c8b5ece25fcb75" } ], "visitResults": [ { "name": "Talked with owner", "code": "ownertalk", "type": "done", "active": true, "ghost": false, "group": "609b3cff61ffd5f1e446d234", "_id": "62e8232ee1ba4d62b8917e22" } ], "additionalDataFields": [ { "name": "House name", "code": "housename", "type": "string", "active": true, "required": true, "ghost": false, "group": "609b3cff61ffd5f1e446d234", "options": [], "_id": "62f190b984d30b2740f7c372" } ], "statusTags": [] } ] ``` --- ## Sales ### GET `/sales` — Get sales data Retrieves sales data filtered with pagination. **Query parameters:** - `page`: integer — Page number for pagination. - `limit`: integer — Number of items per page. **Responses:** - `200`: Successful response with sales data - `data`: object[] - array of objects: - `_id`: string — Unique ID for the receipt. - `company`: string — Company ID associated with the sale. - `user`: object - `createdAt`: string — Creation date of the receipt. - `pagination`: object - `totalItems`: integer — Total number of items. - `totalPages`: integer — Total number of pages. - `currentPage`: integer — Current page number. - `401`: Unauthorized - Invalid API KEY Group - `error`: string - `404`: Invalid query - `error`: string - `zError`: string --- ### POST `/sales` — Create a new sale Creates a new sale record in the system. **Request body:** - `status`: string (required) — The status of the sale to match in system. - `ticket_id`: string (required) — ID of the ticket. - `ticket_sale_id`: string — ID of the ticket sale. - `date_sale`: string — Sale date. Accepted format: yyyy/mm/dd or yyyy-mm-dd. - `date`: string — Sale date. Accepted format: yyyy/mm/dd or yyyy-mm-dd. - `type`: string — Type of sale. - `phone`: string (required) — Customer's phone number. - `name`: string — Customer's name. - `gov_id`: string — Customer's government ID. - `user`: string (required) — ID of the user making the sale. **Responses:** - `200`: Sale created successfully - `ticket_id`: string — ID of the ticket. - `ticket_sale_id`: string — ID of the ticket sale. - `date`: string — Transaction date. - `date_sale`: string — Sale date. - `name`: string — Customer's name. - `phone`: string — Customer's phone number. - `secondary_phones`: string[] — List of secondary phone numbers. - `gov_id`: string — Customer's government ID. - `status`: string — The status of the sale. - `status_lock`: boolean — Indicates if the status is locked. - `sold`: boolean — Indicates if the sale is completed. - `cancel`: boolean — Indicates if the sale is canceled. - `lock`: boolean — Indicates if the sale is locked. - `user`: string — ID of the user making the sale. - `user_string`: string — User's full name. - `user_lock`: boolean — Indicates if the user is locked. - `user_edit`: boolean — Indicates if the user can edit the sale. - `company`: string — ID of the company. - `importation`: string — Importation method. - `value`: number — Value of the sale. - `remove_from_goal`: boolean — Indicates if the sale is removed from the goal. - `comissions`: object[] - `_id`: string — ID of the sale. - `createdAt`: string — Creation timestamp. - `updatedAt`: string — Update timestamp. - `__v`: integer — Version key. - `400`: Invalid request body - `error`: string - `zError`: object - `401`: Unauthorized access (invalid API KEY Group) - `error`: string - `404`: Not found (invalid user, contact, phone, or status) - `error`: string - `500`: Internal server error - `error`: string --- ### GET `/sales/{id}` — Get sale by ID Retrieves a specific sale by its unique ID. **Path parameters:** - `id`: string (required) — The unique ID of the sale. **Responses:** - `200`: Successful response with sale data - `_id`: string — Unique ID of the sale. - `company`: string — Company ID associated with the sale. - `user`: object - `name`: string — First name of the user. - `lastname`: string — Last name of the user. - `createdAt`: string — Date and time when the sale was created. - `400`: Invalid sale ID format - `error`: string - `401`: Unauthorized access (invalid API KEY Group) - `error`: string - `404`: Sale not found - `error`: string --- ### PUT `/sales/{id}` — Upsert sale by ID Updates an existing sale by its unique ID or creates a new one if it doesn't exist. **Path parameters:** - `id`: string (required) — The unique ID of the sale to be upserted. **Request body:** - `status`: string — Status of the sale. - `ticket_id`: string — ID of the ticket related to the sale. - `ticket_sale_id`: string — Optional ID for ticket sale. - `date_sale`: string — Optional sale date. - `date`: string — Optional date of the sale record. - `type`: string — Type of sale. - `phone`: string — Phone number associated with the sale. - `name`: string — Optional name associated with the sale. - `product`: string — Optional product related to the sale. - `gov_id`: string — Optional government ID associated with the sale. - `user`: string — ID of the user responsible for the sale. - `importation`: string — Optional importation method. **Responses:** - `200`: Sale created or updated successfully - `_id`: string — Unique ID of the sale. - `status`: string — Updated or created status of the sale. - `date_sale`: string — Date when the sale occurred. - `phone`: string — Phone number associated with the sale. - `name`: string — Name of the contact. - `user`: string — ID of the user associated with the sale. - `product`: string — Product related to the sale. - `400`: Invalid request body or sale ID format - `error`: string - `401`: Unauthorized access (invalid API KEY Group) - `error`: string - `403`: Access denied or invalid input (e.g., sale locked, invalid date, status mismatch) - `error`: string - `404`: Sale, user, status, or contact not found - `error`: string - `500`: Internal server error - `error`: string --- ### PATCH `/sales/{id}` — Modify sale by ID Updates fields of an existing sale by its unique ID. **Path parameters:** - `id`: string (required) — The unique ID of the sale to be updated. **Request body:** - `status`: string — Status of the sale. - `date_sale`: string — Date when the sale occurred. - `user`: string — ID of the user associated with the sale. **Responses:** - `200`: Sale updated successfully - `_id`: string — Unique ID of the sale. - `user`: string — ID of the user associated with the sale. - `user_string`: string — Name and lastname of the user. - `status`: string — Status of the sale. - `date_sale`: string — Sale date. - `sold`: boolean — Indicates if the sale status is sold. - `400`: Invalid request body or sale ID format - `error`: string - `401`: Unauthorized access (invalid API KEY Group) - `error`: string - `403`: Access denied or invalid input (e.g., sale locked, invalid date, status mismatch) - `error`: string - `404`: Sale, user, or status not found - `error`: string - `500`: Internal server error - `error`: string --- ## LeadEntry ### POST `/leadentry/{code}/new` — Create a new lead entry Validates and creates a new lead entry based on the received data. **Path parameters:** - `code`: string (required) — The unique code of the lead entry form **Request body:** - `firstName`: string - `lastName`: string - `phones`: string[] - `emails`: string[] - `detail`: string - `action_id`: string - `additionalData`: object **Responses:** - `200`: Lead created successfully - `_id`: string - `firstName`: string - `lastName`: string - `phones`: string[] - `emails`: string[] - `detail`: string - `action_id`: string - `additionalData`: object - `400`: Bad request (missing or invalid parameters) - `message`: string - `401`: Unauthorized - Invalid or missing API Key - `message`: string - `404`: Lead entry or required resource not found - `message`: string - `500`: Internal server error - `message`: string --- ## WhatsApp Official ### POST `/whatsapp-business/{channelId}/{contactId}/messages` — Send message _Operation ID: `officialWhatsapp`_ This documentation provides guidelines for sending messages through the official WhatsApp API, with Ventia acting as an intermediary. It covers the supported message types, integration details, and best practices to ensure a seamless messaging experience. The supported message types align with those in the Facebook API. For more details, refer to the official Facebook documentation at https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages/. Some message types are still in development, so please check the documentation below to verify the available types. **Path parameters:** - `channelId`: string (required) - `contactId`: string (required) **Request body:** - `preview_url`: string — Indicates whether a preview of the link will be generated in the WhatsApp message. If present and enabled, WhatsApp will attempt to fetch a preview of the link's content. - `message`: object (required) - `type`: enum("text" | "image" | "video" | "document" | "audio" | "interactive" | "location" | "template") (required) — Type of message to send. A corresponding object must be included based on this type. - `text`: object — Represents a text message. - `body`: string (required) — The text content of the message. - `image`: object — Represents an image message. - `link`: string — URL to access the image file if hosted externally. - `id`: string — WhatsApp media ID for the image. - `caption`: string — Optional caption for the image. - `video`: object — Represents a video message. - `link`: string — URL to access the video file if hosted externally. - `id`: string — WhatsApp media ID for the video. - `caption`: string — Optional caption for the video. - `document`: object — Represents a document message. - `link`: string — URL to access the document file if hosted externally. - `id`: string — WhatsApp media ID for the document. - `caption`: string — Optional caption for the document. - `filename`: string — Optional filename for the document. - `audio`: object — Represents an audio message. - `link`: string — URL to access the audio file if hosted externally. - `id`: string — WhatsApp media ID for the audio. - `interactive`: object — Defines an interactive message that allows user engagement through buttons. The supported interactive type is 'button', where users can tap predefined buttons to send quick replies. - `location`: object — Represents a location message with geographic coordinates. - `longitude`: string (required) — Longitude of the location. - `latitude`: string (required) — Latitude of the location. - `name`: string (required) — Name of the location. - `address`: string (required) — Address of the location. - `template`: object — Allows sending pre-approved WhatsApp message templates that can include variables, media, and buttons. Templates are useful for structured communication, such as notifications or transactional messages. - `name`: string (required) - `language`: object (required) - `components`: object[] **Responses:** - `200`: OK - `400`: Bad Request - `409`: Bad Request - `500`: Internal Server Error --- ## Webhooks ### GET `/webhooks` — Get webhooks _Operation ID: `get-webhooks`_ **Responses:** - `200`: Successfully - `401`: Unauthorized, invalid API key or company not found. - `500`: Internal server error --- ### POST `/webhooks` — Create webhook _Operation ID: `create-webhook`_ **Request body:** - `active`: boolean (required) — Indicates whether the configuration is active. - `name`: string (required) — Identifier name. Must be between 1 and 255 characters. - `callbackUrl`: string (required) — Secure URL (HTTPS) where related events will be sent. - `topics`: enum("interactions.official_whatsapp" | "interactions.official_whatsapp_statuses")[] — List of subscribed topics. Only specific values are allowed. **Responses:** - `200`: Webhook created successfully - `400`: Invalid webhook body. - `401`: Unauthorized, invalid API key or company not found. - `500`: Internal server error --- ### GET `/webhooks/{id}` — Get webhook by ID _Operation ID: `get-webhook-by-id`_ **Path parameters:** - `id`: string (required) **Responses:** - `200`: Successfully - `401`: Unauthorized, invalid API key or company not found. - `500`: Internal server error --- ### PATCH `/webhooks/{id}` — Update webhook by ID _Operation ID: `update-webhook`_ **Path parameters:** - `id`: string (required) **Request body:** - `active`: boolean - `name`: string - `callbackUrl`: string - `topics`: enum("interactions.official_whatsapp" | "interactions.official_whatsapp_statuses")[] **Responses:** - `200`: Webhook updated successfully - `400`: Invalid webhook body. - `401`: Unauthorized, invalid API key or company not found. - `500`: Internal server error --- ### DELETE `/webhooks/{id}` — Delete webhook by ID _Operation ID: `delete-webhook-by-id`_ **Path parameters:** - `id`: string (required) **Responses:** - `200`: Successfully - `401`: Unauthorized, invalid API key or company not found. - `500`: Internal server error --- ## Campaigns ### GET `/campaigns` — List campaigns _Operation ID: `Listcampaigns`_ Returns campaigns belonging to the company associated with the API key. Heavy fields (`sequence`, `schedules`, `config`) are omitted from the list response. **Query parameters:** - `page`: integer — Page number to return (1-indexed). Defaults to `1`. - `limit`: integer — Number of campaigns to return per page. Defaults to `10`. - `search`: string — Case-insensitive substring to match against the campaign `name`. - `status`: enum("draft" | "active" | "cancel" | "finished" | "paused" | "error") — Filter campaigns by status. - `sort`: enum("+createdAt" | "-createdAt" | "+startDate" | "-startDate" | "+name" | "-name") — Sort the results by one of the allowed fields. Prefix with `+` for ascending or `-` for descending. Defaults to `-createdAt`. Allowed fields: `createdAt`, `startDate`, `name`. **Responses:** - `200`: OK - array of objects: - `_id`: string — Campaign id (Mongo ObjectId). - `company`: string — Group/company id the campaign belongs to. - `name`: string — Human-readable name of the campaign. - `status`: enum("draft" | "active" | "cancel" | "finished" | "paused" | "error") — Current campaign status. - `version`: enum("2") - `messageCount`: integer — Total number of messages this campaign has sent. - `isProcessing`: boolean — Whether the campaign is currently being processed by the worker. - `startDate`: string — Date the campaign started running. - `endCampaignDate`: string — Date the campaign ended (if finished). - `lastSentMessageDate`: string - `lastProcessingAt`: string - `createdBy`: string — Id of the user who created the campaign. - `createdAt`: string - `updatedAt`: string - `stats`: object — Aggregated metrics for the campaign. - `sentMessages`: integer - `uniqueSentMessage`: integer - `uniqueReceipts`: integer - `receipts`: integer - `deliveryRate`: number - `totalResponses`: integer - `uniqueResponses`: integer - `responseRate`: number - `messageError`: integer - `messageErrorRate`: number - `documents`: integer - `documentsError`: integer - `documentErrorRate`: number - `archivings`: integer - `uniqueArchivings`: integer - `comunicationsSteps`: integer - `effectivenessIndex`: number Example response: ```json [ { "_id": "65f1c1ff61ffd5f1e446d234", "company": "609b3cff61ffd5f1e446d234", "name": "Black Friday outreach", "status": "active", "version": "2", "messageCount": 1240, "isProcessing": false, "startDate": "2026-04-01T12:00:00.000Z", "createdBy": "6234da84259c59d9a555c498", "createdAt": "2026-03-28T10:15:00.000Z", "updatedAt": "2026-04-12T18:42:11.000Z", "stats": { "sentMessages": 1240, "uniqueSentMessage": 1180, "uniqueReceipts": 1102, "totalResponses": 410, "uniqueResponses": 388, "deliveryRate": 0.93, "responseRate": 0.33 } } ] ``` - `400`: Invalid query parameter. - `401`: Missing or invalid API key. ---