> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wave.sa/llms.txt
> Use this file to discover all available pages before exploring further.

# WhatsApp

> Send WhatsApp messages, manage templates, and receive delivery-status events.

WhatsApp messaging runs through the same channel layer as Wave's other messaging surfaces. You send a message, get a `queued` acknowledgement immediately, and the real outcome (`delivered`, `read`, `failed`) arrives later as a [webhook](/webhooks) event.

<Note>
  Sending (text, template, and media) is live — messages reach real phones. Delivery-status and inbound-message webhooks (`message.delivered`, `message.read`, `message.received`) are being finalized on the provider side; until then, sent messages may continue to show as `queued` in the dashboard even after they've actually delivered.
</Note>

## Sending a message

`POST /v1/messages`

| Field             | Required | Description                                                                           |
| ----------------- | -------- | ------------------------------------------------------------------------------------- |
| `channel`         | ✅        | `whatsapp` (also accepts `sms`, `webchat`, `email` — those channels aren't live yet). |
| `to`              | ✅        | Recipient's WhatsApp number in E.164 (`+9665XXXXXXXX`).                               |
| `content`         | ✅        | One of the three content kinds below.                                                 |
| `conversation_id` | —        | Groups related messages into one thread. Defaults to a new thread per message.        |
| `metadata`        | —        | Key/value object, echoed back on webhooks.                                            |

Returns `202` with `message_id`, `provider_message_id`, and `status: "queued"`.

### Content kinds

**Text** — a plain message. Only allowed within a 24-hour window of the customer's last message; outside it, use a template.

```json theme={null}
{ "channel": "whatsapp", "to": "+9665XXXXXXXX", "content": { "kind": "text", "body": "Your order has shipped!" } }
```

**Template** — a pre-approved message for contacting a customer outside the 24-hour window (see [Templates](#templates) below).

```json theme={null}
{
  "channel": "whatsapp",
  "to": "+9665XXXXXXXX",
  "content": { "kind": "template", "name": "order_update", "language": "en", "variables": { "1": "12345" } }
}
```

**Media** — an image, document, audio, or video file.

```json theme={null}
{
  "channel": "whatsapp",
  "to": "+9665XXXXXXXX",
  "content": {
    "kind": "media",
    "mediaType": "image",
    "url": "https://your-cdn.example/receipt.png",
    "contentType": "image/png",
    "sizeBytes": 84213,
    "filename": "receipt.png"
  }
}
```

<Info>
  `contentType` and `sizeBytes` are required for media to actually send — Wave's WhatsApp provider needs both known upfront and can't derive them from the URL alone. Fetch the file's headers yourself (a `HEAD` request) if your own system doesn't already know them.
</Info>

## Templates

Templates are reviewed and approved before they can be used to start a conversation with a customer.

**`GET /v1/messages/templates`** — list your templates and their approval status (`pending` / `approved` / `rejected`).

**`POST /v1/messages/templates`** — submit a new template.

| Field       | Required                           | Description                                                                                                      |
| ----------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `name`      | ✅                                  | Unique template name.                                                                                            |
| `language`  | ✅                                  | Language code the template was written in (`en`, `ar`, …).                                                       |
| `category`  | ✅                                  | `UTILITY`, `MARKETING`, or `AUTHENTICATION` — this affects both approval rules and pricing.                      |
| `body`      | Required for `UTILITY`/`MARKETING` | Template text. Use `{{1}}`, `{{2}}`, … for variables. Ignored for `AUTHENTICATION` — see below.                  |
| `variables` | —                                  | Sample values for each variable, used during approval review. Not used for `AUTHENTICATION`.                     |
| `header`    | —                                  | Plain-text header line. Ignored for `AUTHENTICATION`. A media (image/video/document) header isn't supported yet. |
| `footer`    | —                                  | Plain-text footer line. Ignored for `AUTHENTICATION`.                                                            |
| `buttons`   | —                                  | Up to 3 buttons — see [Buttons](#buttons) below. Ignored for `AUTHENTICATION` (use `otpButton` instead).         |
| `otpButton` | —                                  | `AUTHENTICATION` templates only — adds a one-tap "copy code" button.                                             |

<Note>
  An `AUTHENTICATION` template has no custom body at all — Meta owns the verification-code wording, so `body`/`variables`/`header`/`footer`/`buttons` are all ignored for this category. The `otpButton` adds a one-tap "copy code" button with no label to configure (Meta generates it).
</Note>

### Buttons

Each entry in `buttons` is one of three types:

```json theme={null}
{ "type": "QUICK_REPLY", "text": "Track order" }
{ "type": "URL", "text": "View details", "url": "https://your-site.example/orders/1" }
{ "type": "PHONE_NUMBER", "text": "Call us", "phoneNumber": "+9665XXXXXXXX" }
```

### Viewing, editing, and deleting a template

**`GET /v1/messages/templates/:name?language=en`** — full detail for one template (body, header, footer, buttons) — the `language` query parameter is required since the same name can exist in more than one language.

**`PUT /v1/messages/templates/:name?language=en`** — update an existing template. Takes the same body as create; editing a template resubmits it for approval, so its status returns to `pending`.

**`DELETE /v1/messages/templates/:name?language=en`** — permanently remove a template.

## Delivery-status events

Subscribe to these via [webhooks](/webhooks) the same way as call events. `message.sent` is listed for completeness but is **not** delivered to your webhook endpoint — it's Wave's internal billing event, generated the moment a send is accepted.

| Event               | Meaning                                             | Delivered to your webhook?        |
| ------------------- | --------------------------------------------------- | --------------------------------- |
| `message.sent`      | Accepted for delivery.                              | No — internal billing event only. |
| `message.received`  | A customer replied to you.                          | Yes                               |
| `message.delivered` | The message reached the customer's device.          | Yes                               |
| `message.read`      | The customer opened it.                             | Yes                               |
| `message.failed`    | Delivery failed — check the event's `reason` field. | Yes                               |

```
queued ──▶ sent ──▶ delivered ──▶ read
                 └─▶ failed
```

## Message log

Every inbound and outbound WhatsApp message is recorded. View them on the **Messages** page in the dashboard, or fetch them with **`GET /v1/messages`** (cursor-paginated, same shape as [call logs](/web-callback#call-logs)).
