Home API and integrations | Keys, endpoints and webhooks
πŸ”—

API and integrations | Keys, endpoints and webhooks

API key, endpoints, webhooks and integrations with other systems.
Ian Kraskoff
By Matheus and 8 others
β€’ 28 articles

API: Import Contact via Hubspot Integration

Importing Contact Using Webhook Trigger in Hubspot Using our import endpoint, you can create or update your contacts in Cloud Chat through webhooks integrated with Hubspot. Example of Webhook Configuration Using Workflows in Hubspot To create a contact import webhook in a Hubspot workflow, follow the steps below. Step 1: Creating the Workflow In the main Hubspot sidebar, hover over the automation icon and then click on Workflows to go to the workflows dashboard: Once in the dashboard, click on Create workflow and select From scratch: For the workflow type configuration, select Contact-based and click Next: Step 2: Configuring the Webhook Request With the initial workflow setup completed, now you need to construct the payload to be sent in the webhook. To start configuring the webhook, click the add action button (+): On the left panel, click Data Operations and then select Send a webhook: In the method selector, choose POST: Next, fill in the webhook URL and API key information: Note: The API key must be configured in manage secrets. Finally, fill in the contact information fields to trigger the webhook: name (Name), phone_number (Phone), email, identifier (Unique contact ID), as well as any other available custom attributes: Note: At least one of phone_number, email, or identifier is required to create a contact. If the contact exists in your database, it will be updated with the provided fields. Otherwise, a new contact will be added.

Last updated on Oct 21, 2025

API: Single Contact Import

API: Contact Import To import or update a single contact via the Cloud Chat API, send a POST request to the endpoint below with your access key and the required fields. Want to import multiple contacts at once? Use the Bulk Contact Import via API endpoint. The two endpoints have different body formats β€” do not mix them. Endpoint POST https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/contacts/external_import Headers | Header | Value | | --- | --- | | content-type | application/json | | api_access_token | Your API token | Request Body The body is a simple JSON object (flat), without arrays. At least one of the fields phone_number, identifier, or email must be present. { "phone_number": "+5599123456789", "identifier": "CUSTOM_ID", "email": "[email protected]", "name": "Contact Name", "company_name": "Company X", "tags": "tag1, tag2, tag3", "CUSTOM_ATTRIBUTE": "value" } Available Fields | Field | Required | Description | | --- | --- | --- | | phone_number | At least 1 of the 3* | Phone number in international format with + (e.g., +5511999998888) | | email | At least 1 of the 3* | Contact's email | | identifier | At least 1 of the 3* | Unique external identifier | | name | No | Contact name | | company_name | No | Company name | | tags | No | Comma-separated tags | | Custom fields | No | Use the key of the custom attribute registered in Cloud Chat | *At least one among phone_number, email, or identifier must be provided. Example Request (curl) curl -X POST \ 'https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/contacts/external_import' \ --header 'content-type: application/json' \ --header 'api_access_token: YOUR_TOKEN' \ --data '{ "phone_number": "+5599123456789", "name": "Contact Name", "email": "[email protected]", "company_name": "Company X", "tags": "tag1, tag2" }' Create and Update Behavior (Upsert) This endpoint creates a new contact or updates an existing one automatically. To determine if the contact already exists, the system searches in the following priority order: 1. First by email 2. If no email provided, by identifier 3. If no identifier provided, by phone_number Important: The search uses only the first available field in the order above. It does not try subsequent fields if the first search yields no result. What this means in practice If you want to update a contact that already exists by phone number (e.g., add an email), and you send: { "phone_number": "+5511999998888", "email": "[email protected]" } The system will search by email first (since the email field is present). If [email protected] does not exist in any contact, it will not attempt to search by phone_number. The result will be an attempt to create a new contact, which may silently fail due to a phone conflict. How to do it correctly To update an existing contact by phone number, send only the phone number as the identifier in the first call, without the field you wish to add as an identifier: Step 1 β€” Locate the contact (if you need the ID): curl -X GET \ 'https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/contacts/search?q=+5511999998888' \ --header 'api_access_token: YOUR_TOKEN' Step 2 β€” Update via individual update endpoint: curl -X PUT \ 'https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}}' \ --header 'content-type: application/json' \ --header 'api_access_token: YOUR_TOKEN' \ --data '{"email": "[email protected]"}' Response | Status | Meaning | | --- | --- | | 204 No Content | Request processed (no response body) | | 422 Unprocessable Entity | Validation error | Note: The 204 status indicates that the request was received but does not return the created/updated contact. If you need to confirm the change, perform a contact query after the call. ⚠️ Phone number variant lookup is not supported on this endpoint. This endpoint performs an exact lookup by phone_number. If you need to match contacts across Brazilian phone number variants (12 vs 13 digits, with or without the leading 9), use the Bulk Contact Import via API endpoint with api_version: "v2" (or normalize_lookup: true). Difference Between This Endpoint and Bulk Import | | This endpoint (external_import) | Bulk create | | --- | --- | --- | | When to use | Import/update 1 contact per call | Import/update multiple contacts at once | | Body format | Simple JSON object (flat) | {"upsert": true, "data": [{...}, {...}]} | | Upsert | Always active (automatic) | Needs flag "upsert": true | | Response | 204 No Content (no body) | 201 Created with result | | Phone variant lookup | Exact match only | Available with api_version: "v2" or normalize_lookup: true | Do not mix formats! Sending {"upsert": true, "data": [...]} to this endpoint (external_import) will not work. That format is exclusive to the bulk create endpoint (bulk_create). Where to Find Configuration Parameters - CLOUDCHAT_DOMAIN: The domain visible in your browser URL when accessing Cloud Chat - ACCOUNT_ID: In account settings - API_TOKEN: At https://{{CLOUDCHAT_DOMAIN}}/app/accounts/{{ACCOUNT_ID}}/profile/settings

Last updated on Sep 22, 2026

Cloud Chat: Import Ticket History

Important Importing tickets via API can only be done after the migration is completed and with the inbox already created and active in Cloud Chat. Technical Requirements To perform this process, it is necessary for the client to have a developer responsible for executing the API requests and structuring the data correctly according to the documentation. The Cloud Humans team does not perform API imports for clients, only provides the technical documentation and implementation guidance. Ticket History Import via API To import tickets from another helpdesk via API in Cloud Chat, simply send a POST request to https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/inboxes/{{INBOX_ID}}/conversations/import with the access key and structured data as defined below. Request curl -X POST \ 'https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/inboxes/{{INBOX_ID}}/conversations/import' \ --header 'content-type: application/json' \ --header 'api_access_token: API_TOKEN' \ --data '{ "conversations_data": [ { "contact": { "email": "[email protected]", "name": "John Doe", "phone_number": "+1234567890", "identifier": "external_helpdesk_id" }, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-16T14:22:00Z", "messages": [ { "content": "My printer is on fire! The smoke is very colorful and I need immediate help.", "message_type": "incoming", "created_at": "2024-01-15T10:30:00Z", "private": false } ] } ] }' Request Body The request body must include: - conversations_data: (mandatory) List of objects containing ticket data, with the following attributes: - created_at and updated_at (mandatory): creation and last update dates, respectively. Must be in ISO 8601 Date Time format. - contact (mandatory): object containing contact data related to the ticket. Includes fields: - identifier (mandatory): unique identifier for the contact in the external helpdesk. - email (optional): contact's email. Must be a valid email. - name (optional): contact's name. - phone_number (optional): contact's phone number. Must be in international format with the "+" symbol and country code; example: +5599988888888 - messages (mandatory): list of objects containing sent message data in the ticket. Includes fields: - content (mandatory): message body. - message_type (mandatory): indicates message direction. Use "incoming" for inbound messages (sent by the contact) and "outgoing" for outbound messages (sent by the system or agents during handling). - created_at (mandatory): message sending date. Must be in ISO 8601 Date Time format. - private (mandatory): indicator of internal (private) message. Use "true" for private messages and "false" for public messages. Example { "conversations_data": [ { "contact": { "email": "[email protected]", "name": "John Doe", "phone_number": "+1234567890", "identifier": "user_6782902" }, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-16T14:22:00Z", "messages": [ { "content": "My printer is on fire! The smoke is very colorful and I need immediate help.", "message_type": "incoming", "created_at": "2024-01-15T10:30:00Z", "private": false }, { "content": "Thanks for contacting us. I can see this is urgent. Let me help you resolve this immediately.", "message_type": "outgoing", "created_at": "2024-01-15T10:31:00Z", "private": false }, { "content": "Internal note: Customer has premium support, prioritize this case.", "message_type": "activity", "created_at": "2024-01-15T11:16:00Z", "private": true }, { "content": "**Status Update**: Escalated to Level 2 Support", "message_type": "activity", "created_at": "2024-01-15T12:00:00Z", "private": true } ] } ] } Important Rules - Unique identifier required: The identifier contact must be unique. Note that two contacts with different data but the same identifier are considered the same contact. - Limits per request: Each request to this endpoint supports up to 10,000 tickets and 15 megabytes. If your import exceeds these limits, you will need to partition the data and send multiple requests to import all data. Parameters CLOUDCHAT_DOMAIN: You can find your domain by logging into your CloudChat account. It’s the part of the URL shown in your browser: ACCOUNT_ID: Found in your account settings section: API_TOKEN: Found in your profile settings (https://{{CLOUDCHAT_DOMAIN}}/app/accounts/{{ACCOUNT_ID}}/profile/settings) INBOX_ID: Identifier of the inbox that will receive the tickets to be imported. It can be found in the URL of the inbox configuration tab:

Last updated on Feb 11, 2026

API: Bulk Import of Contacts via API

Cloud Chat: Bulk Import of Contacts via API To import or update multiple contacts at once via API in Cloud Chat, send a POST request to the endpoint below. Want to import just one contact? Use the Individual Contact Import endpoint. The two endpoints have different body formats β€” do not mix them. Endpoint POST https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/contacts/bulk_create Headers | Header | Value | | --- | --- | | content-type | application/json | | api_access_token | Your API token | Request Body The body uses an array data containing the contacts to be imported: { "upsert": true, "data": [ { "name": "Contact 1", "email": "[email protected]", "phone_number": "+5511999998888", "identifier": "EXT-001", "additional_attributes": { "company": "Acme", "city": "SΓ£o Paulo" }, "custom_attributes": { "plan": "premium", "source": "march-campaign" } }, { "name": "Contact 2", "phone_number": "+5511888887777" } ] } Fields per contact | Field | Required | Description | | --- | --- | --- | | phone_number | At least 1 of the 3* | Phone number in international format with + | | email | At least 1 of the 3* | Contact's email | | identifier | At least 1 of the 3* | Unique external identifier | | name | No | Contact's name | | additional_attributes | No | Object with additional attributes (key-value). Fully overwritten on each update by default. | | custom_attributes | No | Object with custom attributes defined by the account (key-value). Fully overwritten on each update by default. | | tags_add | No | Array of tag names to add (requires apply_tags: true or api_version: "v2"). | | tags_remove | No | Array of tag names to remove (requires apply_tags: true or api_version: "v2"). | *Each contact must have at least one among phone_number, email, or identifier. upsert Flag | Value | Behavior | | --- | --- | | false or absent | Only creates new contacts. If any of the key fields (email, phone number, or identifier) already exists in the database, the row fails with a 422 error (it does not silently ignore). | | true | Creates new contacts and updates existing ones. | Example request (curl) curl -X POST \ 'https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/contacts/bulk_create' \ --header 'content-type: application/json' \ --header 'api_access_token: YOUR_TOKEN' \ --data '{ "upsert": true, "data": [ { "name": "Contact 1", "email": "[email protected]", "phone_number": "+5511999998888" }, { "name": "Contact 2", "phone_number": "+5511888887777" } ] }' Response Success (HTTP 201) { "success": true } Validation or conflict error (HTTP 422) { "success": false, "errors": [ { "index": 0, "attributes": { "name": "Contact 1", "email": "[email protected]" }, "errors": ["Email is invalid"] }, { "index": 1, "attributes": { "name": "Contact 2" }, "errors": "Duplicate: Contact with this phone number already exists" } ] } - index indicates the 0-based position of the row in the data array. - errors per row may be an array of validation messages OR a single string for key conflicts (duplicate, identifier Γ— email Γ— phone divergence, or AMBIGUOUS_MATCH). Empty body (HTTP 400) Returned when data is null or an empty array. Precautions with upsert Attention β€” risk of data loss with upsert: true: When updating an existing contact via bulk_create with upsert: true and the default settings, any field not sent will be overwritten with null, and JSONB attributes (additional_attributes, custom_attributes) are fully overwritten on each update. Example: if a contact has email and phone_number registered, and you send an update with only phone_number, the email field will be deleted. If you need partial updates without deleting other fields, either use the individual update endpoint: PUT /api/v1/accounts/{{ACCOUNT_ID}}/contacts/{{CONTACT_ID}} or use the advanced policy parameters described below (coalesce_nulls, merge_jsonb: "shallow", respect_sentinel). Advanced behavior (optional policy parameters) The endpoint accepts optional top-level parameters in the body to customize processing. Defaults preserve the original behavior (parity with prior versions). | Parameter | Type | Default | Effect | | --- | --- | --- | --- | | api_version | string | "v1" | "v1": parity with prior behavior. "v2": enables all new features (tags granular, sentinel __DELETE__, JSONB shallow merge, variant lookup). "v2-safe": conservative subset. | | apply_tags | boolean | false | Enables row-level processing of tags_add and tags_remove. | | respect_sentinel | boolean | false | Enables __DELETE__ semantics for scalar fields and JSONB keys. | | merge_jsonb | string | "overwrite" | "overwrite": replaces JSONB columns wholesale. "shallow": merges incoming keys with existing object. | | coalesce_nulls | boolean | false | Treats null values in the payload as "preserve existing" instead of overwriting with null. | | coerce_blank_jsonb | boolean | false | Treats empty strings inside JSONB attributes as a delete signal. | | normalize_lookup | boolean | false | Enables variant lookup when matching existing contacts (especially for Brazilian phone numbers). | | orphan_guard | boolean | false | Rejects payloads that would orphan an existing contact (i.e., remove its last strong identifier). | Quick recipe for the new features: send api_version: "v2" to enable everything at once, or combine apply_tags: true + respect_sentinel: true + merge_jsonb: "shallow" + normalize_lookup: true for the same result with explicit flags. api_version { "api_version": "v2", "upsert": true, "data": [ { "email": "[email protected]", "name": "Updated Name" } ] } apply_tags with tags_add and tags_remove { "apply_tags": true, "upsert": true, "data": [ { "email": "[email protected]", "tags_add": ["vip", "premium"], "tags_remove": ["pending"] } ] } ⚠️ Heads up: tags_add and tags_remove are silently ignored unless you send apply_tags: true (or api_version: "v2"). The default preserves prior behavior. If the same tag appears in both lists, removal wins (operations are ordered: add first, then remove). respect_sentinel with __DELETE__ { "respect_sentinel": true, "merge_jsonb": "shallow", "upsert": true, "data": [ { "email": "[email protected]", "name": "__DELETE__", "custom_attributes": { "favorite_color": "__DELETE__" } } ] } The literal value "__DELETE__" clears the field (NULL for scalars, key removal for JSONB). For JSONB, this only applies to top-level keys. If you legitimately use "__DELETE__" as a value, contact support before sending payloads. merge_jsonb { "merge_jsonb": "shallow", "upsert": true, "data": [ { "email": "[email protected]", "custom_attributes": { "plan": "premium" } } ] } With "shallow", only the keys you send are updated; other existing keys in custom_attributes and additional_attributes are preserved. With "overwrite" (default), the JSONB column is replaced entirely. ⚠️ Warning β€” merge_jsonb: "shallow" without respect_sentinel: true: in this combination there is no way to delete a key. If your client previously assumed that "empty value = delete", existing keys may keep their old values. To delete keys explicitly, also set respect_sentinel: true and send "__DELETE__" for those keys. coalesce_nulls { "coalesce_nulls": true, "upsert": true, "data": [ { "email": "[email protected]", "phone_number": null, "name": "New Name" } ] } With coalesce_nulls: true, the null for phone_number is treated as "preserve existing" β€” only name is updated. Useful when your serializer always emits all fields. coerce_blank_jsonb { "coerce_blank_jsonb": true, "merge_jsonb": "shallow", "upsert": true, "data": [ { "email": "[email protected]", "custom_attributes": { "favorite_color": "" } } ] } With coerce_blank_jsonb: true, empty strings inside JSONB are treated as a delete signal (the key is removed). ⚠️ Warning β€” coerce_blank_jsonb: true with payloads that include intentional empty strings: any empty string value in JSONB will be treated as delete. Do not enable this if any of your contacts legitimately store an empty string in a custom attribute β€” those keys will be removed instead of preserved. normalize_lookup { "normalize_lookup": true, "upsert": true, "data": [ { "phone_number": "+5511933334444", "name": "Maria" } ] } With normalize_lookup: true (or api_version: "v2"), the system matches contacts by phone number variants. If you send +5511933334444 and an existing contact is stored as +551133334444, the match still happens and the contact is updated rather than a duplicate being created. Useful to avoid duplication across formats with and without the leading 9 for Brazilian mobile numbers. orphan_guard { "orphan_guard": true, "respect_sentinel": true, "upsert": true, "data": [ { "identifier": "EXT-001", "email": "__DELETE__", "phone_number": "__DELETE__" } ] } With orphan_guard: true, payloads that would leave a contact without any strong identifier (email, phone number, identifier) are rejected. ⚠️ Warning β€” orphan_guard: true in accounts with identifier-only contacts: if your account intentionally has contacts that exist with only one identifier (for example, identifier-only contacts created by an external system), an update that removes that single identifier will be rejected. Only enable this guard if you are sure every contact has at least one strong key after the update. Difference between this endpoint and the individual import | | This endpoint (bulk_create) | Individual Import external_import | | --- | --- | --- | | When to use | Import/update multiple contacts at once | Import/update 1 contact per call | | Body format | {"upsert": true, "data": [{...}, {...}]} | Simple flat JSON object | | Upsert | Requires the flag "upsert": true | Always active (automatic) | | Null handling | Omitted fields are overwritten with null (use coalesce_nulls to opt out) | Omitted fields are preserved | | Variant phone lookup | Available with normalize_lookup: true or api_version: "v2" | Exact lookup by phone_number only | Do not mix formats! If you send a flat object (without data: [...]) to this endpoint, it will not work. For individual contact import, use the individual import endpoint. Where to find the configuration parameters - CLOUDCHAT_DOMAIN: The domain visible in the browser URL when accessing Cloud Chat - ACCOUNT_ID: In account settings - API_TOKEN: At https://{{CLOUDCHAT_DOMAIN}}/app/accounts/{{ACCOUNT_ID}}/profile/settings

