Home API and integrations | Keys, endpoints and webhooks Send Proactive Message via API (WhatsApp and Web Widget)

Send Proactive Message via API (WhatsApp and Web Widget)

Last updated on Oct 21, 2026

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

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.

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.