---
title: "Guía de webhooks de WhatsApp: eventos, seguridad y reintentos"
description: "Cómo funcionan los webhooks de WhatsApp: eventos de mensajes y de estado, un gestor fiable, la firma de Meta, reintentos, idempotencia y eventos perdidos."
canonical: "https://omnichannels.ai/es/blog/whatsapp-webhooks-guide/"
language: "es"
updated: "2026-10-16"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
category: "integration"
primaryQuery: "webhook whatsapp"
keywords: ["webhook api whatsapp business", "eventos de estado webhook whatsapp", "x-hub-signature-256 whatsapp", "reintentos de webhook whatsapp", "webhook de estado de entrega whatsapp", "gestor de webhooks idempotente", "webhook de mensajes entrantes whatsapp"]
published: "2026-10-16"
author: "OmniChannels.ai Editorial Team"
reviewer: "BroadNet Messaging Solutions Team"
readingMinutes: 10
answer: "Un webhook de WhatsApp es un endpoint HTTPS en su servidor que recibe eventos: los estados de entrega de los mensajes que usted envió y los mensajes que le envían los clientes. Con OmniChannels.ai, los estados llegan como SUBMITTED, SENT, DELIVERED, READ, FAILED o REJECTED. Guarde el cuerpo sin procesar, responda 2xx con rapidez, deduplique por ID de mensaje y procese de forma asíncrona. Meta firma sus propios webhooks; nuestra documentación no define ninguna cabecera de firma, así que proteja su endpoint a nivel de transporte y de aplicación."
takeaways: ["Los webhooks envían los estados y los mensajes entrantes a su endpoint HTTPS para que no tenga que consultar periódicamente; los estados de WhatsApp se normalizan a SUBMITTED, SENT, DELIVERED, READ, FAILED y REJECTED.", "Un gestor fiable hace tres cosas por este orden: guarda el evento sin procesar, devuelve 2xx y después procesa de forma asíncrona e idempotente.", "Los estados pueden llegar desordenados o dos veces, así que clasifíquelos y no deje nunca que un SENT tardío sobrescriba un DELIVERED guardado.", "Meta firma los webhooks enviados a las apps con una cabecera X-Hub-Signature-256, pero la especificación de la API de OmniChannels.ai no define ninguna firma de webhook, así que use HTTPS, una ruta imposible de adivinar y la validación del cuerpo.", "Si faltaron eventos, lea el estado de WhatsApp por lote en el endpoint bulk-insights en lugar de reenviar mensajes."]
faq: 
  - q: "¿Qué es un webhook de WhatsApp?"
    a: "Un webhook de WhatsApp es una URL de su servidor a la que la plataforma llama con un HTTP POST cada vez que ocurre algo, como que un mensaje se entregue, se lea o falle, o que un cliente le envíe un mensaje. Sustituye a la consulta periódica (polling). Usted expone un endpoint HTTPS, lo comparte con su proveedor y procesa los eventos JSON que recibe."
  - q: "¿Cómo verifico la firma de un webhook de WhatsApp?"
    a: "Para un webhook que Meta envía directamente a su propia app, la documentación de Meta indica calcular un HMAC-SHA256 de la carga sin procesar con el secreto de su app y compararlo con la cabecera X-Hub-Signature-256. Para el webhook de OmniChannels.ai, la especificación de la API no define ninguna cabecera de firma, así que confíe en HTTPS, una ruta imposible de adivinar y la validación del cuerpo."
  - q: "¿Qué ocurre si mi endpoint de webhook está caído?"
    a: "La documentación de Meta dice que reintenta las entregas fallidas con una frecuencia decreciente durante hasta 7 días, lo que puede producir duplicados. Para los eventos de nuestra plataforma, confirme el comportamiento de los reintentos con su ingeniero de alta, y use el endpoint bulk-insights para leer el estado de WhatsApp por destinatario de un lote. Para el SMS, el endpoint resendDlr vuelve a enviar los informes."
  - q: "¿Cómo gestiono los eventos de webhook duplicados?"
    a: "Haga que el procesamiento sea idempotente. Busque el mensaje por su ID, compare el rango del estado entrante con el almacenado e ignore los eventos que no supongan un avance. Aplicar el mismo evento dos veces debe tener el mismo efecto que aplicarlo una. Guarde el cuerpo sin procesar de cada evento para poder reproducirlo tras corregir un error."
  - q: "¿Con qué rapidez debe responder mi endpoint?"
    a: "En pocos segundos. Guarde el evento sin procesar, devuelva un 2xx y haga el trabajo real en una cola o en un proceso de trabajo. No llame a otros servicios, no envíe mensajes ni ejecute consultas pesadas antes de responder. Si falla el almacenamiento, devuelva un 5xx para que el remitente pueda reintentar, en lugar de confirmar un evento que ha perdido."
  - q: "¿Puedo usar un webhook para enviar una respuesta automática?"
    a: "Sí, pero no desde dentro del gestor. Confirme el evento y decida la respuesta en un trabajo aparte. Dentro de la ventana de atención al cliente de 24 horas puede enviar un mensaje de texto libre; fuera de ella necesita una plantilla aprobada. No reenvíe nunca un mensaje desde el propio gestor del webhook, para evitar bucles y duplicados."
