Skip to main content
Endpoint · POST /conversation/actions
The POST /conversation/actions endpoint runs a group of up to 10 actions on a single conversation, in the order you send them. Instead of making N requests to label, leave a note, and run the AI, you chain them into a single request. It’s the recommended way to mutate a conversation from an external client. Each element of the actions array carries a type field. send_message unifies the four send modes (text, media, quick reply, template). If you pass a template alongside a primary (text/media or quick reply), the server decides by the 24h window: it sends the primary if open, or the template if closed.
A group allows up to 10 actions, of which at most 3 can trigger the AI. Exceeding it fails with BATCH_LIMIT_EXCEEDED.
Each action has its own page with its fields and an example — open the one you need from the table or the nav. To send media, first upload it with the Upload media flow.

Identify the conversation

The group runs on one conversation: you identify it with the conversation object, which carries exactly one of uuid, whatsapp_user_id, username, or phone, plus channel (required).
string
Stable key of a conversation you already know. The most direct path.
string
The contact’s BSUID (Meta’s opaque identity). Resolves by exact match; recommended identifier going forward.
string
Public WhatsApp username, with or without @ and case-insensitive. If two distinct contacts share it in the same channel, the API returns 409 (USERNAME_AMBIGUOUS); the same username in different channels is not ambiguous: channel resolves it.
string
Phone in E.164 format. If it is duplicated across two distinct contacts in the same channel, the API returns 409 (PHONE_NUMBER_AMBIGUOUS) instead of guessing; the same number in different channels is not ambiguous: channel resolves it.
string
required
The channel’s public key — copy it from the dashboard under Settings → Channels (the Channel key field), or list them with GET /channels. Required in every request: it sets the target channel. On the contact-based paths (phone, username, whatsapp_user_id) it restricts resolution to that channel; with uuid the engine ignores it, but the contract still requires it. A key that does not exist → 404 (CHANNEL_NOT_FOUND).
Full reference (resolution order, conversation merging, and contact ambiguities) in Identify a conversation.

How it runs

1

Synchronous validation

The API validates the request. If the preflight rejects it (e.g. the AI has no tokens), it returns a synchronous 4xx and no action runs.
2

202 Accepted

If validation passes, it returns 202 immediately; the group runs in the background.
3

Execution in order

The actions run one by one, in the order sent.
The 202 confirms the group was accepted, not that every action succeeded. The per-action result does not travel in the response — query it in the conversation status or in the business’s activity log.

Stop on error

stop_on_error controls what happens when an action fails during execution:

Escalation to pending

escalate_on_error controls whether a group failure escalates the conversation to inbox_status='pending' for a human to review:
Integrator input errors (*_NOT_FOUND, *_AMBIGUOUS, WINDOW_CLOSED, TEMPLATE_NOT_APPROVED, etc.), misused payment markers (PAYMENT_MARKER_UNKNOWN, PAYMENT_MARKER_UNSUPPORTED_FIELD, TEMPLATE_BODY_TOO_LONG — the fix belongs in the text you sent, not in the conversation), billing guards (WALLET_BLOCKED, VISION_WALLET_BLOCKED), and the mark_resolved integrity guard (TRANSCRIPTION_REQUIRED_TO_RESOLVE) never escalate — fix them and retry without human intervention.

Assembling an action list

Each action is an object in the actions array, identified by its type. A request groups several actions on the same conversation, run in the order sent. The conversation object always includes channel. Example — label, leave a note, and run the AI, without halting on failures:

Identify by different fields

Change only the identifier inside conversation (channel is always included); the rest of the request does not change:
Hand off to a human — a single unassign_ai action, no fields. It’s idempotent: if the conversation already has no AI, it’s a successful no-op.
If the preflight rejects the group, the response is a synchronous 4xx and no action runs. See Errors.