Sign inGet Started

Webhooks de ciclo de vida de mensajes de WhatsApp

Cada paso en el ciclo de vida de un mensaje puede enviarse a tu endpoint en el momento en que ocurre. Cada payload usa la respuesta de evento WhatsApp e incluye los campos que todo evento de mensaje incluye.

Eventos de entrega

whatsapp.accepted, whatsapp.sent, whatsapp.delivered y whatsapp.read solo incluyen los campos que todo evento de mensaje incluye. Eventos de ciclo de vida explica qué significa cada uno y cuándo se omite whatsapp.delivered.
Ejemplo de código
{
  "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 y whatsapp.rejected también incluyen un objeto error con un Bird code estable, un description legible, un meta_error_code opcional y occurred_at. Consulta eventos de fallo para ver qué diferencia a ambos. En un fallo reportado por WhatsApp, description es la explicación propia de WhatsApp. Un mensaje de servicio cuya ventana de atención al cliente se cerró entre la aceptación y el envío falla así:
Ejemplo de código
{
  "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"
}
Marcar un mensaje entrante como leído registra whatsapp.read en la línea de tiempo del mensaje, pero no emite un webhook.

Mensajes entrantes

whatsapp.received incluye el contenido del mensaje junto con los campos que todo evento de mensaje incluye, de modo que un endpoint puede actuar sobre un mensaje entrante sin volver a leerlo. Un toque en un mensaje interactivo llega como interactive_reply, y in_reply_to_message_id indica el mensaje al que responde:
Ejemplo de código
{
  "data": {
    "direction": "inbound",
    "from": {
      "display_name": "Alex Rivera",
      "phone_number": "+14155550100",
      "username": "alexr"
    },
    "in_reply_to_message_id": "wam_01ky7qbvswf3fvyaw3az90391c",
    "interactive_reply": {
      "list": {
        "description": "Next day to 2 days",
        "slug": "priority_express",
        "text": "Priority Mail Express"
      },
      "type": "list"
    },
    "metadata": null,
    "tags": null,
    "to": { "phone_number": "+13124495569" },
    "whatsapp_id": "wam_01ky8b3xq4gd7pmzn2ka51f7te",
    "workspace_id": "ws_01ky7m235keycbnwyajabe1a6b"
  },
  "timestamp": "2026-07-23T14:52:04.118Z",
  "type": "whatsapp.received"
}
Las demás ramas de contenido siguen la misma estructura de uno-de-estos: text, image, video, audio, sticker, document, location, contact_cards y unsupported para un tipo que API no modela. GET /v1/whatsapp/messages/{message_id} documenta cada una.

Próximos pasos