sources: 
  - title: "Webhooks overview — WhatsApp Business Platform, Meta for Developers"
    url: "https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/overview"
  - title: "Create a webhook endpoint — WhatsApp Business Platform, Meta for Developers"
    url: "https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/create-webhook-endpoint"
  - title: "RFC 2104: HMAC: Keyed-Hashing for Message Authentication"
    url: "https://www.rfc-editor.org/rfc/rfc2104"
---

# Guía de webhooks de WhatsApp: eventos, seguridad y reintentos

Canonical: https://omnichannels.ai/es/blog/whatsapp-webhooks-guide/
Language: es
Publisher: OmniChannels.ai by BroadNet Technologies

Esta guía está dirigida a los ingenieros que necesitan recibir eventos de WhatsApp de forma fiable: los estados de entrega de los mensajes que envían y los mensajes entrantes de los clientes. Explica cómo funcionan los webhooks, qué construir en el gestor, en qué se diferencia la seguridad entre los webhooks de Meta y los nuestros, y qué hacer cuando faltan eventos.

## ¿Qué son los webhooks de WhatsApp y por qué usarlos?

Los webhooks de WhatsApp son devoluciones de llamada HTTP. Cuando un mensaje cambia de estado o un cliente le escribe, la plataforma envía un `POST` con un cuerpo JSON a su endpoint. No tiene que consultar periódicamente, y ve los eventos a medida que ocurren.

Importan dos familias de eventos:

- **Eventos de estado** de los mensajes que usted envió: en cola, enviado, entregado, leído, fallido.
- **Mensajes entrantes** de los clientes, que abren o prolongan la ventana de atención al cliente de 24 horas. Consulte nuestra [guía de la ventana](/es/blog/whatsapp-24-hour-customer-service-window/).

Una llamada de envío solo le dice que los mensajes se pusieron en cola. El webhook es donde usted se entera de lo que ocurrió con cada destinatario.

## ¿Qué eventos y estados recibiré?

En OmniChannels.ai, todos los canales informan de los mismos estados normalizados, de modo que un único gestor puede dar servicio a WhatsApp, SMS y el resto.

| Estado | Significado | ¿Final? |
|---|---|---|
| `SUBMITTED` | Aceptado por la plataforma y puesto en cola | No |
| `SENT` | Entregado al canal | No |
| `DELIVERED` | Confirmado en el dispositivo del destinatario | Normalmente; puede seguir `READ` |
| `READ` | Abierto por el destinatario, donde el canal informa de las lecturas | Sí |
| `FAILED` | No entregado; el evento incluye un motivo cuando está disponible | Sí |
| `REJECTED` | Rechazado, por ejemplo por contenido bloqueado o por un remitente sin registrar | Sí |

Trate los estados como una progresión que puede llegar desordenada, y espere valores nuevos con el tiempo. No falle ante un estado que no reconozca. Consulte [estados de entrega de mensajes explicados](/es/blog/message-delivery-status-explained/).

## ¿Cómo configuro el endpoint?

Exponga un endpoint HTTPS, facilite la URL a su proveedor y pruebe después con su propio número.

1. Cree un endpoint que acepte `POST` con un cuerpo JSON, por ejemplo `https://api.example.com/webhooks/omnichannels`.
2. Envíe la URL a nuestro equipo o al administrador de su cuenta para configurarla en su cuenta. Los revendedores pueden tener un webhook distinto por subcuenta.
3. Envíe un mensaje de prueba a su propio número y confirme que llegan los eventos.

Durante el desarrollo, un túnel como ngrok da a su servidor local una URL HTTPS pública. Si además conecta una app directamente a Meta, la verificación del endpoint de Meta es un paso aparte: una petición `GET` con un token de verificación y un valor `hub.challenge`, a la que usted responde `200` con el desafío, como se describe en la [documentación del endpoint de webhook](https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/create-webhook-endpoint) de Meta.

## ¿Qué aspecto tiene la carga?

Varía según el canal. La especificación de la API no define un único esquema de webhook, así que registre primero el cuerpo sin procesar y asigne los campos que necesite a partir de eventos reales de su cuenta. El ejemplo muestra el tipo de información que lleva un evento de entrega y es solo ilustrativo.