Last updated on Sep 22, 2026

How to send a proactive WhatsApp message via API

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference disagree, the reference prevails. ::: When to use - You want to start a WhatsApp conversation via API from an external system - You need to trigger Meta-approved templates with dynamic variables - You need to understand the expected behavior of the ticket created by this API Prerequisites - WhatsApp already connected to Cloud Chat with a valid inbox_id β€” see Master Guide β€” How to connect your WhatsApp number to Cloud Chat - Meta-approved template registered in Cloud Chat β€” see How to create, edit, and delete WhatsApp templates in Cloud Chat - API Key at hand β€” see How to find your API Key in Cloud Chat - Recipient's phone number in E.164 format (e.g. +5511999998888) About this article This endpoint creates a proactive WhatsApp conversation using a previously configured template. The template parameters are dynamic and vary according to the template configuration. Ticket creation behavior :::info Since the system does not know which agent should receive it, the message is not assigned when created. That is why the bubble appears green (automated messages) instead of orange. ::: - Creates a new ticket β€” unless the inbox is configured with single conversation (lock to single conversation), in which case the message is added to the contact's existing conversation - The ticket is created with open status :::warning If the customer has two open tickets, new messages sent by the customer will always be routed to the most recent ticket. ::: Endpoint POST https://cloudchat.cloudhumans.com/api/v1/accounts/{account_id}/conversations/create_proactive_whatsapp_conversation Headers | Header | Value | | --- | --- | | content-type | application/json | | api_access_token | API access key | Body parameters | Parameter | Required | Description | | --- | --- | --- | | inbox_id | Yes | ID of the inbox the message will be sent through | | phone_number | Yes | Recipient's number in E.164 format | | template_name | Yes | Exact name of the approved template | | labels | No | Array of strings with tags to apply to the created conversation β€” see Applying tags (labels) below | | header_attachment | No | Attachment URL, if the template supports media in the header | | button_param_# | No | Button variables β€” replace # with the index (0 to N) | | Template variables | Yes, if the template has variables | One field for each variable, with its exact name, at the root of the JSON (see below) | About dynamic variables Each template variable becomes a field at the root of the JSON, alongside inbox_id, phone_number and template_name, with the variable's exact name: - Template with named variables, such as Hi {{customer}}, your {{amount}} invoice is due tomorrow: send the fields "customer" and "amount". - Template with numbered variables, such as Hi {{1}}, your {{2}} invoice is due tomorrow: send the fields "1" and "2". If any variable is missing, the API rejects the request with the error missing params. Fields that do not match any variable are ignored. Variable names with dots or accents (such as {{contact.name}} or {{horΓ‘rio}}) are not accepted by Meta as variables. Request example curl --location 'https://cloudchat.cloudhumans.com/api/v1/accounts/ACCOUNT_ID/conversations/create_proactive_whatsapp_conversation' \ --header 'content-type: application/json' \ --header 'api_access_token: ACCESS_TOKEN' \ --data '{ "inbox_id": "INBOX_ID", "phone_number": "+5511999998888", "template_name": "payment_reminder", "labels": ["campaign-x", "vip"], "header_attachment": "ATTACHMENT_URL", "button_param_0": "BUTTON PARAMETER", "button_param_1": "ANOTHER BUTTON PARAMETER", "customer": "John", "amount": "$120.00" }' Where to find the parameters - account_id β€” in the account's admin panel - inbox_id β€” ID of the configured inbox (https://cloudchat.cloudhumans.com/app/accounts/{account_id}/settings/inboxes/{inbox_id}) - api_access_token β€” generate it in the API settings panel - Dynamic variables β€” check the template configuration in the admin panel. These parameters go at the root of the payload. :::warning Make sure the phone number is in E.164 format, including the country code. ::: Applying tags (labels) to the created conversation The optional labels parameter takes an array of strings with the titles of the tags to apply to the conversation created by the dispatch β€” no second call to the labels API needed. "labels": ["campaign-x", "vip"] Behavior: - Titles are normalized: surrounding whitespace is trimmed, they are converted to lowercase, and duplicates are removed. - Tags are appended to the conversation (they never replace existing tags) β€” on inboxes with single conversation enabled, tags from previous dispatches and tags applied by agents are preserved. - If the tag does not exist in the account yet, it is created automatically (and starts showing up in the dashboard filters) β€” as long as the token belongs to an administrator or CX Engineer. With an agent (non-admin) token, only tags that already exist in the account are applied; new titles are silently ignored. - Omitting the parameter (or sending an empty array) keeps the previous behavior β€” no tags are applied. Rate limit This endpoint accepts at most 200 requests per minute. Above this limit, the API responds with HTTP 429 and the request is not processed (the message is not sent). The response includes the following headers: | Header | Description | | --- | --- | | Retry-After | Seconds until the window allows new requests | | X-RateLimit-Limit | Request limit for the window (200) | | X-RateLimit-Remaining | Remaining requests in the current window | Example response when the limit is exceeded: { "error": "Rate limit exceeded. Retry later.", "retry_after": 42 } :::warning If your integration sends messages in batches, handle the 429 response by resending the request after the time indicated in Retry-After. Without this handling, sends that exceed the limit will be lost. ::: Notes - To integrate this endpoint with HubSpot workflows: How to send a proactive WhatsApp message via HubSpot - To understand which APIs are available in Cloud Chat: Master Guide β€” How to access and operate Cloud Chat data via API - To avoid blocks and protect your number's reputation: How to avoid blocks and bans on WhatsApp

Last updated on Sep 23, 2026

API: Send Proactive Message via WhatsApp through Hubspot Integration

Sending Proactive Messages via webhook triggers through Hubspot Using our proactive message endpoint, it is possible to initiate WhatsApp conversations through webhooks integrated with Hubspot. These webhooks can be fed with Hubspot's database information, making the message dynamically contextual. πŸ“Œ When to use this integration? Use this flow when you want to: - Automatically send a WhatsApp message (using a Meta-approved template) via Cloud Chat triggered by an action in HubSpot - Personalize the message with contact properties from HubSpot (name, order number, status, among others) - Create automated follow-up, billing, onboarding, or status update flows βœ… Prerequisites Before configuring the endpoint, you need: - Have your WhatsApp number connected to Cloud Chat and possess the corresponding inbox_id. Refer to the FAQ: Master Guide β€” How to connect your WhatsApp number to Cloud Chat The inbox_id can be found by accessing the inbox settings in Cloud Chat. The URL will follow this pattern: https://cloudchat.cloudhumans.com/app/accounts/{{account_id}}/settings/inboxes/{{inbox_id}} - Have an approved template on Meta registered in Cloud Chat. Access the FAQ: How to create WhatsApp templates in Cloud Chat (creation, editing, and approval). - Have your Cloud Chat API Key ready. Visit the following FAQ to obtain the key and token: API: Send proactive message via WhatsApp. Step 1: Create the Workflow in HubSpot To create a proactive trigger webhook in a HubSpot workflow, follow the steps below. In the main HubSpot sidebar, hover over the automation icon and then click on Workflows to be redirected to the workflows dashboard: Once in the dashboard, click on Create workflow and then select From scratch: Choose the options that will trigger this event: Step 2: Configure Webhook Sending With the initial workflow setup complete, now we need to build the payload to be sent in the webhook. To start configuring the webhook, click the add action button (+): On the left panel, click Data Operations and then select Send a webhook: In the method selector, choose POST: Next, fill in the webhook URL and API key information: URL: https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/conversations/create_proactive_whatsapp_conversation To set up the API Key, click Add secret. A window will appear requesting the Secret Name and Secret Value. Fill in the Secret Name with api_access_token and in the Secret Value field, enter the Cloud Chat API Key previously saved. Payload Structure Finally, fill in the body (payload) of the request to perform the trigger, including: - template_name (required) β€” static value matching the exact name of the approved template in Cloud Chat. - inbox_id (required) β€” static value that identifies the Cloud Chat inbox. - phone_number (required) β€” dynamic field using HubSpot variable {{contact.phone}}. - Template variables β€” When registering the template in Cloud Chat, the configured variables must have exactly the same name as the properties sent by HubSpot in the payload. This means the variable name in the template must be identical to the field name sent in the webhook (respecting spelling, case sensitivity, and underscores), to ensure proper value substitution at the time of firing. Below is an example of a payload: Note: The variables used above, as well as the URL for the webhook and API key information, are discussed in the proactive API messaging section.

Last updated on Sep 22, 2026

How to extract data in bulk via API (Data Extract API)

