> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.getdial.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getdial.ai/_mcp/server.

# WhatsApp lines

> Add WhatsApp to a Dial iMessage number, and choose which channel each message goes out on.

WhatsApp is a **channel on an iMessage line**, not a separate kind of number. A line that carries it can send iMessage *and* WhatsApp from the same phone number — so unlike every other channel, you say which one you mean on each message.

**WhatsApp is in beta and enabled per account.** [Talk to us](/documentation/reference/support) to request access.

Until it's enabled, the WhatsApp provisioning endpoints answer **`404`** rather than `403`. That's deliberate: to an account without access the capability doesn't exist, which is also what the dashboard shows — the number's menu has no such item. A `403` would advertise something you can't reach and can't ask for.

## Add WhatsApp to a line

Two entry points. Buy a new iMessage number with WhatsApp included:

```bash title="CLI"
dial number purchase --imessage --whatsapp
```

```bash title="cURL"
curl -X POST https://api.getdial.ai/v1/numbers \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"capabilities":["sms","call","imessage"],"whatsapp":true,"explicitProgrammaticConsent":"User modal confirmation"}'
```

…or add it to an iMessage number you already hold:

```bash title="CLI"
dial number whatsapp pn_123
```

```bash title="cURL"
curl -X POST https://api.getdial.ai/v1/numbers/pn_123/whatsapp \
  -H "Authorization: Bearer sk_live_..."
```

`whatsapp: true` is only valid alongside `capabilities: ["sms","call","imessage"]` — WhatsApp rides on an iMessage line, so there's no standard-number combination to ask for.

Both paths are **asynchronous**. Poll [List phone numbers](/documentation/platform/manage-phone-numbers) until the number's `whatsapp.status` is `ready`; sending before then is rejected.

## What the number tells you

A WhatsApp-capable line reports two things nothing else does:

```json
{
  "id": "pn_123",
  "capabilities": ["sms", "call", "imessage", "whatsapp"],
  "setupStatus": "ready",
  "whatsapp": {
    "status": "ready",
    "error": null,
    "retryAvailableAt": null
  }
}
```

* **`capabilities` gains `whatsapp` only once the channel actually works.** Before that the line reports `["sms","call","imessage"]`, because a capability you can see but can't use is worse than one that shows up a few minutes late.
* **`whatsapp.status` is independent of `setupStatus`.** They're separate tracks on the same line: voice caller-ID can be `ready` while WhatsApp is `failed`, and the other way round. One status field could never carry both, so there are two.
* **`whatsapp.retryAvailableAt`** is when the channel will accept another verification attempt, or `null`. It's the one failure you can neither fix nor retry around — if it's set and in the future, a retry is refused until it lifts. Show the time rather than a button that won't work.

## Choose the channel

`channel` is accepted both when [sending a message](/documentation/capabilities/send-an-sms) (`POST /api/v1/messages`) and on a typing indicator (`POST /api/v1/typing`, or [`dial typing start`](/documentation/cli/commands#typing-start)):

```jsonc
{ "channel": "imessage" }   // the iMessage rail, with its automatic RCS/SMS fallback
{ "channel": "whatsapp" }   // the WhatsApp rail
```

```bash title="CLI"
dial message --to +14155550123 --body "Hello over WhatsApp" --from-number pn_123 --channel whatsapp
```

```bash title="cURL"
curl -X POST https://api.getdial.ai/v1/messages \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"to":"+14155550123","fromNumberId":"pn_123","body":"Hello over WhatsApp","channel":"whatsapp"}'
```

**Omitting `channel` keeps the line's own default**, so nothing you already send changes: a standard number sends SMS, an iMessage number sends iMessage. You only need `channel` on a line that carries both rails — and passing it explicitly is a good habit there, because "the default" is the one thing that could change under you.

Two ways it's rejected, both `400`:

* `channel: "whatsapp"` on a line whose WhatsApp track isn't live — *"WhatsApp isn't connected on this number."*
* `channel: "imessage"` on a number with no iMessage rail (a standard SMS/call number) — the number can't do it, so the ask is refused rather than quietly delivered as an SMS.

## What WhatsApp does differently

**Outbound messages are text-only.** A send with `mediaUrls` or `media` on `channel: "whatsapp"` is rejected with `400` — *"This WhatsApp number sends text only."*

**Inbound attachments are delivered normally.** A photo someone sends *to* your WhatsApp line arrives as a regular `media` array on the [`message.received`](/api-reference/events/message-received) event, hosted by Dial like any other attachment. The limitation is on the way out only.

**Delivery status starts unconfirmed and firms up.** A WhatsApp send comes back with `deliveryState: "unconfirmed"` (`status: "unknown"`) — the channel assigns the message its identity at send time, so there's nothing honest to report yet. Receipts then arrive as [`message.status_changed`](/api-reference/events/message-status-changed) events and the state climbs from there.

**Reads are reported.** Unlike SMS, WhatsApp tells you when a message was read, so `readState` and `readAt` are meaningful on this channel. In a [group](/documentation/capabilities/groups), both delivery and read mean *every* recipient.

**One send at a time per line.** A WhatsApp line sends messages one after another. A second send that arrives while the first is in flight is **refused, not queued** — so you get an error immediately and retry, rather than waiting behind something you can't see.

**Typing indicators inside a group aren't supported yet** — `channel: "whatsapp"` typing works for a one-to-one conversation only. It's on the roadmap.

## Next

#### [Group conversations](/documentation/capabilities/groups)

Send to and read from WhatsApp groups.

#### [Manage phone numbers](/documentation/platform/manage-phone-numbers)

Provision and configure your lines.