# WhatsApp conversations

> Start a WhatsApp conversation with an approved template, and let your agent take it from the first reply.

Your agents already answer people who write to your WhatsApp numbers. With the API, your system can
write first: an appointment reminder, a delivery notice, a renewal. WhatsApp allows a business to
start a conversation only with a **message template** Meta has approved, so that is what you send.
When the person writes back, the number's agent answers, in the same conversation.

## The key it needs

**Start WhatsApp conversations** (`whatsapp:write`), a permission that is never part of a starting
point: it puts a message on a real person's phone. Starting a conversation needs a **live** key. A
test key can list your numbers and templates, and sends nothing, because there are no WhatsApp test
numbers.

## Find your number and its templates

```sh
node aigently.mjs whatsapp list-senders
node aigently.mjs whatsapp list-templates 7d9f1b3d-…
```

`GET /v1/whatsapp/senders` lists your WhatsApp numbers and the agent that answers each.
`GET /v1/whatsapp/senders/{id}/templates` lists the templates Meta has approved for that number's
business account, each with its `body` and how many `parameters` it takes. Write and approve
templates in Meta's WhatsApp Manager; the list here follows within a few minutes. It needs the
connection's WhatsApp Business account id and an access token: without them, the request is refused
with `whatsapp_not_ready`.

## Start the conversation

`POST /v1/whatsapp/conversations`, with an `Idempotency-Key`:

```json
{
  "sender_id": "7d9f1b3d-…",
  "to_number": "+966501234567",
  "template": {
    "name": "appointment_reminder",
    "language": "en_US",
    "parameters": ["Sara", "Monday at 10"]
  },
  "variables": { "first_name": "Sara" },
  "metadata": { "booking": "4471" }
}
```

- **The template is checked first.** A name or language Meta has not approved, or the wrong number
  of `parameters`, is refused with `validation_failed`, naming the field. Nothing is sent.
- **The answer is the conversation**, `channel: whatsapp` and `direction: outbound`. Its first line
  is the template's own words, so when the person writes back, the agent knows what it said. Your
  `variables` fill the agent's placeholders, as they do for a call.
- **It waits a day for an answer**, which is WhatsApp's own window for one. After a reply, it closes
  after the agent's usual quiet period. If nobody answers within a day, it ends.
- **Sent once.** The same `Idempotency-Key` again answers with the first conversation and sends
  nothing.
- **Meta can still refuse a message**, for example to a number that is not on WhatsApp. The
  conversation then ends `failed`, with Meta's reason in `error`. A refusal worth retrying, such as
  a rate limit, is retried by the platform. Each retry checks again first: if the project has been
  frozen, the credit used up or the number listed in the meantime, or the retries run out, the
  template is not sent and the conversation ends `failed` with the reason in `error`.
- **Not to anyone on a block list.** A number on your organization's do-not-call list or WhatsApp
  block list is refused with `do_not_call`.

Each conversation's events reach your webhook receivers as any conversation's do
([Webhooks](/guides/webhooks)).
