Sending and receiving
One endpoint sends every message type. Delivery is asynchronous by default, and every state change comes back to you as a webhook.
Endpoints
The send body
| Field | Type | Notes |
|---|---|---|
session | string | Id or handle. Optional if the key is scoped to one number. |
to | string | A phone number in any format, or a JID. Normalised for you. |
type | string | Defaults to text. |
text | string | The body, for a text message. |
caption | string | Caption on an image, video or document. |
media_id | uuid | From an upload. Send the same file many times without re-uploading. |
file | file | Upload and send in one multipart request. |
latitude / longitude | number | With optional location_name and location_address. |
contacts | array | Contact cards, each with a name and a phone. |
reply_to | string | A WaveSenda or WhatsApp message id to quote. |
mentions | string[] | Numbers to @-mention, in a group. |
view_once | boolean | Media that disappears after it is opened. |
disable_link_preview | boolean | Suppress the URL card. |
idempotency_key | string | Makes the send safely retryable. |
wait | boolean | Block briefly for the WhatsApp id instead of returning on queue. |
priority | boolean | Jump ahead of campaign traffic. For OTPs and other time-critical sends. |
Message types
# 1. Upload once
curl -X POST "$WAVESENDA_URL/messages/media/" \
-H "Authorization: Bearer $WAVESENDA_API_KEY" \
-F "file=@receipt.png" -F "type=image"
# → { "id": "3c9a...", "type": "image", "url": "https://..." }
# 2. Send it as often as you like
curl -X POST "$WAVESENDA_URL/messages/send/" \
-H "Authorization: Bearer $WAVESENDA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"session":"support","to":"+237670000000",
"type":"image","media_id":"3c9a...","caption":"Your receipt"}'{
"session": "support",
"to": "+237670000000",
"type": "location",
"latitude": 4.0511,
"longitude": 9.7679,
"location_name": "Warehouse 3",
"location_address": "Bonabéri, Douala"
}{
"session": "support",
"to": "120363000000000000@g.us",
"text": "@237670000000 this one is yours.",
"mentions": ["+237670000000"],
"reply_to": "wamid.HBgM..."
}A voice note is its own type rather than plain audio: it renders as a waveform in WhatsApp, and in several markets it is the most common thing people send back to you.
Delivery states
queued and sending are ours; the rest mirror WhatsApp’s own acknowledgement levels. Each transition fires a webhook, so you never have to poll.
| Status | Meaning |
|---|---|
queued | Accepted and waiting on the session. Not terminal. |
sending | Handed to the WhatsApp socket. |
sent | One tick. WhatsApp has it. |
delivered | Two ticks. The handset has it. |
read | Blue ticks — if the recipient shows read receipts at all. |
played | A voice note was listened to. |
failed | Terminal. Read error_code for why. |
read is not evidence a message was ignored, and building a follow-up rule on it will misfire.Editing and revoking
WhatsApp allows an edit for about 15 minutes after sending, and a delete-for-everyone for about two days. Both limits are enforced by WhatsApp rather than by us, so a late call fails rather than silently doing nothing.
Typing indicators
If an agent takes four seconds to answer, a typing indicator is the difference between a considered reply and a suspiciously instant one.
{ "session": "support", "to": "+237670000000", "presence": "composing" }Reaching people who are not there
Not every number has WhatsApp. Check before a bulk send rather than discovering it one failed message at a time — a run of sends to non-existent accounts is itself a signal that counts against the number.
{ "session": "support", "numbers": ["+237670000000", "+237690000000"] }