```json
{
  "messageId": "2603121407537573731",
  "channel": "SMS",
  "destination": "447700900123",
  "status": "DELIVERED",
  "timestamp": "2026-10-10T09:15:42Z",
  "reason": null
}
```

No programe contra estos nombres de campo sin comprobar un evento real. Pida a su ingeniero de alta cargas de ejemplo por canal y consérvelas como datos de prueba. Para consultar la documentación más amplia, vea la [referencia de webhooks](/developers/webhooks/).

## ¿Cómo escribo un gestor fiable?

Haga tres cosas por este orden: guarde el evento sin procesar, confirme con un `2xx` y procese después de forma asíncrona. El gestor siguiente sigue el patrón de nuestra documentación.

```js
import express from "express";

const app = express();

// Capture el cuerpo sin procesar para guardarlo exactamente como se recibió.
app.post(
  "/webhooks/omnichannels",
  express.json({ verify: (req, _res, buf) => { req.rawBody = buf.toString("utf8"); } }),
  async (req, res) => {
    try {
      await db.webhookEvents.insert({ receivedAt: new Date(), body: req.rawBody });
    } catch (err) {
      return res.sendStatus(500); // falló el almacenamiento: deje que se reintente el evento
    }
    res.sendStatus(200);          // confirme rápido
    queue.publish("status-events", req.body); // haga el trabajo real en otro lugar
  },
);

// Worker: procesamiento idempotente
async function processEvent(event) {
  const id = event.messageId ?? event.message_id ?? event.id; // asigne según el canal
  const status = event.status;
  const rank = { SUBMITTED: 1, SENT: 2, DELIVERED: 3, READ: 4, FAILED: 4, REJECTED: 4 };

  const current = await db.messages.findOne({ providerId: id });
  if (!current) return; // mensaje desconocido: regístrelo e investigue
  if ((rank[status] ?? 0) <= (rank[current.status] ?? 0)) return; // duplicado u obsoleto

  await db.messages.update({ providerId: id }, { status, updatedAt: new Date() });
}
```

```python
from datetime import datetime, timezone
from flask import Flask, request

app = Flask(__name__)

RANK = {"SUBMITTED": 1, "SENT": 2, "DELIVERED": 3, "READ": 4, "FAILED": 4, "REJECTED": 4}


@app.post("/webhooks/omnichannels")
def omnichannels_webhook():
    raw = request.get_data(as_text=True)
    try:
        db.webhook_events.insert({"received_at": datetime.now(timezone.utc), "body": raw})
    except Exception:
        return "", 500           # falló el almacenamiento: deje que se reintente el evento
    queue.publish("status-events", raw)  # procese de forma asíncrona
    return "", 200               # confirme rápido
```

Los objetos `db` y `queue` son su propio almacenamiento y su propia cola de trabajos. El mapa `rank` es lo que hace idempotente el procesamiento: un evento duplicado u obsoleto no supone un avance, por lo que se ignora.

### Reglas para un gestor fiable

- **Responda en pocos segundos.** No haga trabajo pesado antes de responder.
- **Devuelva `2xx` solo después de guardar el evento.** Si falla el almacenamiento, devuelva `5xx`.
- **Deduplique por ID de mensaje.** El mismo estado puede llegar más de una vez.
- **No reenvíe nunca un mensaje desde el gestor.** Decida los reintentos en un trabajo aparte, tras comprobar el estado.
- **Conserve el cuerpo sin procesar** para diagnosticar problemas y para reproducir eventos tras una corrección.

## ¿Cómo protejo un webhook de WhatsApp?

Depende de quién envíe a su endpoint. Meta firma los webhooks que envía a las apps que usted registra en Meta. La especificación de la API de OmniChannels.ai no define ninguna cabecera de firma de webhook, así que no espere a que exista.

| | Meta a su propia app | OmniChannels.ai a su endpoint |
|---|---|---|
| Firma | Cabecera `X-Hub-Signature-256`, según la documentación de Meta | Ninguna definida en la especificación de la API |
| Verificación | HMAC-SHA256 de la carga sin procesar con el secreto de su app, comparado con la cabecera | No procede |
| Sus controles | Compruebe la firma en cada `POST` | HTTPS con un certificado válido, una ruta imposible de adivinar, validación estricta del cuerpo |

Para el esquema de Meta, la documentación de Meta indica generar un hash HMAC-SHA256 a partir de la carga JSON con el secreto de su app y compararlo con el valor posterior a `sha256=` de la cabecera `X-Hub-Signature-256`. El propio HMAC está definido en la RFC 2104. Calcúlelo sobre los bytes sin procesar, no sobre un objeto reserializado, y compare en tiempo constante.

Para nuestro endpoint:

- Use solo HTTPS, con un certificado válido.
- Use una ruta larga e imposible de adivinar, y rótela si se filtra.
- Valide la forma del cuerpo y rechace todo lo inesperado.
- Trate los eventos como notificaciones. Antes de una acción irreversible, como un reembolso o un bloqueo por fraude, confirme el estado con una llamada de consulta.

## ¿Qué ocurre cuando falla la entrega?

Los reintentos dependen del remitente. La documentación de Meta dice que reintenta una entrega fallida con una frecuencia decreciente durante hasta 7 días, lo que puede producir notificaciones duplicadas. Es un motivo para ser idempotente aunque rara vez vea duplicados. Para los eventos de nuestra plataforma, confirme el comportamiento de los reintentos con su ingeniero de alta en lugar de suponer que coincide con el de Meta.

En cualquier caso, construya pensando tanto en la pérdida como en la duplicación: su endpoint puede estar caído durante un despliegue, y una regla de cortafuegos puede descartar peticiones en silencio.

## ¿Cómo recupero los eventos que faltan?

Consulte el lote, no reenvíe el mensaje.

| Necesidad | Llamada | Notas |
|---|---|---|
| Leer el estado de WhatsApp por destinatario | `GET /whatsapp/message/bulk-insights` | Filtre un lote por `status` o `destination`; paginado con `page` y `size` |
| Reenviar los informes de entrega de SMS | `POST /sms/resendDlr` | Filtre por `startDate`, `endDate`, `senderId` y `messageStatus` |

```bash
curl "https://api.broadnet.me/whatsapp/message/bulk-insights?batch_Id=2609091405000000001&page=0&size=100" \
  -H "Authorization: Bearer $BROADNET_TOKEN"
```

`batch_Id` es el ID devuelto por la llamada de envío, y `page` empieza en cero. Ejecute una conciliación nocturna que lea los lotes del día anterior y rellene las lagunas.

### Lista de verificación para solucionar problemas

1. ¿Está configurada la URL en la cuenta o subcuenta correcta?
2. ¿Se puede acceder al endpoint por HTTPS con un certificado válido?
3. ¿Responde con `2xx` con rapidez, o agota el tiempo de espera?
4. ¿Está una regla de cortafuegos o de WAF bloqueando las peticiones?
5. ¿Registra el cuerpo sin procesar antes de analizarlo, para que un error del analizador no pueda ocultar el evento?

## Ejemplo práctico: el flujo de notificaciones de un comercio

"Souq Rafiq" (ficticia), un comercio de los Emiratos Árabes Unidos, envía actualizaciones de pedidos por WhatsApp y quiere un estado exacto en su herramienta de pedidos.

1. Los pedidos se envían con `sendbulk`, y el `batchId` se guarda en el pedido. Consulte [enviar un mensaje de WhatsApp por API](/es/blog/send-whatsapp-message-api-examples/).
2. El endpoint del webhook escribe cada evento en una tabla y después devuelve `200`.
3. Un proceso de trabajo clasifica los estados y actualiza el estado del mensaje del pedido.
4. Los eventos `FAILED` crean una tarea para soporte con el motivo, y se valora un respaldo por SMS según el [respaldo entre canales](/es/blog/channel-fallback-strategy/).
5. Los mensajes entrantes de los clientes se derivan a la bandeja compartida para que los agentes puedan responder dentro de la ventana.
6. Un proceso nocturno llama a `bulk-insights` para los lotes del día anterior y corrige lo que se haya perdido.

## ¿Cuáles son los errores habituales?

- **Trabajo pesado antes de responder,** que provoca tiempos de espera agotados y entregas repetidas.
- **Confirmar antes de guardar,** que pierde eventos cuando falla el almacenamiento.
- **Fiarse del orden.** Un `SENT` tardío que sobrescribe un `DELIVERED`.
- **Programar contra la carga ilustrativa** en lugar de contra eventos reales.
- **Reserializar el JSON antes de comprobar una firma,** lo que cambia los bytes.
- **Reenviar desde el gestor,** lo que puede crear un bucle.
- **Límites:** esta guía describe nuestro comportamiento documentado. La política de reintentos y los campos de la carga de su cuenta deben confirmarse durante el alta.

## Cómo le ayuda OmniChannels.ai

OmniChannels.ai envía a su webhook, en un único formato normalizado, los estados de entrega y los mensajes entrantes de WhatsApp, SMS, RCS y otros canales, con webhooks distintos por subcuenta para los revendedores. BroadNet es un Meta Business Solution Provider oficial, por lo que los requisitos de webhook de la propia Meta se gestionan por usted, y usted trabaja con nuestra API. Lea la [referencia de webhooks](/developers/webhooks/) y la [documentación de la API de WhatsApp](/developers/whatsapp/), o vea cómo aparecen los eventos en la [bandeja compartida](/es/platform/unified-inbox/).