:::warning Important notice: this API will no longer be evolved. The recommended way to perform bulk data extraction today is the new documentation: CloudHumans Data Export. ::: When to use it - You need to export historical ticket data for BI, auditing or an external dashboard - You want to feed custom reports with complete Cloud Chat data - You need to track delivery events from campaigns and proactive messages Prerequisites - API Key generated by an administrator or supervisor user β€” see How to find your API Key in Cloud Chat - CLOUDCHAT_DOMAIN and ACCOUNT_ID - An extraction period of at most 5 days (120 hours) per request :::warning This API is intended exclusively for bulk historical extraction. For real-time queries or actions on tickets, use the other APIs in the Master Guide. ::: About this article The Data Extract API lets you export complete data from your tickets directly from your Cloud Chat account β€” dates, statuses, owners, response times and much more. Ideal for custom reports and external integrations. Base request curl --location 'https://{CLOUDCHAT_DOMAIN}/api/v2/accounts/{ACCOUNT_ID}/data_extracts?startDate=2025-03-27T01:58:59&endDate=2025-03-28T01:59:00&type=BASE_TICKET_METRICS' \ --header 'Accept: application/json' \ --header 'api_access_token: {API_TOKEN}' Where to find the parameters - CLOUDCHAT_DOMAIN β€” part of the URL when you log in to your account - ACCOUNT_ID β€” after logging in, the ID appears in the URL as app/accounts/{id}/dashboard. E.g.: in cloudhumans.com/app/accounts/1/conversations/6341 the account_id is 1 - API_TOKEN β€” generate it from an administrator or supervisor profile (under "ConfiguraΓ§Γ΅es do perfil" (Profile settings), in your own environment β€” use your account's domain, e.g.: https://YOUR-DOMAIN.cloudhumans.com/app/accounts/{ACCOUNT_ID}/profile/settings. The domain varies by instance: cloudchat, cloudchat2, cloudchat3…) Required parameters - startDate β€” Start date and time (UTC) in the yyyy-MM-ddTHH:mm:ss format. E.g.: 2025-03-27T01:58:59 - endDate β€” End date and time (UTC). It must be later than startDate and the interval cannot exceed 5 days (120 hours). E.g.: 2025-03-28T01:59:00 - type β€” Type of data to export (see the list below) - account_id β€” Account ID, provided in the URL path Available types - BASE_TICKET_METRICS - TICKET_METRICS_WITH_AGENT_INFORMATION - TICKET_SUMMARY - CAMPAIGN_DELIVERY_EVENTS - SINGLE_CONTACT_DELIVERY_EVENTS Optional parameter: rangeFilterProperty Defines which date field is used to apply the period filters. | Value | Behavior | | --- | --- | | CREATED_AT (default) | Filters by the creation date | | UPDATED_AT | Filters by the last update date | Date range :::info To ensure stability and performance, the maximum interval allowed per request is 5 days. To export longer periods (e.g.: 30 days), split it into multiple requests β€” 6 consecutive calls with 5-day windows cover an entire month. ::: Request limit (rate limit) The Data Extract API applies a limit of 20 requests per minute per token. Different tokens from the same account have independent budgets. What happens when you exceed the limit Requests beyond the limit receive HTTP 429 Too Many Requests: { "error": "Rate limit exceeded. Retry later.", "retry_after": 42 } Recommendations :::warning - Respect the Retry-After header before trying again. Retry loops without backoff amplify the blocking - For large extractions (e.g.: 30 days), combine 5-day windows with spacing between requests β€” 20/min is generous for the typical volume - If your integration needs higher throughput on a sustained basis, contact support ::: 1. BASE_TICKET_METRICS Returns basic ticket data. Returned fields: | Field | Type | Description | Possibly Sensitive Data | | --- | --- | --- | --- | | ticketId | Integer | Internal ticket ID | No | | displayTicketId | Integer | ID shown to the user in Cloud Chat β€” visible in the URL and in the search by filters | No | | inboxId | Integer | Inbox ID | No | | accountId | Integer | Account ID | No | | accountName | Text | Account name | No | | ticketStatus | Text | Ticket status: open (Aberto), resolved (Resolvido), pending (Pendente), snoozed (Adiado) | No | | teamName | Text | Name of the responsible team | No | | ticketPriorityName | Text | Priority: low, medium, high, urgent | No | | ticketType | Text | Ticket type (first associated tag) | No | | inboxName | Text | Inbox name | No | | ticketTitle | Text | Ticket title β€” may contain the contact's name or phone number | Yes | | channel | Text | Communication channel (e.g.: Whatsapp) | No | | tags | Text | Ticket tags separated by commas | No | | createdAt | Timestamp | Ticket creation date and time | No | | firstReplyAt | Timestamp | Date and time of the first reply | No | | firstReplyTime | Decimal | Time to the first reply (in minutes) | No | | resolvedAt | Timestamp | Resolution date and time | No | | totalResolutionTimeMin | Decimal | Total resolution time (in minutes) | No | | agentId | Integer | ID of the responsible agent | No | | ticketOwner | Text | Name of the responsible agent | Yes | | ticketOwnerEmail | Text | E-mail of the responsible agent | Yes | | contactId | Integer | Contact ID | No | | contactName | Text | Contact name | Yes | | contactEmail | Text | Contact e-mail | Yes | | contactPhone | Text | Contact phone number | Yes | | campaignId | Integer | ID of the campaign that originated the ticket, if applicable | No | | proactivelyInitiated | Boolean | Indicates whether the ticket was initiated proactively | No | :::warning When you set the account's time zone (e.g.: GMT-3), the timestamp fields (createdAt, firstAgentAssignmentTime, firstReplyAt, firstAgentFirstReplyTime, resolvedAt, firstReplyTime, firstReplierAgentAssignmentTime, firstReplierAgentFirstReplyTime, repliedAt, readAt, receivedAt, sentAt) are returned in the configured time zone. Without a configured time zone, the times come in UTC. Setup: Time zone configuration. ::: Response example [ { "ticketId": 123456, "displayTicketId": 7890, "inboxId": 101, "accountId": 42, "accountName": "Minha Empresa", "ticketStatus": "resolved", "teamName": "Meu Time", "ticketPriorityName": "High", "ticketType": "suporte", "inboxName": "WhatsApp", "ticketTitle": "+5511999999999", "channel": "Whatsapp", "createdAt": "2025-03-27T09:53:14.791Z", "firstReplyAt": "2025-03-27T10:09:29.225Z", "firstReplyTime": 16.24, "resolvedAt": "2025-03-27T13:20:15.830Z", "totalResolutionTimeMin": 207.01, "tags": "suporte,prioridade_alta", "agentId": 42, "ticketOwner": "ClaudIA", "ticketOwnerEmail": "[email protected]", "contactId": 998877, "contactName": "Contact Name", "contactEmail": "[email protected]", "contactPhone": "+5511887774411", "campaignId": 123, "proactivelyInitiated": true } ] 2. TICKET_METRICS_WITH_AGENT_INFORMATION Includes details about the agent who replied and resolved. Additional fields: | Field | Type | Description | Possibly Sensitive Data | | --- | --- | --- | --- | | ticketLink | Text | Direct URL to the ticket in Cloud Chat | No | | agentOnResolutionId | Integer | ID of the human agent who resolved the ticket | No | | agentOnResolutionName | Text | Name of the human agent who resolved it | Yes | | agentOnResolutionEmail | Text | E-mail of the human agent who resolved it | Yes | | firstAgentReplyId | Integer | ID of the first human agent who replied | No | | firstAgentReplyName | Text | Name of the first human agent who replied | Yes | | firstAgentReplyEmail | Text | E-mail of the first human agent who replied | Yes | | firstAgentAssignmentTime | Timestamp | Date and time when the ticket was assigned to the first agent | No | | firstAgentFirstReplyTime | Timestamp | Date and time of the agent's first reply | No | | firstReplierAgentAssignmentTime | Timestamp | Assignment date and time of the agent who replied first | No | | firstReplierAgentFirstReplyTime | Timestamp | Timestamp of the first reply from the agent who replied first | No | | firstAgentReplyTimeMin | Decimal | Time between assignment and the agent's first reply (min) | No | | firstAgentResolutionTimeMin | Decimal | Time between assignment and ticket resolution (min) | No | | csatScore | Numeric | Satisfaction score (CSAT) given by the customer | No | | csatFeedback | Text | Text comment left by the customer in the CSAT survey | Yes | | contactCustomFields | JSON | Contact custom fields β€” may contain personal data | Yes | | conversationCustomFields | JSON | Conversation custom fields β€” may contain personal data | Yes | | conversationAdditionalFields | JSON | Additional conversation metadata β€” may contain personal data | Yes | Response example [ { "ticketId": 11111, "displayTicketId": 11111, "accountName": "account name", "inboxName": "WhatsApp", "ticketLink": "https://cloudchat.cloudhumans.com/app/accounts/99999/conversations/11111", "ticketStatus": "resolved", "createdAt": "2025-03-27T13:00:40.897954", "resolvedAt": "2025-03-27T15:38:02.743726", "agentOnResolutionId": 225, "agentOnResolutionName": "ClaudIA", "agentOnResolutionEmail": "[email protected]", "firstAgentReplyId": 111, "firstAgentReplyName": "ClaudIA", "firstAgentReplyEmail": "[email protected]", "firstAgentAssignmentTime": "2025-03-27T13:16:13.001269", "firstAgentFirstReplyTime": "2025-03-27T13:17:01.344971", "firstAgentReplyTimeMin": 0.81, "firstAgentResolutionTimeMin": 141.83, "csatScore": null, "csatFeedback": "", "contactCustomFields": "{}", "conversationCustomFields": "{}", "conversationAdditionalFields": "{}" } ] :::info - firstAgentReplyTimeMin β€” time between firstAgentAssignmentTime and firstAgentFirstReplyTime - firstAgentResolutionTimeMin β€” time between firstAgentAssignmentTime and resolvedAt ::: 3. TICKET_SUMMARY Returns a summary of the ticket conversation. Returned fields: | Field | Type | Description | Possibly Sensitive Data | | --- | --- | --- | --- | | ticketId | Integer | Internal ticket ID | No | | displayTicketId | Integer | ID shown to the user in Cloud Chat β€” visible in the URL and in the search by filters | No | | ticketLink | Text | Direct URL to the ticket in Cloud Chat | No | | summary | Text | Summary of the conversation between customer and agent β€” it may come truncated in long conversations | Yes | [ { "ticketId": 1111, "displayTicketId": 1111, "ticketLink": "https://cloudchat.cloudhumans.com/app/accounts/99999/conversations/1111", "summary": "CONTATO: Oi\nUSUÁRIO: OlΓ‘!" } ] :::warning The summary field does not guarantee the full transcript of the conversation: it consolidates excerpts and, in long conversations, the content may come cut off. If you need the complete history, use the transcript delivery by e-mail from the conversation itself, instead of the API. ::: 4. CAMPAIGN_DELIVERY_EVENTS Returns WhatsApp campaign delivery events, tracking message status by contact and campaign. Returned fields: | Field | Type | Description | Possibly Sensitive Data | | --- | --- | --- | --- | | id | Integer | Unique ID of the delivery event | No | | campaignId | Integer | Campaign ID | No | | campaignTitle | Text | Campaign title | No | | audience | Text | Audience/list used in the campaign | No | | contactId | Integer | ID of the recipient contact | No | | contactName | Text | Name of the recipient contact | Yes | | contactEmail | Text | E-mail of the recipient contact | Yes | | contactPhoneNumber | Text | Phone number of the recipient contact | Yes | | ticketId | Integer | ID of the ticket generated by the send, if any | No | | displayTicketId | Text | ID shown to the user in Cloud Chat β€” visible in the URL and in the search by filters | No | | messageSent | Boolean | Flag indicating whether the message was sent to the WhatsApp (Meta) API | No | | sentAt | Timestamp | Send date and time | No | | messageReceived | Boolean | Flag indicating whether the message was delivered to the contact's device | No | | receivedAt | Timestamp | Delivery date and time | No | | messageRead | Boolean | Flag indicating whether the message was read (depends on the contact's privacy settings) | No | | readAt | Timestamp | Read date and time | No | | messageReplied | Boolean | Flag indicating whether the message was replied to | No | | repliedAt | Timestamp | Date and time of the first reply | No | | error | Text | Delivery error: invalid number, no WhatsApp, block, etc. | No | | createdAt | Timestamp | Record creation date and time | No | | updatedAt | Timestamp | Date and time of the last update | No | Response example [ { "id": 103, "campaignId": 5502, "campaignTitle": "Natal 2025 - PromoΓ§Γ£o Especial", "audience": "lista_fidelidade_natal", "contactId": 9003, "contactName": "Carla Souza", "contactEmail": "[email protected]", "contactPhoneNumber": "+55 31 99999-99999", "ticketId": 78414, "displayTicketId": "2027", "messageSent": false, "sentAt": null, "messageReceived": false, "receivedAt": null, "messageRead": false, "readAt": null, "messageReplied": false, "repliedAt": null, "error": "NΓΊmero de telefone invΓ‘lido ou nΓ£o registrado no WhatsApp", "createdAt": "2025-12-10T09:00:00.000Z", "updatedAt": "2025-12-10T09:00:00.000Z" } ] 5. SINGLE_CONTACT_DELIVERY_EVENTS Returns delivery events of proactive single-send messages (not campaigns). Returned fields: | Field | Type | Description | Possibly Sensitive Data | | --- | --- | --- | --- | | id | Integer | Unique ID of the delivery event | No | | contactId | Integer | ID of the recipient contact | No | | contactName | Text | Name of the recipient contact | Yes | | contactEmail | Text | E-mail of the recipient contact | Yes | | contactPhoneNumber | Text | Phone number of the recipient contact | Yes | | ticketId | Integer | ID of the ticket generated by the send, if any | No | | displayTicketId | Text | ID shown to the user in Cloud Chat β€” visible in the URL and in the search by filters | No | | messageSent | Boolean | Flag indicating whether the message was sent to the WhatsApp (Meta) API | No | | sentAt | Timestamp | Send date and time | No | | messageReceived | Boolean | Flag indicating whether the message was delivered to the contact's device | No | | receivedAt | Timestamp | Delivery date and time | No | | messageRead | Boolean | Flag indicating whether the message was read (depends on the contact's privacy settings) | No | | readAt | Timestamp | Read date and time | No | | messageReplied | Boolean | Flag indicating whether the message was replied to | No | | repliedAt | Timestamp | Date and time of the first reply | No | | error | Text | Delivery error: invalid number, no WhatsApp, block, etc. | No | | createdAt | Timestamp | Record creation date and time | No | | updatedAt | Timestamp | Date and time of the last update | No | Response example [ { "id": 321, "contactId": 555777, "contactName": "Maria Silva", "contactEmail": "[email protected]", "contactPhoneNumber": "+55 11 98888-7777", "ticketId": 78414, "displayTicketId": "2027", "messageSent": true, "sentAt": "2025-08-01T12:00:05.000Z", "messageReceived": true, "receivedAt": "2025-08-01T12:00:08.000Z", "messageRead": true, "readAt": "2025-08-01T12:01:30.000Z", "messageReplied": false, "repliedAt": null, "error": null, "createdAt": "2025-08-01T11:59:59.000Z", "updatedAt": "2025-08-01T12:01:30.000Z" } ] Practical step by step 1. Generate your API Key in an administrator or supervisor profile ("ConfiguraΓ§Γ΅es do perfil" (Profile settings) β†’ see "How to find your API Key"). 2. Choose where to run it: it is an HTTP GET call β€” use an API client (Postman, Insomnia) or the terminal with curl. No programming required. 3. Build the URL replacing the fields between {}: https://{YOUR_DOMAIN}/api/v2/accounts/{ACCOUNT_ID}/data_extracts?startDate=2025-03-27T00:00:00&endDate=2025-03-27T23:59:59&type=TICKET_METRICS_WITH_AGENT_INFORMATION 4. Add the authentication header (required β€” without it, it returns 401): api_access_token: {YOUR_API_KEY} 5. Send the request (Send button in Postman, or run the curl). 6. Read the result: you get a JSON with the list of tickets; each field is described in the type tables of this article. Notes - For real-time queries (not historical): How to query contacts, tickets and messages in real time via API - To change ticket data via API: How to update and act on tickets via API - Overview of all available APIs: Master Guide β€” How to access and operate Cloud Chat data via API

Last updated on Sep 22, 2026

How to Create Tickets via API in Cloud Chat

πŸ“Œ What does this feature allow? This API allows you to create a ticket in Cloud Chat from any external system, such as: - A telephony system (e.g., when a call arrives) - A form filled out on your website - An integration with CRM, ERP, or any custom tool By using this route, you can: - Create a new ticket with status open, pending, or closed - Associate the ticket with a contact via email, phone, or identifier - Include an initial message (inbound or outbound) - Set custom conversation attributes at the time of creation 🧭 When to use this API? Use when you need to start a conversation in Cloud Chat without the customer sending a message through an active channel. Examples: - Received a call outside of Cloud Chat? β†’ Generate a ticket with the call summary. - Someone filled out a form? β†’ Automatically create the ticket and start correspondence via email. - Want to centralize communications from other sources? β†’ Use this API as an entry point. πŸ”— Endpoint POST https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/conversations πŸ” Required Headers { "content-type": "application/json", "api_access_token": "YOUR_API_TOKEN" } 🧾 Request Body { "inbox_id": "1", "contact_identifier": "id_123", "contact_email": "[email protected]", "contact_phone_number": "+12345", "message": { "content": "Hello, I just filled out the form on the website and need assistance.", "message_type": "incoming" }, "status": "open", // Optional "private": false, // Optional "custom_attributes": { // Optional "example1": "valueXPTO" }, "additional_attributes": { // optional "mail_subject": "Support Protocol ABCD" }, "assignee_id": "1" // Optional } 🧠 Explanation of Main Fields inbox_id: Identifier of the inbox, obtainable from the browser bar (URI/route) when accessing the inbox settings. assignee_id (optional): Identifier of the agent to be assigned at creation. To reference the contact, send one of the following three fields: - contact_identifier: Unique contact ID - contact_email: Contact's email - contact_phone_number: Contact's phone number message: The message object with the following fields: - content: the message content - message_type: - "incoming": message from the customer - "outgoing": sent by the agent - "activity": internal note - private: whether the message is visible to the customer (false) or internal (true) additional_attributes β†’ mail_subject (optional) If the ticket is handled via email channel, you can use this field to customize the email subject sent to the contact when the conversation starts. custom_attributes (optional but powerful) You can add any custom conversation field already existing in your configuration directly here. To learn how to create custom fields, see this FAQ. 🎯 Does the ticket start as "open"? Yes. The ticket will be created with status "open" by default, unless the status field is provided in the request, which makes it visible and ready for immediate support in the specified inbox. πŸ§ͺ How to test? 1. Access your api_access_token in the configuration panel. 2. Copy ACCOUNT_ID, INBOX_ID, and CLOUDCHAT_DOMAIN as described in this import FAQ. 3. Send the request via Postman or script. 4. Check in Cloud Chat if the ticket appeared in the correct inbox with complete information. ⚠️ Common Errors Incorrect use of unique identifiers The fields identifier, phone_number, and email are unique contact attributes. They should not be fixed in ticket creation requests. Because the request uses upsert, if these are fixed, the result will always be a single contact being updated on each call, with all conversations linked to it. Creating a Ticket does not create a contact Manual ticket creation via API does not generate new contacts. The system only uses existing contacts. Therefore, if the contact does not exist, you must create it beforehand before starting a conversation. Create it following this FAQ!

Last updated on Sep 22, 2026

Updating Custom Attributes in Conversations via API

To update custom attributes in conversations via API in Cloud Chat, simply send a PUT request to: https://cloudchat.cloudhumans.com/api/v1/accounts/ACCOUNT_ID/conversations/CONVERSATION_ID/custom_attributes Make sure to include the access key (API_TOKEN) in the headers and follow the requested fields as described below. - API_TOKEN: Access token obtained from your profile settings. - (https://cloudchat.cloudhumans.com/app/accounts/ACCOUNT_ID/profile/settings) Example request with fields: curl --request PUT \ --url https://cloudchat.cloudhumans.com/api/v1/accounts/ACCOUNT_ID/conversations/CONVERSATION_ID/custom_attributes \ --header 'api_access_token: API_TOKEN' \ --header 'content-type: application/json' \ --data '{ "custom_attributes": { "to_be_updated": "new_value", "to_be_removed": null } }' Request Body The request must contain a single field, custom_attributes, which should be an object with the attributes to be updated. Note: The conversation_id of the conversation to be updated must not be included in the request body, as it is passed as a URL parameter. Example Request: PUT /conversations/123/custom_attributes { "custom_attributes": { "to_be_updated": "new_value", "to_be_removed": null } } Attribute Types Custom conversation attributes have a predefined value type, set in their configuration, which must be respected when using the endpoint to update values: - Text: Must accept String values. - Number: Must contain only digits. Alphabetic or special characters are not allowed. - Link: Must be a valid URL (http or https). The link must end with a valid domain (e.g., .com, .net, .org). - Date: Must be in ISO8601 format (YYYY-MM-DDTHH:MM:SS.sssZ). Valid example: "2025-01-01T12:00:00.000Z". - List: Must be a String value, and this value must be among the options defined in the attribute configuration. - Checkbox: Must be either "true" / "false" (string), or true / false (Boolean). Note: To remove a value assigned to a custom attribute, simply send null or an empty string (""). The system will process the request and remove the attribute from the custom_attributes object, ensuring it is no longer present in the conversation. Error Handling If any value sent in the custom_attributes field does not comply with the rules, the request will not be processed and a specific error will be returned: - If the conversation is not found, the system returns an error "Conversation not found" with status code 404. - If the request body is incorrect, an error "Invalid attributes" with status code 422 will be returned. - If an attribute does not exist in the configuration, an error indicating that the attribute was not found will be returned. - If a value does not match the expected type, a message will be returned indicating the issue, such as: "number_attr must contain only numeric digits" or "date_attr must be in ISO8601 format (YYYY-MM-DDTHH:MM:SS.sssZ)".

Last updated on Oct 21, 2025

How to bulk remove tags from contacts via API

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference differ, the reference prevails. ::: When to use - You need to remove tags from multiple contacts at once without opening each contact manually - You are running a tag cleanup or correction routine on your contact base - You want to keep your base organized after a campaign or migration Prerequisites - API Key (API_TOKEN) at hand β€” see How to find your API Key in Cloud Chat - The account's ACCOUNT_ID - Each contact must have at least one identifier among identifier, email or phone_number Endpoint DELETE https://cloudchat.cloudhumans.com/api/v1/accounts/{ACCOUNT_ID}/contacts/delete_tags Headers | Header | Value | | --- | --- | | content-type | application/json | | api_access_token | Your API token | Request body The body must contain a single field, contacts, which is an array of objects. Each object represents a contact and must contain: | Field | Required | Description | | --- | --- | --- | | identifier | At least 1 of the 3* | Unique identifier of the contact | | email | At least 1 of the 3* | Contact's email | | phone_number | At least 1 of the 3* | Contact's phone number | | tags | Yes | Array with the tags to remove (by name) | *At least one identifier must be provided to locate the contact. Request example curl --request DELETE \ --url 'https://cloudchat.cloudhumans.com/api/v1/accounts/ACCOUNT_ID/contacts/delete_tags' \ --header 'api_access_token: API_TOKEN' \ --header 'content-type: application/json' \ --data '{ "contacts": [ { "identifier": 123, "tags": ["tag-de-massa-1","tag-de-massa-2"] }, { "email": "[email protected]", "tags": ["tag-de-massa-2","tag-de-massa-3"] }, { "phone_number": 5551000000000, "tags": ["tag-de-massa-1","tag-de-massa-3"] } ] }' How the contact is located The system looks up the contact in this order: 1. identifier (first) 2. email (second) 3. phone_number (third) :::info Unlike the contact import endpoint (which prioritizes email), here identifier takes priority. ::: About phone_number :::info If sent without the + prefix, the system adds it automatically (e.g.: 5511999998888 β†’ +5511999998888). ::: Notes - To delete the contact (not just remove tags): How to create, update and delete contacts via API - To create or update contacts (including managing tags with granular tags_add and tags_remove): How to bulk import contacts via API - To update custom attributes (not tags) on conversations: How to update custom attributes on conversations via API - Overview of all available APIs: Master Guide β€” How to access and operate Cloud Chat data via API

Last updated on Oct 02, 2026

API - Send Proactive Message via WhatsApp

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference disagree, the reference prevails. ::: This article is the quick reference for the WhatsApp endpoint. The full guide, including Web Widget and tags, is at Trigger a proactive message via API (WhatsApp and Web Widget). Description This endpoint allows creating a proactive conversation through WhatsApp using a pre-configured template. The template parameters are dynamic and may vary depending on the template configuration used. Endpoint URL: POST https://cloudchat.cloudhumans.com/api/v1/accounts/{account_id}/conversations/create_proactive_whatsapp_conversation Headers: - content-type: application/json - api_access_token: Your API access key. Parameters Path Parameter account_id - Type: String - Required: Yes - Description: Account ID in the system. Body Parameters 1. inbox_id - Type: String - Required: Yes - Description: ID of the inbox where the message will be sent. 2. phone_number - Type: String - Required: Yes - Description: Recipient's phone number, including country code. 3. template_name - Type: String - Required: Yes - Description: Name of the template configured in the system. 4. Dynamic Template Parameters - Type: Various - Required: Yes, if the template has variables (all of them are required) - Description: One field for each template variable, with its exact name (see below). 5. labels - Type: Array of strings - Required: No - Description: Titles of the tags to apply to the created conversation. Details in the full guide. About Dynamic Parameters Each template variable becomes a field at the root of the JSON, alongside inbox_id, phone_number and template_name, with the variable's exact name: - Template with named variables, such as Hi {{customer}}, your {{amount}} invoice is due tomorrow: send the fields "customer" and "amount". - Template with numbered variables, such as Hi {{1}}, your {{2}} invoice is due tomorrow: send the fields "1" and "2". If any variable is missing, the API rejects the request with the error missing params. Fields that do not match any variable are ignored. Variable names with dots or accents (such as {{contact.name}} or {{horΓ‘rio}}) are not accepted by Meta as variables. Request Example curl --location 'https://cloudchat.cloudhumans.com/api/v1/accounts/ACCOUNT_ID/conversations/create_proactive_whatsapp_conversation' \ --header 'content-type: application/json' \ --header 'api_access_token: ACCESS_TOKEN' \ --data '{ "inbox_id": "INBOX_ID", "phone_number": "+15551234567", "template_name": "payment_reminder", "customer": "John", "amount": "$120.00" }' Notes 1. account_id: The account_id can be found in the account's admin panel. 2. inbox_id: The inbox_id corresponds to the ID of the configured inbox for receiving messages. 3. api_access_token: Generate the token in the API configuration panel. 4. Dynamic Template Parameters: Check your template configuration in the admin panel to identify available and mandatory variables. These parameters should be sent directly at the root of the payload. Important: Ensure that the phone number is in international format (E.164), including the country code. Rate limit This endpoint accepts up to 200 requests per minute per API key. Above that, the response is 429 with the Retry-After header (seconds until you can try again). Wait that long before resending and, for large batches, spread the sends across minutes. A request that received 429 was not processed, so resending it does not duplicate the message. The response body and the other headers are in the rate limit section of How to send a proactive WhatsApp message via API. Campaigns via API To send to a list of contacts, use campaign creation on the public API (api.cloudhumans.com), also available through the Cloud Humans MCP: - The audience is defined by tag: the campaign goes to the contacts that have the tag. - Before creating, the API asks you to confirm how many contacts will receive it. - Sending goes through the campaign scheduler, within a few minutes or at the scheduled time. - Authentication is by user login (Bearer token), not by this endpoint's api_access_token. Reference: Create a campaign. The endpoint on this page remains the way to send one by one; to send in volume through it, respect the limit of 200 requests per minute.

Last updated on Sep 23, 2026

Master Guide β€” How to Access and Operate CloudChat Data via API

This guide exists to answer a single question: πŸ‘‰ β€œWhich CloudChat API should I use for what I want to do?” Before copying any endpoint or writing code, read this page. It prevents confusion, incorrect API usage, and unintended impacts in production. 🧠 Overview: there are 3 types of APIs in CloudChat CloudChat APIs are not all the same. They are divided into three categories, each with a clear purpose. πŸ“¦ Data Extraction APIs Used for historical analysis and reports. - Batch export (batch) - Typical use: BI, auditing, dashboards - Do not modify data - Ideal for scheduled jobs πŸ” Real-Time Query APIs Used to read current data from the system. - Search contacts - List tickets - Read messages - Do not modify data - Used in real-time integrations and automations ✏️ Update and Action APIs ⚠️ These APIs modify real data in production. - Resolve tickets - Change status, priority, or team - Create messages in tickets - Can impact operations, SLA, and metrics - Some routes are experimental or require an active flag πŸ“¦ When to use Data Extraction APIs Use extraction APIs when you want to: - Create reports - Feed BI tools - Conduct audits - Analyze large periods of time - Export many tickets at once These APIs: - Work in batches - Have interval limits per request - Should not be used for real-time application logic πŸ‘‰ Specific documentation: πŸ“¦ Data Extraction API (Data Extract API) πŸ” When to use Real-Time Query APIs Use query APIs when you need to answer questions now, such as: - β€œDoes this contact already exist?” - β€œWhat tickets does this customer have?” - β€œWhat is the current status of this ticket?” - β€œWhat messages have been exchanged in this conversation?” These APIs: - Are read-only (GET) - Operate directly on the production database - Do not replace the extraction API πŸ‘‰ Specific documentation: πŸ” Real-Time Query APIs (Contacts, Tickets, and Messages) ✏️ When to use Update and Action APIs ⚠️ Attention: these APIs modify real data in CloudChat. Use action APIs when you want to: - Resolve a ticket via integration - Update priority or responsible team - Automatically create messages - Synchronize actions from another system with CloudChat These APIs: - Execute actions in production - Can affect operation and metrics - Should be used carefully and validated πŸ‘‰ Specific documentation: ✏️ Update and Action APIs in Tickets 🧩 Practical rule for choosing the right API Always ask: - Do I want to analyze historical data? β†’ Use Data Extraction API - Do I just want to read current data? β†’ Use Real-Time Query APIs - Do I want to change something in the system? β†’ Use Update and Action APIs If still unsure, do not proceed. Using the wrong API can cause unexpected side effects. 🚦 Levels of caution (important) - Data extraction β†’ low risk - Real-time query β†’ medium risk - Update / action β†’ high risk The closer you get to write actions, the more attention and testing are necessary. ❌ Common mistakes this guide helps to avoid - Using extraction API for something that requires real-time - Using write API thinking it is just a query - Mixing application logic with data export - Changing tickets without understanding operational impact πŸ“Œ Next steps Now choose the right documentation for your case: - πŸ“¦ Data Extraction API (Data Extract API) - πŸ” Real-Time Query APIs (Contacts, Tickets, and Messages) - ✏️ Update and Action APIs in Tickets This guide should always be read before the above technical FAQs.

Last updated on Sep 22, 2026

How to query contacts, tickets, and messages in real time via API

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference differ, the reference prevails. ::: When to use - You want to read current data from Cloud Chat without changing anything (look up a contact, view a customer's tickets, read the messages of a conversation) - You are integrating Cloud Chat with another system (CRM, internal portal) that needs to display live data - You want to avoid duplicate contacts before creating a ticket Prerequisites - Administrator API Key β€” see How to find your API Key in Cloud Chat - CLOUDCHAT_DOMAIN and ACCOUNT_ID :::info If you are not sure yet which type of API to use, start with the Master Guide β€” How to access and operate Cloud Chat data via API. This page covers real-time reading only. ::: About this article The Real-Time Query APIs let you read current data from Cloud Chat, straight from the production database, without changing anything. They are ideal for integrations, automations, and internal screens that need to answer questions like: - "Does this contact already exist?" - "Which tickets does this customer have?" - "What is the current status of this ticket?" - "Which messages were exchanged in this conversation?" About the /api/client/ namespace :::info The endpoints on this page use /api/client/accounts/... instead of the /api/v1/accounts/... used by other APIs. Both use the same api_access_token for authentication. The /api/client/ namespace offers simplified read endpoints β€” they are more direct for one-off queries. For write operations (create, update, delete), use the /api/v1/ namespace. ::: What these APIs are for Use them when you need to: - Read data right now - Integrate Cloud Chat data with another system - Display information in an application - Make decisions based on the current state of the service What they are not for :::warning Do not use these APIs to: - Generate reports β†’ use the Data Extract API - Export large volumes of data β†’ use the Data Extract API - Analyze long time periods β†’ use the Data Extract API - Create or update tickets β†’ use the Ticket Update and Action APIs - Insert messages β†’ use the Ticket Update and Action APIs ::: Authentication All endpoints require: - {CLOUDCHAT_DOMAIN} β€” your account's domain (e.g. cloudchat.cloudhumans.com) - {ACCOUNT_ID} β€” account ID - api_access_token β€” for the /api/client/ endpoints (sections 1, 2, and 3), the token must belong to an administrator β€” supervisor or agent tokens receive 403 Forbidden. The free-text search (section 1b, /api/v1/ namespace) accepts a token from any agent profile 1. Find a contact by email or phone When to use - Before creating a ticket (to find out whether the contact already exists) - To associate external data with a contact - To avoid duplication Endpoint GET https://{CLOUDCHAT_DOMAIN}/api/client/accounts/{ACCOUNT_ID}/contacts?email=EMAIL&phone_number=PHONE Rules - At least one of the parameters (email or phone_number) is required - If both are sent, the API attempts the most precise match possible What it returns - Contact ID, name, email, phone - Custom fields - Creation and last activity dates 1b. Search contacts by free text (Search) When to use To find a contact by any text field (name, email, phone, identifier, company) without knowing exactly which one holds the information. Unlike the previous endpoint, this one performs an ILIKE search (case-insensitive, partial) across multiple fields simultaneously. Endpoint GET /api/v1/accounts/{account_id}/contacts/search?q={termo} Parameters | Parameter | Type | Required | Description | | --- | --- | --- | --- | | q | string | Yes | Search term. Minimum of 2 characters when it contains only letters (searches name only); minimum of 3 characters when it contains any digit (searches all fields). Below these limits, it returns HTTP 422 | | page | integer | No | Results page (default: 1, 15 results per page) | Searched fields - name β€” contact name (always searched) - email β€” email (from 3 characters with a digit) - identifier β€” external identifier (from 3 characters with a digit) - phone_number β€” phone, with and without the + prefix (from 3 characters with a digit) - company_name β€” company name (from 3 characters with a digit) Response - payload[] β€” array of matching contacts - meta β€” contains only the current page :::info meta.count and meta.total_pages were removed to reduce database cost on repeated queries. To get the absolute total, use the dedicated endpoint GET /api/v1/accounts/{account_id}/contacts/search/count?q={termo} (cached for 30s). ::: Example GET /api/v1/accounts/1/contacts/search?q=maria&page=1 Returns every contact whose name, email, phone, identifier, or company contains maria. Usage limit (rate limit) :::warning 40 requests per minute per access token. If you exceed the limit, the API responds with HTTP 429 (Too Many Requests). The same limit applies to /contacts/search/count. ::: Difference between the two search endpoints | | Search by email/phone | Free-text search | | --- | --- | --- | | Namespace | /api/client/ | /api/v1/ | | Fields | Email or phone only | name, email, identifier, phone, company | | Match type | Exact | Partial (ILIKE) | | Pagination | No | Yes (15 per page) | | Result total | β€” | Separate endpoint (/search/count) | 2. List a contact's tickets When to use You already have the CONTACT_ID and want to list that customer's tickets: - Show the service history - View open or resolved tickets - Integrate with a CRM or internal portal Endpoint GET https://{CLOUDCHAT_DOMAIN}/api/client/accounts/{ACCOUNT_ID}/contacts/{CONTACT_ID}/conversations?page=1&limit=10 Parameters - page β€” required - limit β€” optional (default: 10) What it returns - Ticket IDs - Status (open, resolved, etc.) - Priority - Inbox - Creation dates - Whether it was started by a campaign 3. List a ticket's messages When to use To retrieve the message history of a ticket: - Real-time auditing - Display the conversation in another interface - Debug integrations Endpoint GET https://{CLOUDCHAT_DOMAIN}/api/client/accounts/{ACCOUNT_ID}/conversations/{CONVERSATION_ID}/messages?page=1&limit=10 What it returns - Message content - Type (incoming / outgoing) - Public or private - Creation date - Message status - Attachment links (if any) How these APIs connect (typical flow) 1. Find the contact by email or phone 2. Get the CONTACT_ID 3. List that contact's tickets 4. Pick a ticket 5. List the ticket's messages :::success All of this without changing any data. ::: Risk level Medium risk β€” they do not change data, but they query the production database in real time. :::info Best practices: - Avoid aggressive loops - Use caching whenever possible - Do not use for bulk exports ::: Common mistakes :::warning - Using these APIs for historical reports - Forgetting the page parameter - Mixing up CONTACT_ID and CONVERSATION_ID - Trying to create or update data with GET ::: Conversation tags (labels) and how to find the contact_id Tags applied to a conversation have their own endpoint (in Chatwoot, the base of Cloud Chat, they are called labels): GET https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/conversations/{CONVERSATION_ID}/labels To find the contact_id from the CONVERSATION_ID you don't need a separate endpoint β€” the conversation details already return it: GET https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/conversations/{CONVERSATION_ID} In the response, meta.sender.id is the contact_id of the contact who owns the conversation. The same meta.sender object includes the name, email, phone, and other identifiers. Both endpoints require an api_access_token from a user with the appropriate permission. Notes - To change status, priority, or team: How to update and act on tickets via API - For reports and BI (historical extraction): How to extract data in bulk via API - Overview of the available APIs: Master Guide β€” How to access and operate Cloud Chat data via API

Last updated on Oct 02, 2026

How to update and act on tickets via API

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference differ, the reference prevails. ::: When to use - You want to change a ticket's status (resolve, reopen), priority, or team through an integration - You need to send messages automatically in an existing ticket - You need to manage labels on tickets Prerequisites - An administrator or supervisor API Key β€” see How to find your API Key in Cloud Chat - CLOUDCHAT_DOMAIN, ACCOUNT_ID, CONVERSATION_ID (internal ID) and/or DISPLAY_ID (the ID visible in the UI) :::error These APIs write to production. Changes impact SLAs, metrics, and your operation. Validate the ticket's current state before making changes and test in a controlled environment before using in production. ::: About this article These APIs let you modify real ticket data β€” change status, priority, team, and send messages. To only query data (without changing anything), use How to query contacts, tickets, and messages in real time via API. Authentication All endpoints require: | Header | Value | | --- | --- | | content-type | application/json | | api_access_token | Administrator or supervisor token | 1. Change ticket status (resolve, reopen, etc.) Endpoint POST https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}/toggle_status Body { "status": "resolved" } Accepted values | Value | Description | | --- | --- | | open | Reopen ticket | | resolved | Resolve ticket | | pending | Mark as pending | Example curl -X POST \ 'https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}/toggle_status' \ --header 'content-type: application/json' \ --header 'api_access_token: SEU_TOKEN' \ --data '{"status": "resolved"}' Returns the updated conversation object with status 200 OK. :::warning The PUT /api/v1/accounts/{ACCOUNT_ID}/conversations/{CONVERSATION_ID} endpoint does not change the status β€” it only accepts the priority field. To change status, always use the toggle_status endpoint above. ::: 2. Change ticket priority Endpoint PUT https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}} Body { "priority": "high" } Accepted values | Value | Description | | --- | --- | | nil / null | No priority | | low | Low | | medium | Medium | | high | High | | urgent | Urgent | Example curl -X PUT \ 'https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}' \ --header 'content-type: application/json' \ --header 'api_access_token: SEU_TOKEN' \ --data '{"priority": "high"}' :::warning This endpoint (PUT .../conversations/{ID}) accepts only the priority field. Fields such as status, team_id, or others are silently ignored. ::: 3. Change status, priority, and team (Client API) To change status, priority, and/or team in a single call, use the Client API: Endpoint PATCH https://{{CLOUDCHAT_DOMAIN}}/api/client/accounts/{{ACCOUNT_ID}}/conversations/{{DISPLAY_ID}} :::warning This endpoint uses the display_id (the ID visible in Cloud Chat), not the internal conversation_id. ::: :::warning This Client API requires an administrator token. Supervisor or agent tokens receive 403 Forbidden. If you use a supervisor token, change status via toggle_status (section 1) and priority via the PUT (section 2). ::: Body { "status": "resolved", "priority": "high", "team_id": "1" } Accepted fields | Field | Description | | --- | --- | | status | Ticket status (open, resolved, pending) | | priority | Priority (low, medium, high, urgent) | | team_id | ID of the team for reassignment | All fields are optional β€” send only what you want to change. If the provided team_id does not exist in the account, the API returns 422 with {"error": "Team not found"}. Example curl -X PATCH \ 'https://{{CLOUDCHAT_DOMAIN}}/api/client/accounts/{{ACCOUNT_ID}}/conversations/{{DISPLAY_ID}}' \ --header 'content-type: application/json' \ --header 'api_access_token: SEU_TOKEN' \ --data '{"status": "resolved"}' 4. Create a message in a ticket Endpoint POST https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}/messages Body { "content": "OlΓ‘! Segue atualizaΓ§Γ£o sobre sua solicitaΓ§Γ£o.", "message_type": "outgoing" } Fields | Field | Required | Description | | --- | --- | --- | | content | Yes | Message content | | message_type | Yes | incoming (message from the customer) or outgoing (message from the agent/system) | | private | No | true for an internal note (not visible to the customer) | Example curl -X POST \ 'https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/conversations/{{CONVERSATION_ID}}/messages' \ --header 'content-type: application/json' \ --header 'api_access_token: SEU_TOKEN' \ --data '{ "content": "Sua solicitaΓ§Γ£o foi processada.", "message_type": "outgoing" }' 5. Manage labels on a ticket :::warning The PUT /conversations/{ID} endpoint does not accept the labels field. If you send labels in the PUT body, the API returns 200 but silently ignores the field. To manage labels, use the dedicated endpoint below. ::: Endpoint POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/labels Body { "labels": ["suporte", "prioridade-alta"], "append": true } Fields | Field | Type | Required | Description | | --- | --- | --- | --- | | labels | array of strings | Yes | List of labels to apply | | append | boolean | No | true adds to the existing labels. false or omitted replaces all of them | Example curl -X POST \ 'https://cloudchat.cloudhumans.com/api/v1/accounts/1/conversations/12345/labels' \ -H 'api_access_token: SEU_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"labels": ["suporte", "urgente"], "append": true}' Fields that cannot be changed via PUT/PATCH Some fields look editable but are silently ignored by the API (it returns 200 with no error): | Field | Situation | What to do | | --- | --- | --- | | mail_subject | Attribute inside additional_attributes. Can only be set when the ticket is created. Update attempts via PUT are ignored | There is no workaround via API. If the email subject needs to be different, create a new ticket | | labels | Ignored in the ticket PUT/PATCH | Use the dedicated endpoint POST .../conversations/{ID}/labels (section 5) | Summary: which endpoint to use for each action | Desired action | Endpoint | Method | | --- | --- | --- | | Change status (resolve, reopen) | .../conversations/{ID}/toggle_status | POST | | Change priority | .../conversations/{ID} | PUT | | Change status + priority + team | /api/client/.../conversations/{DISPLAY_ID} | PATCH | | Create a message in the ticket | .../conversations/{ID}/messages | POST | | Manage labels | .../conversations/{ID}/labels | POST | Recommended safe flow 1. Query the ticket's current state before changing it β€” see How to query contacts, tickets, and messages in real time via API 2. Validate whether the action is necessary (e.g., do not resolve a ticket that is already resolved) 3. Execute the change using the correct endpoint from the table above 4. Confirm the result by checking the API response Where to find the parameters - CLOUDCHAT_DOMAIN β€” domain visible in the browser URL - ACCOUNT_ID β€” in Account Settings - CONVERSATION_ID β€” internal conversation ID (returned by the query APIs) - DISPLAY_ID β€” ID visible in the Cloud Chat interface (used only in the Client API) - API_TOKEN β€” at https://{{CLOUDCHAT_DOMAIN}}/app/accounts/{{ACCOUNT_ID}}/profile/settings Notes - To create new tickets via API: How to create tickets via API in Cloud Chat - To update custom attributes on conversations: How to update custom attributes on conversations via API - To query without changing data: How to query contacts, tickets, and messages in real time via API - Overview of the available APIs: Master Guide β€” How to access and operate Cloud Chat data via API

Last updated on Oct 02, 2026

Create or Update an Article in the Help Center

To create a new article in the Cloud Chat Help Center, simply send a POST request to: http://{CLOUDCHAT_DOMAIN}/v1/accounts/{ACCOUNT_ID}/portals/{PORTAL_SLUG}/articles Example request with fields: curl --location 'http://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/portals/{PORTAL_SLUG}/articles' \ --header 'Content-Type: application/json' \ --header 'api_access_token: BSvG6cFEqsMxKi72F6mvcjWc' \ --data '{ "content": "Article content...", "status": 0, //Must start as draft! "title": "Article Title", "author_id": 1, "category_id": 1 }' To publish the article (set status to "published"), you need to make a second request, this time a PUT, changing the status to 1: curl --location --request PUT 'http://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/portals/{PORTAL_SLUG}/articles/{ARTICLE_ID}' \ --header 'Content-Type: application/json' \ --header 'api_access_token: BSvG6cFEqsMxKi72F6mvcjWc' \ --data '{ "status": 1, // --- Other fields are optional --- //"title": "...", //"content": "...", //"author_id": 2, //"category_id": 20, }' Necessary Parameters CLOUDCHAT_DOMAIN: You can find your domain by logging into your CloudChat account. It's the part that appears in the URL of your browser: ACCOUNT_ID: Found in your account settings section: API_TOKEN: Found in your user profile settings in Cloud Chat (https://{{CLOUDCHAT_DOMAIN}}/app/accounts/{{ACCOUNT_ID}}/profile/settings) author_id and category_id can be found by inspecting the request made in your browser during some change in the articles page:

Last updated on Dec 18, 2025

How to create articles in the Help Center via API

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference differ, the reference prevails. ::: When to use - You want to create a new article in the Cloud Chat Help Center via API - You are automating content publishing from another source - You need a quick reference for the creation endpoint Prerequisites - API Key at hand β€” see How to find your API Key in Cloud Chat - ACCOUNT_ID and PORTAL_SLUG (portal slug, e.g.: cloud-chat) - Registered author_id and category_id Endpoint POST /api/v1/accounts/{id}/portals/{slug}/articles Headers | Header | Value | | --- | --- | | content-type | application/json | | api_access_token | Your API token | Required fields | Field | Description | | --- | --- | | title | Article title | | content | Content in Markdown | | status | 0 (draft) or 1 (published) β€” we recommend creating it as 0 and publishing it later with a PUT | | author_id | Author ID | | category_id | Category ID | Example curl --location 'https://cloudchat.cloudhumans.com/api/v1/accounts/{ACCOUNT_ID}/portals/{PORTAL_SLUG}/articles' \ --header 'Content-Type: application/json' \ --header 'api_access_token: SEU_TOKEN' \ --data '{ "title": "TΓ­tulo do artigo", "content": "ConteΓΊdo em Markdown...", "status": 0, "author_id": 1, "category_id": 1 }' :::info After creating it as a draft (status=0), publish it by making a PUT with status=1 on the same article_id. See the full flow in How to create, update or delete articles in the Help Center via API. ::: Notes - For the full flow (create + publish + update + delete): How to create, update or delete articles in the Help Center via API - Overview of all available APIs: Master Guide β€” How to access and operate Cloud Chat data via API

Last updated on Oct 02, 2026

Send Proactive Message via API (WhatsApp and Web Widget)

:::info The most up-to-date API documentation for Cloud Humans can be found at docs.cloudhumans.com/api-reference.** If there is any discrepancy between this article and the reference, the reference takes precedence. ::: When to use - When an external system (your backend, CRM, marketing automation) needs to initiate a conversation with a specific contact β€” without manual intervention by an agent. - For transactional and proactive notices per contact: order confirmation, payment reminder, status update, cart abandonment. - In two channels, with the same authentication (api_access_token): - WhatsApp β€” sends an approved template message to the contact's phone. - Authenticated Web Widget β€” displays a message that appears when the contact returns authenticated in the chat on your website/app. Prerequisites - An API Access Token from Cloud Chat (available in your profile, under Profile β†’ Settings β†’ Access Token). It must be included in the header api_access_token. - The account_id of your account (shown in the Cloud Chat URL). - The address of your Cloud Chat instance, which is the domain shown in your browser when accessing the platform (e.g., cloudchat5.cloudhumans.com). Requests must be directed to this address. An address of another instance will respond with 401. - The token is valid only for the instance it was generated for. If you generate a new one, the previous one becomes invalid immediately, so update all systems using it. - For WhatsApp: a connected WhatsApp inbox + an approved template by Meta. - For Web Widget: a Web Widget inbox with HMAC authentication required (authenticated area / verified identity) + a identifiable contact. How it works Authentication Both endpoints use the same header. Never expose the token on the frontend β€” these triggers are server-to-server. api_access_token: YOUR_API_ACCESS_TOKEN Content-Type: application/json :::warning Send the token only in the api_access_token header, just the value, without quotes or the Bearer prefix. Do not add an Authorization header, as it will cause the request to be rejected with 401. ::: WhatsApp: template-based trigger Sends (push) an active message β€” arrives on the contact's WhatsApp immediately. Since it's WhatsApp, the content must be an approved template. POST https://{YOUR_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/conversations/create_proactive_whatsapp_conversation {YOUR_DOMAIN} is your instance address (e.g., cloudchat5.cloudhumans.com). { "inbox_id": 123, "phone_number": "+5511999998888", "template_name": "payment_reminder", "labels": ["campaign-x", "vip"], "client": "John", "amount": "R$ 120.00" } - inbox_id β€” the WhatsApp inbox through which the message is sent. - phone_number β€” the contact's phone number in international format E.164 (with + and country code, e.g., +5511999998888). - template_name β€” name of the approved template. - Template variables β€” each variable should be sent as a top-level field in the body (sibling to inbox_id/phone_number/template_name), with the variable name of the template. Example: a template with variables client and amount should receive the fields "client" and "amount". If the template uses numbered variables ({{1}}, {{2}}), the fields are "1" and "2". Do not place these inside a template_params object. - labels (optional) β€” array of strings with tag titles to apply to the created conversation (e.g., ["campaign-x", "vip"]). Titles are normalized to lowercase, and tags are added without removing existing tags. New tags are automatically created in the account only if the token has admin or CX Engineer permissions; with an agent token, non-existent tags are ignored. Details at How to send proactive messages via WhatsApp API. WhatsApp: request rate limit The WhatsApp endpoint accepts up to 200 requests per minute per API key. Exceeding this results in a 429 response with the Retry-After header (seconds until retry). Wait this time before resending, and distribute large batches over multiple minutes. A request that receives 429 was not processed, so resending does not duplicate the message. Response body, other headers, and how the limit is counted are explained in What are the API request limits (rate limits) of Cloud Chat routes?. Web Widget (authenticated area): contact-based trigger Displays a passively appearing message: the widget does not push β€” the message shows up the next time the contact authenticates in the chat within the logged-in area. You can trigger this even for users who haven't opened the chat yet (by identifying via identifier). POST https://{YOUR_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/conversations/create_proactive_web_widget_conversation { "inbox_id": 456, "identifier": "user-42", "content": "Hi John! I saw your plan expires tomorrow. Can I help you renew?", "idempotency_key": "renewal-user-42-2026-06-28" } - inbox_id β€” the Web Widget inbox (HMAC required). - Contact identification β€” send exactly one of these: - identifier β€” your stable user ID. Creates the contact if it doesn't exist yet. - email β€” uses an already identifiable contact with that email. - contact_id β€” the contact's ID in Cloud Chat. - content β€” free message text (no template required). - idempotency_key (optional) β€” see below. - contact_attributes (optional) β€” attributes/name to enrich the contact upon creation. :::info Delivery is passive: the message only becomes visible after the contact authenticates the session in the widget (HMAC). That's why this trigger is exclusive to logged-in areas. ::: Web Widget: identifier format The identifier must be exactly the same value your app uses to generate the HMAC in the widget SDK for that user. If they differ (e.g., you send "42", but the widget sends "user-42"), Cloud Chat will treat them as different contacts and the message will not appear for the user. - identifier β€” stable string (the same as in the HMAC). It's recommended to use the user's ID from your system. - email β€” a valid email of an already identifiable contact. Web Widget: multiple inboxes and contacts without phone - Multiple Web Widget inboxes. The identifier identifies the contact across the entire account, so the same user can be reached in different inboxes (e.g., different products or logged-in areas) using the same identifier. The trigger always occurs per inbox (inbox_id): each inbox maintains its own conversation/session with the contact. To talk to the user in two areas, send a message to each inbox_id. - When no phone number is present. Unlike WhatsApp (where number is the identity), in Web Widget the contact is identified by identifier/email and does not need a phone number. Contacts without a number are fully supported β€” the phone is irrelevant for this channel. Idempotency (Web Widget) Resends are safe if you use idempotency_key. The same key, within 24 hours, returns the same conversation, instead of creating a duplicate β€” useful for retry attempts. Reusing the same key for a different contact is rejected (idempotency_key_contact_mismatch). Main errors | Code | Meaning | | --- | --- | | inbox_id_required / inbox_not_found | Missing or not found inbox in the account. | | contact_not_identifiable | Provided email/contact_id does not match an identifiable contact. | | ambiguous_contact_match | The data matches more than one contact β€” refine identification. | | invalid_contact_attributes | contact_attributes invalid for creating the contact. | | idempotency_key_contact_mismatch | The idempotency_key has already been used for another contact. | Remarks - WhatsApp = active (push, via template); Web Widget = passive (free text, upon next authentication). Choose the channel based on the desired delivery type. - The trigger is per contact in both channels (one-to-one), not a mass campaign. - The created conversation is out of the agents' queue/SLA until the contact engages β€” it does not count as active atendimento until someone responds. - Keep the api_access_token only on the server.

Last updated on Oct 21, 2026

How to extract Quick Reply button responses from WhatsApp campaigns via API

When to use it - When you send a WhatsApp campaign with a template that has quick reply buttons (Quick Reply) and want to know, per campaign, who tapped which button and when. - To build campaign and button metrics (response rate, which option was chosen most) from your backend, without having to open conversation by conversation in the interface. - It is a server-to-server, read-only endpoint. There is no interface for this in Cloud Chat β€” the data comes out through the API. Prerequisites - An administrator or supervisor Cloud Chat API Access Token. To get yours: click your avatar (bottom-left corner) β†’ Profile Settings and scroll down to the "Access Token" section β€” the field is masked; use the buttons next to it to reveal or copy it. With an agent token the endpoint returns 401/403. Users with ClaudIA-only access do not see this section. "Access Token" section in Profile Settings - Your account's account_id β€” it is the number right after /accounts/ in the Cloud Chat URL. Example: in https://cloudchat.cloudhumans.com/app/accounts/1/dashboard, the account_id is 1. - A WhatsApp campaign already sent, whose template has Quick Reply buttons. - The campaign's display_id β€” see the section below, "How to find the campaign ID". How to find the campaign ID (display_id) The Cloud Chat interface does not display the campaign ID (it does not appear in the listing or in the URL). To find it, use the campaign listing endpoint with the same token: curl -s 'https://cloudchat.cloudhumans.com/api/v1/accounts/{ACCOUNT_ID}/campaigns?query=CAMPAIGN_TITLE&campaign_type=one_off' \ -H 'api_access_token: YOUR_API_ACCESS_TOKEN' - query searches by the campaign title (the same one shown in the listing in the interface) and campaign_type=one_off restricts to one-off campaigns β€” together they usually return the desired campaign directly. - To list all campaigns (bulk extraction), call it without query, paginating: curl -s 'https://cloudchat.cloudhumans.com/api/v1/accounts/{ACCOUNT_ID}/campaigns?page=1&per_page=100' \ -H 'api_access_token: YOUR_API_ACCESS_TOKEN' - The response comes paginated in the format { "data": [...], "meta": {...} } β€” default 20 per page, per_page maximum 100; iterate page from 1 to meta.total_pages. - The id field of each returned campaign is already the display_id you use in the responses endpoint β€” do not confuse it with any internal id. { "id": 22081, "title": "My campaign", "campaign_status": "completed", "campaign_type": "one_off" } How it works Authentication api_access_token: YOUR_API_ACCESS_TOKEN Route GET https://cloudchat.cloudhumans.com/api/v1/accounts/{ACCOUNT_ID}/campaigns/{DISPLAY_ID}/responses - {ACCOUNT_ID} β€” the account id. - {DISPLAY_ID} β€” the campaign's display_id. Query parameters (optional) - page β€” page (default 1). - per_page β€” items per page (default 100, maximum 500). Example call curl -s 'https://cloudchat.cloudhumans.com/api/v1/accounts/7/campaigns/156/responses?page=1&per_page=100' \ -H 'api_access_token: YOUR_API_ACCESS_TOKEN' Tip: this curl can be imported directly into Postman (File β†’ Import β†’ Raw text) β€” just replace the token and the ids. Response The response has three parts: responses, summary and meta. { "responses": [ { "id": 27749371, "content": "Sim, tenho interesse e desejo prosseguir", "inbox_id": 174, "conversation_id": 1777, "message_type": 0, "status": "delivered", "additional_attributes": { "campaign_id": 188, "template_button_reply": true, "template_button_payload": "Sim, tenho interesse e desejo prosseguir" }, "created_at": 1784781019, "sender": { "id": 1350835, "type": "contact", "name": "JoΓ£o da Silva", "phone_number": "+5511999998888" } } ], "summary": { "Sim, tenho interesse e desejo prosseguir": 1 }, "meta": { "current_page": 1, "total_count": 1, "total_pages": 1 } } - responses β€” each item is the contact's reply message (the button tap). Useful fields: - content β€” the text of the button that was tapped. - sender β€” the contact who replied (name + phone number). - additional_attributes.template_button_payload β€” the button's payload (it echoes the button text). - conversation_id / created_at β€” where and when the reply happened (created_at is a Unix timestamp, in seconds). - summary β€” aggregated count by button text: { "<button text>": <quantity> }. It is the shortcut for the metric "how many people chose each option". The summary always covers the whole campaign, regardless of the page. - meta β€” pagination: current_page, total_count (total responses for the campaign), total_pages. Note: total_pages depends on the per_page used. To export all responses, use per_page=500 and iterate page from 1 to total_pages. Common errors - 401 Unauthorized β€” invalid token, expired/regenerated token, or the api_access_token header was not sent. - 401/403 β€” the token belongs to an agent user (the endpoint requires an administrator or supervisor on the account). - 404 Not Found β€” campaign not found: either the number used is not the display_id (see "How to find the campaign ID"), or the campaign belongs to a different account than the {ACCOUNT_ID} in the URL. - Empty responses with the right campaign β€” the template had no Quick Reply buttons, nobody tapped a button yet, or the campaign was sent before the feature's launch (no retroactive data). Important notes - No retroactive history. Only responses recorded from the feature's launch onward appear. Old campaigns are not backfilled retroactively. - The analysis identifier is the button text. Since the templates do not define their own payload, the payload simply repeats the button text. Group/analyze by the text (that is what summary does). - Counts are per tap, not per unique contact. If the same contact taps more than one button (or the same button more than once), each tap becomes a response and enters the summary. For unique-contact metrics, deduplicate by sender.id on your side. - Only campaign Quick Reply button taps count. If the contact replies with free text (instead of tapping a button), that reply does not show up here β€” the link to the campaign only exists when it is a button tap from a campaign send.

Last updated on Aug 18, 2026

How to find your API Key in Cloud Chat

When to use this - You are setting up an integration and need the api_access_token to authenticate your requests - You want to reuse the same key in another flow (HubSpot, Postman, a script) - You need to rotate the key for security reasons Prerequisites - Be logged in to Cloud Chat with your own account β€” the key is generated per user, not per account About this article The API key used to sit at the bottom of the Profile Settings screen, next to your picture, signature and notifications. It now has a page of its own, MCP / API, in the same avatar menu. That page holds the two integration topics tied to your user: the MCP server, to connect Cloud Humans to AI assistants, and the API key, to authenticate calls to the Cloud Chat API. :::info If you open the menu and do not see MCP / API yet, but you do find Access token at the bottom of Profile Settings, your instance has not received this update yet. The key is the exact same value in both places β€” copy it from wherever it is. ::: Step by step Step 1 β€” Open the MCP / API page 1. In the bottom left corner, click your avatar to open the menu 2. Click MCP / API Step 2 β€” Copy the key 1. Go to the API key section, the second one on the page 2. The key is masked. Click the eye icon to reveal it, or just use the copy button to send the value straight to your clipboard :::success Use this value in the api_access_token header of your requests to the Cloud Chat API. ::: Step 3 β€” Generate a new key (optional) Only do this when you need to rotate the key β€” for example, if you suspect it has leaked. 1. In the API key section, click the circular arrows button, to the left of the copy button 2. Confirm in the dialog that opens :::warning The old key is invalidated immediately. Any integration still using the previous value stops working until it is updated with the new key. ::: Notes :::warning The API key is personal and per user: it grants access to your account data, with your permissions. Treat it like a password β€” do not share it publicly and do not commit it to repositories. ::: - Can't find the API key section? On accounts that only use the ClaudIA panel, this section does not appear β€” only the MCP server one does. Talk to your Cloud Humans support team. - The MCP server is a different thing. It lives on the same page, but it uses no key at all: authorization happens when you sign in with your own Cloud Humans account. The walkthrough is in the MCP connection guide. - To use the key for a bulk data extraction: How to extract data in bulk via API (Data Extract API)

Last updated on Sep 17, 2026

Jira Integration in CloudChat

What is the Jira integration? Jira integration allows agents to create, link, and unlink Jira issues directly from within a conversation in CloudChat. This eliminates the need to switch between tools and ensures traceability between support interactions and product/engineering tickets. Prerequisites - Jira Cloud account (Atlassian) - A Jira user with permission to create issues in the desired projects - A Jira API Token (generated atΒ https://id.atlassian.net/manage-profile/security/api-tokens) How to set up the integration? 1. Go to Settings > Integrations in the CloudChat sidebar menu. 2. Click on Jira and then on Connect. 3. Fill in the fields: - Jira Site URL β€” e.g.,Β https://yourcompany.atlassian.net - Email β€” the email of the Jira user that will be used for API calls - API Token β€” the token generated in the previous step 4. Click on Save. The integration will be available to all agents in the account. How to create a Jira issue from a conversation? 1. Open a conversation in CloudChat. 2. In the conversation header, click on the Jira icon. 3. Click on Create issue. 4. Fill in the required fields (marked with *): - Summary β€” issue summary - Project β€” the Jira project where the issue will be created - Issue Type β€” appears only after selecting the project (e.g., Bug, Task, Story) 5. Optionally, fill in: - Description β€” additional details - Priority β€” urgency level - Assignee β€” the person to whom the issue will be assigned 6. Click on Create. The issue will be created in Jira with a link to the conversation in the description. How to link an existing issue? 1. In the Jira panel within the conversation, click on Link existing issue. 2. Search by the issue's title or key (e.g.,Β PROJ-123). 3. Click on the desired issue to link it. An automatic comment will be added to the Jira issue indicating that it has been linked to the conversation. How to unlink an issue? 1. In the Jira panel within the conversation, locate the linked issue. 2. Click on the trash can icon next to the issue. A comment will be added in Jira indicating that the link with the conversation has been removed. Can an issue be linked to more than one conversation? Yes. The same Jira issue can be linked to multiple conversations in CloudChat. Each link generates a comment in Jira with a link to the corresponding conversation. What information appears on the issue card? The card displays: - Key of the issue (e.g., PROJ-123) - Title - Status β€” current status in Jira (e.g., To Do, In Progress, Done) The information updates automatically every time you open the panel. In which language are comments added in Jira? Comments are added in the language configured in the CloudChat account. Which Jira versions are supported? The integration works exclusively with Jira Cloud. Jira Server and Jira Data Center are not supported.

Last updated on Sep 02, 2026

Migrating ticket history to Cloud Chat

When you migrate from another helpdesk, your old conversations do not come over automatically β€” they stay in your previous tool. If you want to keep them in Cloud Chat, see below what you need to send us. What you need to send us 1. Inbox ready. Make sure the migration of your channel is complete and the inbox is created and active in Cloud Chat β€” we only import the history after that (with no inbox, there is nowhere to import to). 2. The history in JSON format. Export your old conversations in a JSON file with the conversations_data key β€” a list of tickets. Each ticket has: - Ticket dates: created_at (when it was opened) and updated_at (last update), in ISO 8601 (e.g.: 2024-01-15T10:30:00Z). - contact: identifier (required, unique and stable per customer) and, optionally, name, email, phone_number (E.164). - messages: each message with content (text), message_type (incoming = customer, outgoing = agent, activity = internal note), created_at (ISO 8601) and private (true for internal notes). - custom_attributes (recommended): the information you want to keep as a reference. Store the ID of the old ticket in external_helpdesk_id (traceability), and include the ticket tags and attributes you want to keep (e.g.: priority, source_queue, tags). These tags come in as reference information/labels on the imported conversation β€” not as the native tag that filters on the platform. Tell us which ones you want to keep. Example: { "conversations_data": [ { "contact": { "identifier": "user_6782902", "name": "John Doe", "email": "[email protected]", "phone_number": "+5511988887777" }, "custom_attributes": { "external_helpdesk_id": "ZD-78901", "priority": "high" }, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-16T14:22:00Z", "messages": [ { "content": "Meu pedido nΓ£o chegou.", "message_type": "incoming", "created_at": "2024-01-15T10:30:00Z", "private": false }, { "content": "Oi! JΓ‘ verifiquei, sai hoje.", "message_type": "outgoing", "created_at": "2024-01-15T10:31:00Z", "private": false }, { "content": "Cliente VIP, priorizar.", "message_type": "activity", "created_at": "2024-01-15T11:16:00Z", "private": true } ] } ] } 3. Agree on the scope with your contact. Align with us the time range (the whole history or a slice, e.g.: the last 12 months), which tags/attributes you want to keep, and whether you want to split it by channel (WhatsApp, Instagram, email…). 4. Send the file. Upload the .json file(s) to the Google Drive folder we share with you β€” or, if you prefer, send a link to the file (Google Drive, OneDrive, whichever). If you want to keep the channels separate, send one file per channel (e.g.: historico_whatsapp.json). 5. Start with a sample. Before the complete file, send 20–50 tickets in the format β€” we import them into a validation environment, you check them, and only then do we process everything. :::info Not imported: images and attachments. The migration covers text (messages, internal notes and metadata). If an attachment was essential, include its link in the message text. Rules: dates always in ISO 8601 (if you cannot provide them in UTC, let us know the time zone); a truly unique identifier (two customers with the same value become a single one); file in UTF-8. ::: Cloud Humans does the import for you Once the file has been sent, the Cloud Humans team runs the import β€” we import in batches, respecting the platform limits, and we confirm the result with you. You do not need to deal with any API or give us access to your old tool. Prefer to do it yourself? Here is the step by step If your team has a developer and prefers to run the import, use the API. Besides the file in the format above, you will need: an API Key (see How to get your API Key), CLOUDCHAT_DOMAIN, ACCOUNT_ID and INBOX_ID. Endpoint POST https://{{CLOUDCHAT_DOMAIN}}/api/v1/accounts/{{ACCOUNT_ID}}/inboxes/{{INBOX_ID}}/conversations/import | Header | Value | | --- | --- | | content-type | application/json | | api_access_token | Your API token | The body is the same conversations_data described above. Limits β€” each request accepts at most 10,000 tickets or 15 MB. For larger volumes, split it into multiple requests. The contact identifier is unique (dedup). For the custom_attributes to show up formatted in the panel, define them beforehand in Settings β†’ Custom Attributes (scope: Conversation). Where to find the IDs CLOUDCHAT_DOMAIN Part of the URL when you log in to your account: ACCOUNT_ID In "ConfiguraΓ§Γ΅es da conta" (Account settings): API_TOKEN At https://{{CLOUDCHAT_DOMAIN}}/app/accounts/{{ACCOUNT_ID}}/profile/settings: INBOX_ID ID of the inbox that will receive the tickets. You can get it from the URL of the inbox settings tab: Notes - To create new tickets via API (not a historical import): How to create tickets via API in Cloud Chat - To import contacts before or together with the ticket import: How to bulk import contacts via API - Overview of the available APIs: Master Guide β€” How to access and operate Cloud Chat data via API

Last updated on Sep 22, 2026

Create and Monitor Campaigns via Public API

When to Use - You want to send campaigns from your own system without opening the Cloud Chat interface. - You want to estimate how many contacts an audience reaches before sending. - You need to programmatically monitor the status of a campaign. Prerequisites :::error Creating a campaign triggers sending. There is no draft mode in the API, unlike the interface. Do not use the creation endpoint to "assemble and review later". ::: - Account API key. - Profile with permission for campaigns. The agent profile cannot send campaigns via API or interface. How It Works Check Reach Before Sending There is an endpoint that determines the audience and returns the actual number of contacts reached. Use it before creating the campaign: this prevents discovering the actual size of the send after it has been dispatched. Mandatory Recipient Confirmation During creation, you must declare how many recipients you expect to reach. The system compares this number with the actual audience size: - If they match, the campaign is created and queued for sending. - If they differ, the response is a conflict error and nothing is created. :::info This is a safeguard against unintentional sends. It exists precisely because there is no draft: if your audience has grown since the last time you checked, the request fails instead of sending to more people than expected. ::: Available Channels Creation covers the three channels also available in the interface: WhatsApp, email, and web widget. Discover Templates and Variables Since API callers do not see the interface, there are two discovery endpoints: one lists available templates in the account, and the other lists the variables you can use. Use them to compose the campaign body without relying on someone to check the panel. Check Status Later There is a read endpoint to monitor the created campaign. Notes - The full endpoint reference is in the public API documentation. The same capabilities are also available as an MCP tool. - Campaigns created via API start in the same state as those created via the interface, and the same scheduler sends them. The API is the entry point, not a different sending path. - There are recipient limits, both per total audience and per channel. If the request exceeds these limits, you receive a validation error and nothing is created.

Last updated on Sep 22, 2026

What the "Falha no envio do webhook" (Webhook delivery failed) warning on messages means

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference disagree, the reference prevails. ::: When to use - You saw the "Falha no envio do webhook" (Webhook delivery failed) warning on the messages of a ticket and want to know what it means - You want to know whether this warning affects support or message delivery What this warning is The warning appears when an automation rule in your account tries to send data to an external endpoint (webhook) and that endpoint does not confirm receipt. It is common in accounts that use "Mensagem recebida" (Message received) or "Ticket resolvido" (Ticket resolved) automations to send a copy of the data to their own system (spreadsheet, script, ERP, BI tool). :::info The warning does not affect support. Sending and receiving messages (including on WhatsApp) keeps working normally, and ClaudIA is not impacted either. The only thing that fails is the parallel integration that was supposed to receive this data. ::: How to investigate 1. Go to ConfiguraΓ§Γ΅es β†’ AutomaΓ§Γ£o (Settings β†’ Automation) and identify the rules that send data to an external endpoint. 2. Check the destination URL of each one. 3. Test that URL outside Cloud Chat: it needs to respond confirming receipt. If it redirects (302 response) or starts requiring login, the delivery is considered a failure. Common case β€” Google Apps Script: the deployment must be set to "Anyone has access", executing as the script owner. When the deployment is changed (or the old link starts requiring login), the endpoint starts redirecting and every attempt fails β€” sometimes for months, without anyone noticing. Notes - Whoever manages the endpoint (your team or whoever maintains the script/integration) is the one who needs to fix the deployment β€” the fix is not in Cloud Chat. - If the integration is no longer used, the cleanest path is to deactivate the automation rule that sends the data, and the warning stops appearing.

Last updated on Oct 02, 2026

CloudChat Webhook Payload

:::info The most up-to-date documentation for Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article differs from the reference, the reference prevails. ::: Payload sent by the CloudChat Webhook When an automation triggers a webhook, it makes an HTTP POST to the configured URL, sending a JSON with the following main information: Payload structure (JSON) FieldDescriptioneventThe type of event that triggered the webhook (e.g.: message_created, conversation_created, etc.)contentThe message contentmessage_typeMessage type (incoming, outgoing, etc.)conversationObject with conversation data, including id, status, etc.senderObject with sender (contact) data, including id, name, email, phone_number, etc.accountObject with account data, including idinboxObject with inbox/channel datacontactData of the associated contact Practical example (based on the code) As seen in the Rasa integration example: chatwoot / implementation-examples / rasa-agent-bot-demo / rasa_flask_router.py @app.route('/rasa', methods=['POST']) def rasa(): data = request.get_json() message_type = data['message_type'] message = data['content'] conversation = data['conversation']['id'] Events supported for webhooks As defined in the model: chatwoot / chatwoot / app / models / webhook.rb ALLOWED_WEBHOOK_EVENTS = %w[conversation_status_changed conversation_updated conversation_created contact_created contact_updated message_created message_updated webwidget_triggered inbox_created inbox_updated conversation_typing_on conversation_typing_off].freeze Summary of the typical JSON that arrives at your endpoint: webhook_payload_example.json { "event": "message_created", "message_type": "incoming", "content": "OlΓ‘, preciso de ajuda!", "id": 12345, "conversation": { In summary: The webhook sends a POST with JSON containing data about the event, the conversation, the contact/sender, the account and the inbox, along with the message content and the message type. This allows the external system (the one receiving the webhook) to know exactly what happened and take the appropriate action.

Last updated on Oct 02, 2026

What are the request limits (rate limits) for the Cloud Chat API routes?

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference differ, the reference prevails. ::: When to use - You integrate external systems with the Cloud Chat API and need to plan your call volume without being blocked. - You received a 429 (Too Many Requests) error and want to understand why. - You are importing contacts in bulk, sending proactive WhatsApp conversations, generating reports or data extracts via API, and need to know the safe pace of calls. About this article Some Cloud Chat API routes have a requests-per-minute limit (rate limit). This limit exists to protect the platform's stability during heavier operations, such as bulk contact imports, report generation and sending proactive messages. Most API routes have no specific limit configured β€” the limits below apply only to the routes listed in the table. If you don't have your API key at hand yet, see How to find your API Key in Cloud Chat. Limits per route The table below shows the requests-per-minute limit for each route: | Route | Limit / minute | | --- | --- | | contacts/external_import | 500 | | conversations/create_proactive_whatsapp_conversation | 200 | | contacts/bulk_create | 100 | | contacts/search and contacts/search/count | 40 | | v2/reports | 20 | | v2/data_extracts | 20 | | integrations/hooks/{id}/process_event (Copilot events) | 20 | | conversations/{id}/transcript | 10 | | messages/{id}/transcription | 10 | :::info The limit for integrations/hooks/{id}/process_event applies only to Copilot events (rephrase, fix spelling, summarize tone, expand, among others). Legacy reply suggestion, summary or label events are not subject to this limit. ::: How the limit is applied - Fixed 1-minute window. The counter resets every calendar minute β€” it is not a sliding window. - Counting key. On most routes, the limit is counted per API key (api_access_token). On routes that can also be called from the Cloud Chat dashboard (create_proactive_whatsapp_conversation, process_event, contacts/search/contacts/search/count and messages/{id}/transcription), the limit is counted both by API key and by the logged-in dashboard session β€” that is, each agent or token has its own counter. - Not per IP. The limit does not depend on the source IP address, only on the API key (or session) used in the call. What happens when you exceed the limit When you exceed a route's limit, the API responds with status 429 and the body: { "error": "Rate limit exceeded. Retry later.", "retry_after": 42 } The response also includes these headers: | Header | Description | | --- | --- | | X-RateLimit-Limit | Limit configured for this route. | | X-RateLimit-Remaining | Always 0 in a 429 response. | | X-RateLimit-Reset | Timestamp (epoch) of when the window resets. | | Retry-After | Seconds until you can try again. | :::warning Always respect Retry-After before trying again. Retrying immediately on a route that is already limited only prolongs the block and does not speed up delivery. ::: Notes - Most API routes have no specific rate limit β€” the limits above cover only the routes listed in this table. - If you need a higher limit for one of these routes for a legitimate use case (for example, a one-off migration of a large volume of contacts), talk to the Cloud Humans support team before running the operation. - For bulk contact imports, also see How to import contacts in bulk via API. - For an overview of authentication and data operations via API, see the Master Guide β€” How to access and operate Cloud Chat data via API.

Last updated on Oct 02, 2026

How to merge contacts via API

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference differ, the reference prevails. ::: When to use - You have the same customer duplicated across two contacts (e.g., they came in through different channels) and want to combine them into one - You are deduplicating your contact base through an integration - You want to consolidate the history (conversations, messages, notes) of two contacts into a single record Prerequisites - Your API Key at hand β€” see How to find your API Key in Cloud Chat - CLOUDCHAT_DOMAIN and ACCOUNT_ID - The two contact ids to be merged β€” to find them, use the search described in How to query contacts, tickets and messages in real time via API Endpoint POST https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/actions/contact_merge Headers | Header | Value | | --- | --- | | content-type | application/json | | api_access_token | Your API token | Request body { "base_contact_id": 100, "mergee_contact_id": 250 } | Field | Description | | --- | --- | | base_contact_id | Contact that remains (the winner of the merge) | | mergee_contact_id | Contact that will be absorbed and deleted | How it works When merging: - All conversations, messages, notes, inboxes (contact_inboxes), CSAT responses and campaign events of the absorbed contact are moved to the base contact. - For profile fields (name, email, phone_number, identifier, additional_attributes, custom_attributes), the base contact wins. Where the base contact is empty, the value from the absorbed contact is used. - The absorbed contact (mergee_contact_id) is deleted at the end. - Response 200 with the resulting base contact. :::error Merging is irreversible. An internal audit record is kept, but there is no "undo". Confirm which id is the base_contact_id (the one that remains) before calling β€” swapping the two deletes the wrong contact. ::: Request example curl -X POST \ 'https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/actions/contact_merge' \ --header 'content-type: application/json' \ --header 'api_access_token: SEU_TOKEN' \ --data '{ "base_contact_id": 100, "mergee_contact_id": 250 }' Common errors | Status | Meaning | | --- | --- | | 404 Not Found | One of the contacts (base_contact_id or mergee_contact_id) does not exist in the account | | 422 Unprocessable Entity | Invalid payload (missing base_contact_id or mergee_contact_id) | Notes - Create, update and delete individual contacts: How to create, update and delete contacts via API - Find contact ids: How to query contacts, tickets and messages in real time via API - Overview of all available APIs: Master Guide β€” How to access and operate Cloud Chat data via API

Last updated on Oct 02, 2026

How to connect the Cloud Humans MCP Server to Claude

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference differ, the reference prevails. ::: When to use - You want to manage your knowledge base content directly from Claude β€” list, create and edit without leaving the conversation - You want to stop maintaining the same knowledge base in several places - You use another MCP client (Claude Code, Cursor, VS Code) and want to connect it to Cloud Humans :::info The Cloud Humans MCP Server is in Beta. The content management features are already available, and new ones are being added. If something does not work as expected, contact your Cloud Humans support team. ::: Prerequisites - An active Cloud Humans account β€” the connector login uses the same email and password you already use on the platform - An MCP client that supports custom connectors (in Claude, this depends on your plan) - No token or API key needs to be generated, requested from Cloud Humans or pasted anywhere β€” authorization happens on the login screen About this article The Cloud Humans MCP Server is the address that gives your AI assistant access to the Cloud Humans tools. Once connected, you talk to Claude as usual and it can view and change your content in Cloud Humans. The server address is: https://mcp.cloudhumans.com/openapi/cloudhumans/mcp :::warning This address is not a page to open in the browser. If you paste this URL into the address bar, you will see the message {"detail":"missing_token"}. This is expected and is not an error: it does not mean you lack permission, nor that you need a token. The address only works when it is added as a connector inside your AI client, which is what the steps below explain. ::: This article covers connecting your AI assistant to Cloud Humans. If you are looking for the opposite path β€” connecting ClaudIA agents to external MCP servers β€”, see How to configure MCP servers for ClaudIA agents. Step by step Step 1 β€” Open the connector settings 1. In Claude, open Settings 2. Go to the Connectors section Step 2 β€” Add it as a custom connector 1. Click Add custom connector :::warning It must be a custom connector. Cloud Humans does not appear in the list of ready-made connectors β€” if you look for it there, you will not find it. ::: 2. In Name, type something you will recognize later (for example, Cloud Humans) 3. In URL, paste the server address: https://mcp.cloudhumans.com/openapi/cloudhumans/mcp 4. Confirm to add it Step 3 β€” Log in and authorize 1. Click Connect on the connector you just created 2. A Cloud Humans login screen will open, asking for email and password 3. Sign in with your Cloud Humans account β€” the same one you use on the platform 4. After logging in, the browser automatically returns to Claude and the connector shows as connected :::info You have about 10 minutes to complete the login after clicking Connect. If it takes longer than that, the screen expires β€” just click Connect again and start over. ::: Step 4 β€” Test it Go back to a conversation and ask for something simple, such as: List the content in my knowledge base on Cloud Humans. If Claude replies with your content, everything is working. :::info If your login has access to more than one account or project in Cloud Humans, say in the conversation which one you want to use. Otherwise, the assistant has no way to guess which one to act on and will ask you to specify. ::: Notes - The connection lasts 30 days and is renewed automatically while you use it. After that period, Claude asks you to log in again β€” just repeat Step 3. - Changing your password or losing access to your account ends the connection immediately. This is the expected behavior: whoever loses access to the platform also loses access through the connector. - Permissions are exactly those of your account. The connector neither expands nor reduces what you could already see and edit in Cloud Humans, and each person who connects uses their own account. - It works with other MCP clients. The address and the login flow are the same in any client that supports remote MCP servers with login β€” the only thing that changes is where the option to add the connector is located. - If the login screen does not open and you keep seeing {"detail":"missing_token"}, the address was almost always opened in the browser instead of being added as a custom connector. Redo Step 2.

Last updated on Oct 02, 2026

How to create, update, and delete contacts via API

:::info The most up-to-date documentation for the Cloud Humans APIs is at docs.cloudhumans.com/api-reference. If this article and the reference differ, the reference prevails. ::: When to use - You need to create, look up, update, or delete a specific contact in Cloud Chat via API - You want to change only some fields of a contact without erasing the others - You are integrating Cloud Chat with another system that manages contacts individually Prerequisites - API Key at hand β€” see How to find your API Key in Cloud Chat - CLOUDCHAT_DOMAIN and ACCOUNT_ID :::info This article covers operations on one contact at a time through the standard REST endpoint. To import or update multiple contacts at once, use How to bulk import contacts via API. To only read data, see How to query contacts, tickets, and messages in real time via API. ::: Permissions by operation | Operation | Minimum permission | | --- | --- | | Create, look up, update | Any agent profile | | Delete contact | Administrator | | Look up by email (/contacts/email) | Administrator | :::warning If you can create and update but get 403 Forbidden when deleting, your token belongs to an agent. Use an administrator user token to delete contacts. ::: Create contact POST https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/contacts The body is a simple JSON object β€” at least one of email, phone_number, or identifier: { "name": "Maria Silva", "email": "[email protected]", "phone_number": "+5511999998888", "identifier": "CRM-123", "additional_attributes": { "company_name": "Acme" }, "custom_attributes": { "plano": "premium" } } - Optional: send inbox_id (and source_id) to link the contact to an inbox right away. - Response 200 with the created contact, including the id. Look up contact By id: GET https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/contacts/{CONTACT_ID} By exact email (requires administrator): GET https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/contacts/[email protected] :::info To search by free text (name, phone, company, partial), use the search endpoint β€” see How to query contacts, tickets, and messages in real time via API, section "Buscar contatos por texto livre" (Search contacts by free text). ::: Update contact PUT https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/contacts/{CONTACT_ID} Send only the fields you want to change: { "name": "Maria S. Silva", "custom_attributes": { "plano": "enterprise" } } :::success Unlike the bulk import with upsert: true, the individual update does not erase the fields you don't send. ::: - custom_attributes are merged with the existing ones (the others are not cleared). - To remove a specific custom attribute: POST https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/contacts/{CONTACT_ID}/destroy_custom_attributes { "custom_attributes": ["plano"] } - Response 200 with the updated contact. Delete contact DELETE https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/contacts/{CONTACT_ID} - Requires an administrator user. - Response 200 on success. :::warning If the contact is online at the time of the call, the deletion is blocked and returns 422. Try again when the contact is not active. ::: :::info To remove only tags from contacts (without deleting the contact), see How to bulk remove tags from contacts via API. ::: Request example (update) curl -X PUT \ 'https://{CLOUDCHAT_DOMAIN}/api/v1/accounts/{ACCOUNT_ID}/contacts/{CONTACT_ID}' \ --header 'content-type: application/json' \ --header 'api_access_token: SEU_TOKEN' \ --data '{ "name": "Maria S. Silva" }' Common errors | Status | Meaning | | --- | --- | | 403 Forbidden | Token without permission (deleting requires administrator) | | 422 Unprocessable Entity | Invalid data, or attempt to delete an online contact | | 404 Not Found | Contact not found in the account | Where to find the parameters - CLOUDCHAT_DOMAIN β€” domain visible in the browser URL - ACCOUNT_ID β€” in "ConfiguraΓ§Γ΅es da conta" (Account Settings) - API_TOKEN β€” at https://{CLOUDCHAT_DOMAIN}/app/accounts/{ACCOUNT_ID}/profile/settings Notes - Import multiple contacts at once: How to bulk import contacts via API - Import 1 contact from an external system (upsert, preserves fields): How to import an individual contact via API - Join duplicate contacts: How to merge contacts via API - Overview of all available APIs: Master Guide β€” How to access and operate Cloud Chat data via API

Last updated on Oct 02, 2026