# Webhook

En esta sección se describe cómo funciona la recepción de mensajes y eventos a través del webhook. Cuando tienes un webhook registrado, B2Chat envía automáticamente notificaciones a la URL configurada en tu servidor cada vez que ocurren eventos relevantes — como un mensaje entrante de un cliente.

Estas notificaciones se envían mediante una solicitud `HTTP POST` directamente a tu endpoint. El cuerpo de la solicitud contiene información sobre el tipo de evento y el contenido del mensaje. Es tu responsabilidad procesar ese payload y responder con un `HTTP 200` para confirmar que lo recibiste correctamente.

{% hint style="info" %}
La URL del webhook es la de **tu servidor**, no la de B2Chat. B2Chat actúa como el emisor de las notificaciones — tú eres quien las recibe. Asegúrate de que tu URL sea pública y accesible desde internet
{% endhint %}

#### ¿Cómo configurar tu webhook?

Para recibir eventos, debes tener lista una URL pública en tu servidor y registrarla en B2Chat a través del una solicitud al correo **<support@b2chat.io>** <i class="fa-mailbox-open-letter">:mailbox-open-letter:</i>

#### ¿Cómo funciona tu webhook?

B2Chat envía un HTTP POST a la URL de webhook configurada cada vez que ocurre un evento entrante de WhatsApp (mensajes, actualizaciones de estado, etc.).

**Firma de solicitudes (HMAC-SHA256)**

Cuando tienes configurado el secret, cada solicitud de webhook saliente incluye los siguientes headers de firma para que tu servidor pueda verificar la autenticidad del payload:

* `X-Hub-Signature-256`: Firma HMAC-SHA256 del cuerpo crudo de la solicitud, compatible con Meta, con prefijo `sha256=`. Verifícala de la misma forma que verificarías una firma de webhook de Meta.
* `X-Signature`: Firma HMAC-SHA256 adicional de `timestamp + "." + raw body`, codificada en hex. Úsala junto con `X-Webhook-Timestamp` para verificación resistente a replay.
* `X-Webhook-Timestamp`: Timestamp Unix (en segundos) del momento en que se envió la solicitud. Rechaza solicitudes cuyo timestamp difiera más de 5 minutos del tiempo de tu servidor para prevenir ataques de replay.

La firma es **totalmente compatible hacia atrás** — las solicitudes se envían sin firmar hasta que optas por activarla configurando un secret con el equipo de soporte de B2Chat

#### Estructura general del payload

Todos los eventos comparten la misma estructura raíz:

## POST /webhook

>

