Messages

Send message

Send a message in a conversation. Supports text, attachments, quick replies, buttons, templates, and message tags. Attachment and interactive message support varies by platform.

WhatsApp per-recipient rate limit: WhatsApp caps how many messages you may send to the same recipient in a short window and rejects the excess with error code 131056 ("Too many messages sent to this recipient"). Pace sends to a single recipient at roughly 10 per minute; bursts above that return a 400 with code 131056. Sends to other recipients are unaffected, so parallelise across recipients rather than flooding one.

iMessage pacing: messages to contacts who have not written to the sender in the last 24 hours must be at least 2 minutes apart per sender; a send inside that window returns 429 with code new_contact_limit and the time to retry. Replies to contacts who wrote within the last day are not paced. A thread opened with POST /v1/inbox/conversations takes at most two follow-ups before the contact replies, at least 24 hours apart (429 new_contact_limit sooner, 409 recipient_must_message_first for a fourth message). Each such follow-up counts as a new conversation: no links, emails, phone numbers, prices or attachments (400 invalid_content), and it uses the sender's 15-minute spacing and daily warm-up (429 new_contact_limit). Text must be shorter than 10,000 characters.

WhatsApp template messages: to send an approved template into this conversation (required when the 24-hour customer-service window is closed), use the template field with a single element carrying the template reference: { "elements": [{ "name": ..., "language": ..., "components": [...] }] }. See the template field below for the exact shape. To send a template to a phone number you have no conversation with yet, use the create-conversation endpoint (POST /v1/inbox/conversations) instead.

Zernio resolves the exact APPROVED template name and language before any WhatsApp template send. A failed lookup or missing exact definition sends no message and returns code platform_api_error, type platform_error, and platform whatsapp. Sanitized Meta code, message, and error_data.details are returned in platformError; details identifies phase: template_lookup, the query-free endpoint, upstream status, and only safe provider usage or retry headers.

WhatsApp rich interactive messages (list, CTA URL, Flow, location request) are available via the interactive field. Tap events are delivered through the message.received webhook with WhatsApp-specific metadata fields (interactiveType, interactiveId, flowResponseJson, flowResponseData).

Idempotency: send an Idempotency-Key header to make retries safe (e.g. after a client-side timeout where delivery is unknown): same key + same body replays the original response (with Idempotent-Replayed: true) instead of sending the message a second time; same key + different body returns 422; a key still in flight returns 409. Works for JSON and multipart (file upload) requests alike. Keys are retained for 24 hours.

Only successful (2xx) responses are stored for replay: if the request throws or returns a non-2xx status, the key is released so the same key can be retried once the problem is fixed. The header therefore protects the "request succeeded but the response was lost" case. For an ambiguous failure (a 5xx or a network timeout), reconcile before retrying: a failure after the platform already accepted the message also releases the key, and a blind retry could send it twice. List the conversation's messages first, and treat an empty result as inconclusive rather than as proof nothing was sent, since a send that failed while being recorded leaves no trace on our side.

post/v1/inbox/conversations/{conversationId}/messages

Path parameters

conversationIdstring required

Opaque conversation identifier, accepted verbatim from the list endpoint or from the conversationId on inbox webhooks. Format not to be assumed.

Headers

Idempotency-Keystring

Optional client-generated unique key (e.g. a UUID) that makes retries safe. Same key + same body replays the original response; same key + different body → 422; key still processing → 409.

Request body

accountIdstring required

Account ID

messagestring

Message text

attachmentUrlstring

URL of the attachment to send (image, video, audio, or file). The URL must be publicly accessible. For binary file uploads, use multipart/form-data instead. On WhatsApp, combining an image, video, or file with buttons renders the media as the header of one interactive reply-button message; audio cannot be combined with buttons.

category'utility'

WhatsApp only (Meta Direct Send). Sends this message as a business-initiated UTILITY message without an approved template, for example outside the 24-hour customer service window; Meta matches or auto-creates a template asynchronously. The WhatsApp Business Account must be eligible for Direct Send, otherwise the send fails with an error telling you to use an approved message template instead. Supported only for text messages (link preview ok) and interactive messages (reply buttons, CTA URL buttons, voice-call button, header of text/image/video/document). Cannot be combined with template, attachments, location, or contacts. Utility messages only; marketing content is not allowed under this category. Accepted on the JSON body only, not on multipart requests.

linkPreviewboolean

WhatsApp and iMessage. Set false to send the message without a link-preview thumbnail (WhatsApp: the first URL; iMessage: every link renders as plain text). Defaults to true, which is how every WhatsApp text has been sent to date. Ignored on other platforms. Accepted on the JSON body only, not on multipart requests.

attachmentType'image' | 'video' | 'audio' | 'file'

Type of attachment. Defaults to file if not specified.

attachmentNamestring

WhatsApp only. Display name for a document sent via attachmentUrl with attachmentType: file (e.g. "Report.pdf"). Maps to the recipient's file name; without it WhatsApp derives the name from the URL and shows "Untitled". Ignored for image/video/audio and for binary uploads (which use the uploaded file's name).

voiceNoteboolean

WhatsApp only. When true on an audio attachment, the message is sent as a voice message (PTT): the recipient sees the waveform + voice-note UI instead of a basic audio attachment. The audio file MUST be .ogg encoded with the OPUS codec (mono) per Meta's voice-message contract; other formats are rejected by WhatsApp. Ignored for non-audio attachments.

subjectstring

iMessage only (JSON body only). Bold title line rendered above the message text. Rejected with 400 on other platforms; ignored on voice-message sends.

effect'slam' | 'loud' | 'gentle' | 'invisibleInk' | 'echo' | 'spotlight' | 'balloons' | 'confetti' | 'love' | 'lasers' | 'fireworks' | 'shootingStar' | 'celebration'

iMessage only (JSON body only). Apple screen/bubble animation played when the message arrives. Rejected with 400 on other platforms.

contactCardboolean

iMessage only (JSON body only). When true, attaches the sender's contact card (vCard) so the recipient can save the sender. Counts as message content on its own, so message becomes optional.

channel'imessage' | 'sms' | 'rcs' | 'whatsapp'

iMessage only (JSON body only). Overrides the delivery channel for this one send; the provider otherwise picks it automatically. The sender must carry the matching add-on (SMS, RCS or WhatsApp), or the send fails. Not a default to set on every request. Rejected with 400 on other platforms.

messagingType'RESPONSE' | 'UPDATE' | 'MESSAGE_TAG'

Facebook messaging type. Required when using messageTag.

messageTag'CONFIRMED_EVENT_UPDATE' | 'POST_PURCHASE_UPDATE' | 'ACCOUNT_UPDATE' | 'HUMAN_AGENT'

Facebook message tag for messaging outside 24h window. Requires messagingType MESSAGE_TAG. Instagram only supports HUMAN_AGENT.

replyTostring

Platform message ID to quote-reply to. For WhatsApp, pass the wamid; for Telegram, the Telegram message ID (delivered as message.platformMessageId on webhooks, and as id on each entry of the list-messages endpoint). On Slack it threads the reply (thread_ts) instead of quoting. Instagram and Facebook Messenger do not support send-side quote replies: the message is sent without a quote and the successful response includes a warnings entry with code ignored_field and param replyTo. Other platforms without send-side reply support ignore this field.

Response

Message sent

successboolean

Changes