WhatsApp Gateway
API referenceMessages

Send a message

Sends one message from the given session. There is a **single** send endpoint for every kind of message; the discriminated `type` field in the request body chooses which one. **Supported in v1:** `text`, `poll`, `location`, and `contact`. **Not implemented yet:** the media types `image`, `video`, `audio`, `document`, and `sticker` return **501 `not_implemented`** before any WhatsApp call is made. ### Delivery mode (`?async`) - **Synchronous (default, `?async=false`):** the call blocks until WhatsApp acknowledges the send and returns **200** with the final `SendResult`. - **Asynchronous (`?async=true`):** the gateway persists the send to a queue and returns **202** immediately with a queued `SendResult`. The final delivery status arrives later as a `message.status` event on the event stream. ### Idempotency (`Idempotency-Key` header) Supply a stable key to make retries safe: replaying a send with a key already seen for your organization returns the **original** result and does not dispatch a second WhatsApp message. ### Preconditions & errors - Requires the **`send`** capability. - The session must exist, be owned by your organization, and be connected. - **400 `validation_error`** — malformed body or an unsupported/invalid field for the chosen `type`. - **404 `not_found`** — the session does not exist or is not owned by your organization. - **429 `rate_limited`** — over the per-session send rate limit. A synchronous send is rejected with 429; an async send stays queued instead of failing. - **501 `not_implemented`** — a media `type` that is not built yet.

POST
/api/v1/sessions/{session}/messages

Authorization

AuthorizationBearer <token>

Send Authorization: Bearer <token>. The router accepts two kinds of token and tries each in turn: a frontend-minted login JWT (verified against the frontend JWKS; the person's org + role are read from it), or an api-key for a script/service (carrying a fixed set of gateway permissions). The bearerFormat: JWT label describes the person-login case.

In: header

Path Parameters

session*string

The WhatsApp session id (a session is one attached WhatsApp number) that performs the send. Must be a session your organization owns and that is currently connected.

Query Parameters

async?boolean

Delivery mode. When false (the default) the call blocks until WhatsApp acknowledges the send and the response is 200 with the final SendResult. When true the gateway enqueues the send, returns immediately with 202 (status "queued"), and the final delivery status arrives later as a "message.status" event on the event stream. Async also changes rate-limit behavior: an over-limit synchronous send returns 429, whereas an async send stays queued instead of failing.

Header Parameters

Idempotency-Key?string

Optional client-supplied idempotency token, scoped to your organization. If you retry a send with the same key, the gateway returns the result of the first send and does not dispatch a second message to WhatsApp. Use a fresh UUID per logical send and reuse it on retries. Omit it to send unconditionally.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

contact?

The contact card to share. Required for type contact.

latitude?number

Latitude of the shared location in decimal degrees. Required for type location.

Formatdouble
longitude?number

Longitude of the shared location in decimal degrees. Required for type location.

Formatdouble
media?

The media file to send (base64). Required for the media types (image/video/audio/document/sticker). Caption, replyTo, and mentions apply.

mentions?array<string>|

JIDs to @-mention in the message. Optional.

name?string

For a poll, the poll question; for a location, the place label. Required for poll; optional for location.

options?array<string>|

The poll's answer options. Required for type poll.

replyTo?string

Id of the message this one quotes/replies to (a wa_message_id). Optional.

selectableCount?integer

How many options a voter may pick in the poll (1 = single choice). Used for type poll.

Formatint64
text?string

The message text. Required for type text; ignored otherwise.

to*string

The recipient's JID: a user JID for a direct message (e.g. 6281234567890@s.whatsapp.net) or a group JID for a group (e.g. 120363021234567890@g.us). Required.

type*string

Which kind of message to send. Determines which other fields are required. text uses text (+ optional replyTo/mentions); poll uses name (question) + options + selectableCount; location uses latitude + longitude + optional name (label); contact uses contact. The media types image, video, audio, document, sticker use media (a base64 file + optional caption/filename, replyTo, mentions).

Value in

  • "text"
  • "poll"
  • "location"
  • "contact"
  • "image"
  • "video"
  • "audio"
  • "document"
  • "sticker"

Response Body

application/json

application/json

curl -X POST "https://example.com/api/v1/sessions/01HZX.../messages" \  -H "Content-Type: application/json" \  -d '{    "to": "6281234567890@s.whatsapp.net",    "type": "text"  }'
{  "mode": "string",  "outboxId": "string",  "replayed": true,  "status": "string",  "timestamp": 0,  "waMessageId": "string"}
{  "error": {    "code": "not_found",    "details": {      "property1": null,      "property2": null    },    "message": "session not found"  }}