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

# Events

> What a WhatsApp conversation sends you, and when.

Delivered on the endpoint you registered in
[Webhooks](/reseller/webhooks), which is also where signature verification,
the envelope and retry behaviour are described. This page is only *which*
events WhatsApp produces.

| Event                                            | Fires when                                                                               |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| `conversation.created`                           | a thread is opened — **including when no assistant will answer it**                      |
| `message.received`                               | a customer's message is accepted — **including media**, before transcription finishes    |
| `message.sent`                                   | an outbound message is accepted by Meta — AI, the merchant's staff, or your own API call |
| `message.delivered`                              | it reached the recipient's device                                                        |
| `message.read`                                   | the recipient opened it                                                                  |
| `message.failed`                                 | Meta could not deliver it. Carries their code and title                                  |
| `message.deleted`                                | the sender revoked a message. Carries the revoked id                                     |
| `handoff.requested`                              | the assistant stopped and a person is needed. Time-sensitive                             |
| `template.status_changed`                        | a template was approved, rejected or paused                                              |
| `conversation.completed`                         | a thread reached a terminal state                                                        |
| `lead.hot` <sup>preview</sup>                    | a message showed buying intent                                                           |
| `lead.verification_requested` <sup>preview</sup> | a lead asked to be verified                                                              |

`GET /api/v2/webhooks/catalogue/` returns the live list, including the resource
each event carries and the scope it needs. Your code probably wants that rather
than this table.

<Note>
  `message.received` fires for media **before** the voice note is transcribed, so
  `channel.media.transcription` may be empty on arrival. Render the message
  immediately rather than waiting — a customer's voice note appearing thirty
  seconds late looks like a broken inbox. Fetch the file with
  [`GET /media/{ref}/`](/reseller/channels/whatsapp/conversations#media).
</Note>

## Delivery status

The ticks you draw beside a message, and the per-recipient outcome a broadcast
report is built from.

```json theme={null}
{
  "type": "message.delivered",
  "tenant_ref": "merchant_8812",
  "data": { "object": {
    "object": "message_status",
    "channel": { "name": "whatsapp", "message_id": "wamid.HBg…" },
    "conversation": "…",
    "status": "delivered",
    "recipient": "919876543210",
    "at": "2026-09-07T10:12:04Z",
    "pricing": { "billable": true, "category": "marketing", "model": "PMP" }
  } }
}
```

`pricing.category` is what a broadcast cost estimate multiplies, and this is the
only place it is available.

A failure carries Meta's own diagnosis rather than ours:

```json theme={null}
"error": { "code": "131047", "title": "Re-engagement message",
           "detail": "More than 24 hours have passed…" }
```

<Warning>
  **`sent` is not re-emitted as a status.** `message.sent` already fired when we
  handed the message to Meta. Emitting the same fact twice under two names is how
  a delivery report ends up counting every message once too often.

  The states you receive are `delivered`, `read` and `failed` — and they can
  arrive out of order, or not at all. A customer with read receipts disabled
  never produces `message.read`, which is not a failure and not something to wait
  for.
</Warning>

## Template approval

Approval takes hours, so it arrives long after the `POST` that created the
template.

```json theme={null}
{
  "type": "template.status_changed",
  "data": { "object": {
    "object": "template",
    "name": "order_update",
    "language": "en_US",
    "status": "REJECTED",
    "category": "MARKETING",
    "rejected_reason": "INVALID_FORMAT"
  } }
}
```

Meta sends this against the WhatsApp Business Account rather than a phone
number, so it arrives for the merchant that owns the WABA. See
[Templates](/reseller/channels/whatsapp/templates).
