Messages
Send WhatsApp messages via the API.
Send a message
Send a text, image, video, or document to any WhatsApp number or group.
Request body
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
to | string | β | Phone number with country code, or a group JID |
text | string | β (unless sending media) | The message text |
imageUrl | string | β | Public URL of an image to send |
videoUrl | string | β | Public URL of a video to send |
documentUrl | string | β | Public URL of a document to send |
fileName | string | β (required with documentUrl) | File name shown to recipient |
connection_id | string | β | Which of your numbers to send from (alias: from) β a Personal or Business number's id from GET /api/v1/connections. Defaults to your API key's Personal number, or the workspace's only Personal number. |
channel | string | β | Set to "business" to send from your Business WhatsApp number without naming it (only when you have exactly one). |
Sending from a Business WhatsApp number
Pass the Business number's connection_id (or "channel": "business"). Business numbers support everything above plus these message types:
| Field | Type | Description |
|---|---|---|
buttons | array | Up to 3 quick-reply buttons under text. Each: { "id": "confirm", "title": "Confirm" } β title max 20 characters; id comes back to you when tapped (defaults to btn_1, btn_2β¦). |
list | object | A menu under text: { "button_text": "View options", "sections": [{ "title": "...", "rows": [{ "id": "...", "title": "...", "description": "..." }] }] }. Max 10 rows in total; row title max 24 characters, description max 72. sections[].title is required when there is more than one section. |
cta_url | object | One button under text that opens a link: { "display_text": "Track order", "url": "https://..." } β label max 20 characters. |
location | object | A map pin: { "latitude": 28.6139, "longitude": 77.209, "name": "Our showroom", "address": "..." }. |
audioUrl | string | Public URL of an audio file or voice note (OGG, MP3, AAC, M4A, AMR). Sent without a caption. |
header | string | Optional bold heading on a buttons, list or link-button message (max 60 characters). |
footer | string | Optional small text under a buttons, list or link-button message (max 60 characters). |
These are Business-only β sending them from a Personal number returns 400.
The 24-hour rule. WhatsApp only lets a Business number send free-form messages β text, media, buttons, lists, link buttons and locations β within 24 hours of the customer's last message to that number. Outside that window the API returns 422 outside_window; send an approved template instead with POST /api/v1/templates/:id/send, which works at any time.
Business messages are charged to your wallet the same way as messages sent from the Inbox. Group sends are Personal-only.
When a customer taps a button or picks a list row, your message.received webhook carries the id you set β see interactive_payload there.
Response
A Business send also returns "channel": "business" and the connection_id it was sent from.
Keep message_id β the message.delivered and message.read webhooks for this send carry the same value in wa_message_id, so that's how you match a status back to your message. Treat it as an opaque string: depending on the channel it may not look like a 3EB0β¦ WhatsApp id. It can occasionally be null; the message was still sent, but its status can't be matched.
Examples
Send a text message:
Send an image:
Business number β message with buttons:
Business number β list menu:
Business number β link button:
Send to a group:
JavaScript example
Errors
| Status | error | Meaning |
|---|---|---|
| 400 | bad_request | A field is missing or invalid β the message says which. |
| 400 | ambiguous_connection | You have more than one number of that kind; pass connection_id. The response lists the choices. |
| 402 | insufficient_balance | Not enough wallet balance for a Business message. |
| 422 | outside_window | Business number, but the customer hasn't messaged it in the last 24 hours. Use a template. |
| 422 | no_connection / no_session | No active number to send from. |
| 429 | rate_limited / daily_limit_reached | Too many requests, or the Business number's daily limit is reached. |
| 502 | send_failed | WhatsApp rejected the message; the message explains why. |
| 404 | flow_not_found | No Flow with that id or name. See GET /api/v1/flows. |
| 422 | flow_not_published / flow_wrong_number | The Flow isn't published yet, or it belongs to a different Business WhatsApp account than the number you're sending from. |
Send a WhatsApp Flow (a form inside WhatsApp)
A Flow is a form the customer fills in without leaving WhatsApp: a booking, a lead form, a document checklist. Create and publish it under WhatsApp Flows in SalesByte, then send it from a Business number to a customer who has messaged you in the last 24 hours.
First list your Flows:
Only PUBLISHED Flows can be sent, and only from a number listed in connection_ids.
Then send it with POST /api/v1/messages:
| Field | Required | Description |
|---|---|---|
flow.id | Yes | The Flow's id from GET /api/v1/flows, or its name. |
flow.cta | No | The button label, up to 20 characters. Defaults to the Flow's own. |
flow.data | No | Values to pre-fill the Flow's first screen. |
text, header, footer | No | Override the message shown with the Flow. |
When the customer submits the form you get a message.received webhook with "interactive_type": "nfm_reply". The answers are in interactive_payload.response, keyed by the field names in your Flow.
Mark a message read (and show typing)
Marks a customer's Business WhatsApp message as read, so they see blue ticks. With "typing": true they also see typing⦠for up to 25 seconds, or until your next message reaches them. Use it while your bot is preparing a reply. Typing is only available together with a read receipt. This call is free.
Request body
| Field | Required | Description |
|---|---|---|
wa_message_id | Yes | The wa_message_id from the message.received webhook. |
typing | No | true to show typing as well. Default false. |
Response
Errors
| Status | error | Meaning |
|---|---|---|
| 400 | missing_wa_message_id / invalid_typing | A field is missing or invalid. |
| 404 | not_found | No message with that id in your workspace. |
| 422 | not_inbound | That message was sent by you, not the customer. |
| 422 | not_business | Read receipts and typing work on Business WhatsApp numbers only. |
| 422 | no_connection | The number the message came in on is no longer connected. |
| 502 | send_failed | WhatsApp rejected the request; the message explains why. |