Documentation
Sign inGet started

Sending WhatsApp messages

This guide covers the send endpoint, POST /v1/whatsapp/messages. You build one JSON payload with a recipient and a template; Bird returns 202 Accepted with a message ID and delivers asynchronously. Business-initiated WhatsApp is template-only — you send a pre-approved template, not free text — and each request sends one message to one recipient. There is no batch endpoint.

A minimal send

The smallest valid payload is a to recipient and a template with its name. Include language unless the template has a single language, and fill any {{n}} variables the template declares through components.
Code example
curl -X POST https://us1.platform.bird.com/v1/whatsapp/messages \
  -H "Authorization: Bearer bk_us1_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+15551234567",
    "template": {
      "name": "bird_otp",
      "language": "en",
      "components": [
        { "type": "body", "parameters": [{ "type": "text", "text": "481920" }] }
      ]
    }
  }'
Use your regional host (https://us1.platform.bird.com or https://eu1.platform.bird.com) with a matching bk_{region}_... key. There is no from field: Bird selects the sender number from the template's category.

Building up the payload

Recipient

to is a single recipient in E.164 format — a leading +, country code, and subscriber number, e.g. +15551234567. One message goes to one recipient; there is no recipient array and no batch send, so reach many people with one call per recipient.

Template

template names the pre-approved template to send:
  • name (required) — the template's name, e.g. bird_otp. It must match an approved template in your workspace (lowercase letters, digits, and underscores).
  • language — the template's language tag, e.g. en or pt_BR. Omit it only when the template exists in a single language.
  • components — the values that fill the template's {{n}} variables (see below). Omit it for a template that has no variables.
Browse your approved templates, their languages, and a rendered preview on the Templates page.

Components and parameters

Templates in the catalogue today carry numbered variables — {{1}}, {{2}}, and so on. You supply their values through components. Each component names a type (header, body, or button) and a parameters array; each parameter is { "type": "text", "text": "..." }, applied in order (the first parameter fills {{1}}). Only text parameters are supported today.
For example, a one-time-passcode template whose body reads {{1}} is your verification code and whose button copies the code takes the code as both a body parameter and a button parameter:
Code example
{
  "components": [
    { "type": "body", "parameters": [{ "type": "text", "text": "481920" }] },
    { "type": "button", "parameters": [{ "type": "text", "text": "481920" }] }
  ]
}

Category and sender

Category and sender are properties of the template, not of the send. A template's category — authentication, utility, or marketing — determines how WhatsApp treats the message, which sender number Bird uses, and, together with the destination country, what the message costs. There is no from field on the request.

Field reference

FieldTypeRequiredLimits / notes
tostring (E.164)yesOne recipient per message
template.namestringyesAn approved template name; lowercase letters, digits, and underscores
template.languagestringno*Template language tag (e.g. en, pt_BR); omit for single-language templates
template.componentsarraynoFills {{n}} variables; component type is header, body, or button
* language is optional only when the template has a single language.

What isn't supported yet

The request accepts to and template and nothing else. The following are part of the roadmap but rejected today — a request that includes them fails with a 422:
  • Free-text (non-template) sends — WhatsApp sends are template-only in this release.
  • Non-text parameters — media, location, and other parameter types are reserved; only text is supported.
  • tags and metadata — not accepted on a WhatsApp send.
  • Batch sending — there is no /v1/whatsapp/batches; send one message per call.
  • Recipients without a phone number — a WhatsApp-ID-only recipient is rejected before any charge.

The async model: what 202 means

A successful send returns 202 Accepted with a message ID and status: accepted. The 202 is returned only after the send is durably accepted — it is never accepted and then silently dropped. Hard failures you can fix (an invalid recipient, an unknown template, a missing variable) fail immediately with a 422; a send that would exceed your workspace balance, or a route with no price, is rejected before anything is charged. Actual delivery happens asynchronously: the message moves to sent when Bird hands it to WhatsApp, then to a terminal status (delivered or failed) when the receipt arrives, reported through events, webhooks, and the read endpoints. A read receipt is surfaced separately as a read_at timestamp and a whatsapp.read event, not as a status.

Cost and billing

Billing — Bird charges for a WhatsApp message when it is sent, regardless of whether it is ultimately delivered. The price depends on the destination country and the template's category; see WhatsApp pricing.
WhatsApp is priced per message, keyed on the template's category and the recipient's country. Bird charges your wallet up-front, when it accepts and processes the send — before the message is dispatched to WhatsApp — and the charge stands whether or not the message is later delivered. If the route has no price or your balance is insufficient, the send is rejected with an error and nothing is charged.

Retrying safely

Send the Idempotency-Key header with a unique value per logical send, and retries become safe: if your first request succeeded but you never saw the response (timeout, dropped connection), replaying the same request with the same key returns the original result — and the response carries an Idempotency-Replay header — instead of sending, and charging for, a duplicate message. See idempotency for key format and retention.

Next steps