Sign inGet Started

WhatsApp message status webhooks

Each change in an outbound message's status can be pushed to your endpoint as it happens. Every payload uses the WhatsApp event envelope and carries the fields every message event carries.

Delivery events

whatsapp.accepted, whatsapp.sent, whatsapp.delivered, and whatsapp.read carry only the fields every message event carries. Lifecycle events gives what each one means and when whatsapp.delivered is skipped.
Code example
{
  "data": {
    "direction": "outbound",
    "from": { "phone_number": "+13124495569" },
    "metadata": { "session_id": "sess_4821" },
    "tags": [{ "name": "flow", "value": "login-otp" }],
    "to": { "phone_number": "+14155550100" },
    "whatsapp_id": "wam_01ky7qbvswf3fvyaw3az90391c",
    "workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
  },
  "timestamp": "2026-07-23T14:51:39.913Z",
  "type": "whatsapp.delivered"
}
whatsapp.failed and whatsapp.rejected also carry an error object with a stable Bird code, a human-readable description, an optional meta_error_code, and occurred_at. See failure events for what separates the two. On a failure WhatsApp reported, description is WhatsApp's own explanation. A service message whose customer service window closed between accept and dispatch fails like this:
Code example
{
  "data": {
    "direction": "outbound",
    "error": {
      "code": "service_window_expired",
      "description": "Message failed to send because more than 24 hours have passed since the customer last replied to this number.",
      "meta_error_code": "131047",
      "occurred_at": "2026-07-23T14:51:40.201Z"
    },
    "from": { "phone_number": "+13124495569" },
    "metadata": null,
    "tags": null,
    "to": { "phone_number": "+14155550100" },
    "whatsapp_id": "wam_01ky7qbvswf3fvyaw3az90391c",
    "workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
  },
  "timestamp": "2026-07-23T14:51:40.201Z",
  "type": "whatsapp.failed"
}
Marking an inbound message as read records whatsapp.read in the message's timeline but does not emit a webhook.

Next steps