```json
{"openapi":"3.0.3","info":{"title":"B2Chat WhatsApp Cloud API","version":"0.0.1"},"tags":[{"name":"Webhook","description":"Receive incoming WhatsApp messages and events"}],"servers":[{"url":"https://{your-domain}","description":"URL del servidor del cliente. B2Chat enviará un HTTP POST a esta URL cada vez que ocurra un evento o mensaje entrante de WhatsApp. Debes reemplazar {your-domain} por el dominio de tu servidor.\n"}],"security":[],"paths":{"/webhook":{"post":{"tags":["Webhook"],"operationId":"receiveWebhook","parameters":[{"in":"header","name":"X-Hub-Signature-256","required":false,"schema":{"type":"string"},"description":"Firma HMAC-SHA256 del cuerpo crudo de la solicitud, compatible con Meta. Formato: `sha256=<hex_digest>`. Solo está presente cuando se configura el secret.\n"},{"in":"header","name":"X-Signature","required":false,"schema":{"type":"string"},"description":"Firma HMAC-SHA256 de `X-Webhook-Timestamp + \".\" + raw_body` codificada en hex. Úsala junto con X-Webhook-Timestamp para verificación resistente a ataques de replay. Solo está presente cuando se configura el secret.\n"},{"in":"header","name":"X-Webhook-Timestamp","required":false,"schema":{"type":"string"},"description":"Timestamp Unix (en segundos) del momento en que B2Chat despachó la solicitud. Rechaza solicitudes cuyo timestamp difiera más de 300 segundos (5 minutos) del tiempo de tu servidor para prevenir ataques de replay. Solo está presente cuando se configura el secret.\n"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookPayload"}}}},"responses":{"200":{"description":"Webhook received and processed successfully"},"401":{"description":"Signature verification failed"}}}}},"components":{"schemas":{"WebhookPayload":{"type":"object","properties":{"object":{"type":"string"},"entry":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"changes":{"type":"array","items":{"type":"object","properties":{"value":{"type":"object","properties":{"messaging_product":{"type":"string"},"metadata":{"type":"object","properties":{"display_phone_number":{"type":"string"},"phone_number_id":{"type":"string"}}},"contacts":{"type":"array","items":{"type":"object","properties":{"profile":{"type":"object","properties":{"name":{"type":"string"}}},"wa_id":{"type":"string"}}}},"messages":{"type":"array","items":{"$ref":"#/components/schemas/IncomingMessage"}}}},"field":{"type":"string"}}}}}}}}},"IncomingMessage":{"type":"object","properties":{"from":{"type":"string"},"id":{"type":"string"},"timestamp":{"type":"string"},"type":{"type":"string","enum":["text","image","audio","video","document","location","contacts","sticker","button","interactive"]},"text":{"type":"object","properties":{"body":{"type":"string"}}},"image":{"type":"object","properties":{"mime_type":{"type":"string"},"sha256":{"type":"string"},"id":{"type":"string"},"caption":{"type":"string"}}},"audio":{"type":"object","properties":{"mime_type":{"type":"string"},"sha256":{"type":"string"},"id":{"type":"string"},"voice":{"type":"boolean"}}},"location":{"type":"object","properties":{"address":{"type":"string"},"latitude":{"type":"number"},"longitude":{"type":"number"},"name":{"type":"string"},"url":{"type":"string"}}}}}}}}
```

#### Tipos de mensajes entrantes

El campo `type` dentro de `messages[]` indica qué tipo de contenido envió el cliente. A continuación se describen los más comunes.

{% tabs %}
{% tab title="Mensaje de texto" %}

```json
{
    "from": "573117249185",
    "id": "wamid.HBgMNTczMTE3MjQ5MTg1FQIAEhggQ0QxODk4NkYzMTRBQjhCRUM1RjVDRDFENjc1NTAyMzAA",
    "timestamp": "1681779631",
    "type": "text",
    "text": {
        "body": "Hola, necesito información sobre sus servicios"
    }
}
```

{% endtab %}

{% tab title="Mensaje de audio" %}

```json
{
    "from": "573117249185",
    "id": "wamid.HBgMNTczMTE3MjQ5MTg1FQIAEhggNkEwN0YwQTZFNTBGN0MxMTg0RUY4QzNERUE4MzE3QTAA",
    "timestamp": "1681780519",
    "type": "audio",
    "audio": {
        "mime_type": "audio/ogg; codecs=opus",
        "sha256": "6Y7WQBAbHOgvGhp1fQt4jLOJ2kBJAv3JhoIhjWicpzU=",
        "id": "239060685298489",
        "voice": true
    }
}
```

{% endtab %}

{% tab title="Mensaje de ubicación" %}

```json
{
    "from": "573117249185",
    "id": "wamid.HBgMNTczMTE3MjQ5MTg1FQIAEhggMjU1MjgwOUYwM0Q2QTc0QkUyMENCRTY0RUI3QjBBNzYA",
    "timestamp": "1681780601",
    "type": "location",
    "location": {
        "address": "Carrera 52 # 8b Sur 72, Medellín, Antioquia",
        "latitude": 6.2009706162562,
        "longitude": -75.588375451565,
        "name": "Degres Guayabal",
        "url": "https://foursquare.com/v/4ef4a035e5fa4c3505db90ec"
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
*ID del archivo subido. Úsalo en el campo `image.id`, `audio.id`, `document.id`, etc., al enviar un mensaje*
{% endhint %}

#### :white\_check\_mark: Buenas prácticas

* Se recomienda que tu endpoint sea `HTTPS`
* Tu endpoint debe responder con un **HTTP 200** en menos de **5 segundos**. Si demora más, B2Chat intentará reenviar el evento.
* Procesa los mensajes de forma **asíncrona** — recibe el evento, guárdalo en una cola, y luego procésalo. Esto evita timeouts.
* Valida siempre el campo `type` antes de acceder a los campos específicos del contenido, ya que su estructura varía según el tipo de mensaje.
* Guarda el campo `id` del mensaje para **evitar procesar duplicados** en caso de reenvíos.
* Para descargar archivos multimedia recibidos (imágenes, audios, documentos), usa el `id` del objeto multimedia y consulta la sección 🖼️ Media.

{% hint style="warning" %}
Si tu servidor no responde con `HTTP 200` dentro del tiempo límite, B2Chat reintentará entregar el evento. Asegúrate de implementar un mecanismo de duplicación usando el campo `id` del mensaje para evitar procesarlo más de una vez.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://b2chat.gitbook.io/b2chat-api-mensajeria-whatsapp/nuestros-servicios/webhook.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
