Sending messages

Every send goes through one endpoint:

POST /api/v1/accounts/{account_id}/developer/messages

Three ways to address a message

Supply exactly one identifier. When a request carries more than one, the API reads them in the order below and ignores the rest.

1{ "conversation_id": 1234, "content": "It is on its way." }

The conversation supplies the inbox, so inbox_id is not needed. An id that belongs to another account returns 404.

1{ "contact_id": 42, "inbox_id": 5, "content": "It is on its way." }

The API reuses the most recent unresolved conversation on that inbox, and opens a new one when there is none. The contact needs an address the channel can reach: a phone number for WhatsApp, an email address for email. Without one, the request returns contact_not_messageable. A channel that cannot be addressed from a contact record at all returns the same code.

1{
2 "phone_number": "+971500000000",
3 "inbox_id": 5,
4 "content": "Hi, your order 121212 is confirmed",
5 "contact": { "name": "Omar A", "custom_attributes": { "crm_id": "9912" } }
6}

The number must be in E.164 format: a leading +, then the country code, then digits, with no spaces or dashes. When no contact has that number, the API creates one, and only then does it use the optional contact attributes. This path works on WhatsApp, Twilio, and SMS inboxes. Any other inbox returns unsupported_channel.

content is always required, even for a template send. It is what your agents read in the thread.

The messaging window

WhatsApp lets a business send free-form text only within 24 hours of the customer’s last message. Outside that window, only an approved template goes through. Facebook, Instagram, TikTok, Twilio WhatsApp, and API inboxes configured with a reply-time window have their own equivalents.

The API checks the window before it accepts the request, so the failure is immediate and explicit rather than a silent drop later:

1{
2 "error": "outside_messaging_window",
3 "message": "The customer service window is closed for this conversation. Send a template message instead."
4}

A conversation that has never received an inbound message has no open window at all. The first message to a new contact is always a template. Plain content to a number you have not heard from returns outside_messaging_window every time.

Some channels have no window: website, email, SMS, and API inboxes with no configured reply-time window. The check never affects them.

template_params skips the window check on every channel, including channels that do not support templates. On a channel that ignores the field, the API sends the free-form content instead, and the provider alone enforces the window. Send template_params only on a channel where you have an approved template.

Conversation reuse

An API send lands in the same thread as the customer’s replies. The API reuses the most recent conversation that is not resolved. When the last one was resolved, a new conversation opens. An inbox configured to lock to a single conversation always reuses the latest one, resolved or not.

A follow-up send to the same number therefore continues the existing thread instead of splitting your agents’ view.

Authorization scope

A key is authorized for a whole account and can send through any inbox in it. Read Errors for the full statement and how to store these keys.

Rate limit

The API accepts 600 requests per minute per key. Each key has its own budget, so one busy integration does not starve the others on the account. Over that limit it returns 429. See Errors.