
# Webhooks

Los webhooks permiten que <span data-t="appName">Your AI Connector</span> notifique automáticamente a sus otras herramientas empresariales siempre que ocurra algo importante: la creación de un nuevo contacto, la reserva de una cita o la recepción de un mensaje. En lugar de comprobar manualmente si hay actualizaciones, sus sistemas conectados reciben una notificación instantánea en el momento en que sucede algo.


---

## ¿Qué son los webhooks?

Piense en un webhook como un mensaje de texto automático entre dos aplicaciones. Cuando ocurre algo en <span data-t="appName">Your AI Connector</span> (como el registro de un nuevo contacto), la plataforma envía instantáneamente una notificación a otro sistema de su elección. Usted proporciona una dirección web (llamada "URL de webhook") a la que deben enviarse estas notificaciones; normalmente, esta la proporciona su CRM, plataforma de automatización o desarrollador.

> **Los webhooks solo envían datos FUERA de <span data-t="appName">Your AI Connector</span>.** Un webhook es una vía de sentido único *desde* <span data-t="appName">Your AI Connector</span> *hacia* sus otras herramientas. **No existe una URL de webhook que envíe clientes potenciales, contactos o mensajes HACIA la plataforma.** Para introducir un nuevo cliente potencial (desde un formulario web, su CRM o GoHighLevel), su sistema realiza una **llamada a la API** en su lugar. Consulte [Acceso a la API](api-access.md) (la operación *Crear un contacto*) y [Embudos](funnels.md). Lo único que necesita para la dirección de entrada es su **clave de API**, que se encuentra en su propia sección; consulte [Acceso a la API](api-access.md#generating-your-api-key). La página de **Webhooks** descrita aquí es exclusivamente para la dirección de salida.

::: note
**Nota:** La configuración de webhooks implica cierta configuración técnica. Si no se siente cómodo con esto, comparta esta página con su desarrollador o utilice una plataforma de automatización como Zapier, Make o Pabbly, que proporcionan URL de webhook sin necesidad de programación.
:::


Los usos comunes incluyen:

- Sincronizar nuevos contactos con su CRM.
- Activar un flujo de trabajo en Zapier, Make o Pabbly cuando se aplica una etiqueta.
- Notificar a su equipo en Slack cuando se alerta a un humano.
- Actualizar su sistema de calendario cuando se reserva una cita.
- Registrar resúmenes de conversaciones en su base de datos.

---

## Configuración de webhooks

1. En la barra lateral izquierda, haga clic en **Configuración** (icono de engranaje).
2. En la barra lateral de Configuración, bajo el grupo **Integraciones**, haga clic en **Webhooks**.


En una cuenta sin webhooks configurados todavía, la página se ve así:


3. Haz clic en **New webhook**, en la parte superior derecha. Se abrirá un formulario en la misma página:


4. Rellene:
   - **URL del endpoint**: la dirección web a la que <span data-t="appName">Your AI Connector</span> enviará las notificaciones de eventos. La obtendrá de su sistema externo (CRM, plataforma de automatización o servidor personalizado).
   - **Nombre**: una etiqueta que reconocerá más adelante (p. ej., "Alertas de Slack" o "Sincronización con CRM"). Solo para su referencia.

> **Su URL de webhook debe ser una dirección `https://` alcanzable públicamente.** Las direcciones `http://` simples, `localhost` o las direcciones de red privada y las direcciones internas de la plataforma se rechazan al guardar. Para realizar pruebas desde su propia máquina, utilice un túnel público (webhook.site o ngrok) en lugar de localhost.

5. En **Eventos**, haga clic en los eventos que desea que reciba este webhook; los 22 se enumeran en [Los 22 eventos de webhook](#the-22-webhook-events).
6. *(Opcional)* Active **Reintentar entregas fallidas** si desea que <span data-t="appName">Your AI Connector</span> siga intentándolo ante un fallo temporal; consulte [Reintento de entregas fallidas](#retrying-failed-deliveries).
7. Haga clic en **Crear webhook**. Aparecerá en la lista debajo del formulario, y puede hacer clic en **Probar** en su fila en cualquier momento para enviar una carga útil de muestra a su endpoint.

> **Permiso necesario.** Agregar, editar o probar webhooks requiere el permiso de "edición" de Integraciones (los miembros del equipo con acceso de solo lectura verán un aviso de solo lectura en lugar del formulario).

> **Firmar un webhook** requiere que ya esté guardado primero; abra la fila de un webhook existente para editarlo y el panel **Secreto de firma** aparecerá en la parte inferior del formulario de edición. Un borrador nuevo y sin guardar aún no tiene opción de firma; consulte [Cargas útiles firmadas](#signed-payloads-verifying-a-webhook-really-came-from-us) a continuación.

---

## Un webhook para todas sus cuentas de cliente (Agencias)

Si usted dirige una agencia, no tiene que volver a crear el mismo webhook en cada cuenta de cliente. En la cuenta de agencia, el formulario de webhook tiene un interruptor adicional: **Disparar también para todas las cuentas de cliente**. Actívelo y este webhook también recibirá los eventos que ocurran en todas las cuentas de cliente bajo su agencia: un solo endpoint, toda la agencia.

Cómo funciona:

- **El bloque `user` le indica a qué cliente pertenece un evento.** Cada notificación ya incluye un bloque `user` que identifica la cuenta en la que ocurrió el evento, por lo que su automatización puede realizar el enrutamiento por cliente.
- **La configuración de su webhook se aplica en todas partes.** Los eventos que seleccionó, el secreto de firma y la configuración de reintento también se utilizan para las entregas de las cuentas de cliente.
- **Sin entregas duplicadas.** Si una cuenta de cliente tiene su propio webhook apuntando a la misma URL, ese se utilizará para los eventos de dicha cuenta en su lugar; el mismo evento nunca llega dos veces al mismo endpoint.
- **Los clientes no lo ven.** El webhook no aparece en la página de Webhooks de la cuenta del cliente y los clientes no pueden desactivarlo; es usted quien lo gestiona.
- **La fiabilidad se rastrea por cuenta de cliente.** Si su endpoint sigue fallando, se desactivará automáticamente para la cuenta cuyas entregas fallaron (consulte [Fiabilidad de Webhooks](#webhook-reliability)), no para toda la agencia a la vez.

El interruptor solo aparece en cuentas de agencia. También se admite su configuración a través de la API; consulte el campo `apply_to_sub_accounts` en la [API de Webhooks](../api/webhooks.md#one-subscription-for-all-client-accounts-agencies).

---

## Eventos de activación disponibles

Puede habilitar o deshabilitar cada uno de los 22 eventos de webhook de forma independiente. Cuando se activa un evento, <span data-t="appName">Your AI Connector</span> envía una notificación a su URL de webhook con los datos relevantes. Cada evento, su significado y el código `event` que incluye en la carga útil se enumeran juntos en [Los 22 eventos de webhook](#the-22-webhook-events) más adelante en esta página.

> **Es bueno saberlo:** **Tarea creada**, **Tarea actualizada** y **Tarea completada** son totalmente seleccionables y se guardan correctamente. **Resumen diario creado** también es una incorporación reciente. Consulta [Webhook de tarea completada](#task-completed-webhook) más abajo para ver la estructura de esa carga útil.

---

## Activadores de webhook basados en etiquetas

`subscribed_to_tags` no limita los eventos de un webhook a una etiqueta. Solo restringe qué etiquetas generan una notificación de resumen de conversación. Para recibir una solicitud cuando se aplica una etiqueta específica, configura una URL de webhook en esa etiqueta en la pestaña **Etiquetas** del agente (o campaña).

El formulario de webhook en sí no tiene un selector de etiquetas, ni al crear un nuevo webhook ni al editar uno, por lo que `subscribed_to_tags` solo se puede leer o cambiar a través de la [API de Webhooks](../api/webhooks.md) o solicitándolo al equipo de soporte.

> **Es bueno saberlo:** editar un webhook existente que tiene una lista `subscribed_to_tags` (cambiarle el nombre, cambiar sus eventos, activar/desactivar reintentos) ya no borra esa lista; dado que el formulario no tiene un selector de etiquetas para enviar de vuelta, guardar desde esta página ahora deja la lista existente intacta. (Esto era un error real antes del **21 de julio de 2026**: guardar desde el formulario de webhook solía borrar la lista porque siempre enviaba una lista de etiquetas vacía. Si un webhook perdió su lista `subscribed_to_tags` antes de esa fecha, deberá reconfigurarse a través de la API).

### Generar resumen para contactos etiquetados

Cuando un webhook tiene una lista `subscribed_to_tags`, puedes activar **Generar resumen**. Cuando está habilitado, <span data-t="appName">Your AI Connector</span> genera automáticamente un resumen de la conversación para el contacto cuando se aplica una de esas etiquetas y lo incluye en los datos del webhook: contexto completo sin necesidad de una solicitud separada.

---

## Prueba de su webhook

1. Abra **Configuración → Integraciones → Webhooks**.
2. En la fila de su webhook, haga clic en **Probar**.
3. Verifique su sistema externo para confirmar que recibió los datos de prueba.
4. Revise el formato de los datos para asegurarse de que su sistema pueda analizarlos correctamente.

Para una prueba completa de extremo a extremo, envíe un mensaje que active uno de sus eventos configurados (una difusión o un mensaje entrante en un canal conectado) y verifique que el webhook se active con los datos reales.

::: tip
**Consejo:** Utilice una herramienta como [webhook.site](https://webhook.site) o [RequestBin](https://requestbin.com) durante el desarrollo para inspeccionar los datos brutos del webhook antes de conectar su sistema de producción.
:::


### Qué se considera una entrega exitosa

Tanto si haces clic en **Test** como si el evento se dispara de forma real, enviamos lo mismo:

- Una solicitud **POST** (nunca GET), con el cuerpo en formato JSON y `Content-Type: application/json`.
- Los encabezados enumerados en [Cargas útiles firmadas](#signed-payloads-verifying-a-webhook-really-came-from-us). Los encabezados de firma solo se incluyen una vez que hayas configurado un secreto de firma.

Consideramos que la entrega es exitosa cuando:

- Tu endpoint responde con **cualquier estado 2xx** (200, 201, 204: todos son válidos).
- Responde **en un plazo de 30 segundos**.

Algunas cosas que sorprenden a los usuarios:

- **El cuerpo de la respuesta se ignora.** No es necesario que devuelva ningún JSON en particular. Un 200 vacío es suficiente.
- **Las redirecciones cuentan como un error.** No las seguimos, por lo que un 301 o 302 (incluida una redirección de barra diagonal final, o de http a https) se registra como una entrega fallida. Guarde la URL final, no una que redirija.
- **Las cadenas de consulta son totalmente compatibles.** `https://your-app.com/hook?token=abc123` se envía exactamente como la guardó, por lo que incluir un token en la cadena de consulta funciona igual de bien que ponerlo en la ruta.
- **Su URL debe ser `https://` y estar disponible públicamente.** Las direcciones que pertenecen a la propia infraestructura de <span data-t="appName">Your AI Connector</span> son rechazadas, pero sus propios puntos de conexión en Google Cloud Functions, Cloud Run, App Engine, Firebase Hosting o cualquier otro lugar están bien.
- **Un firewall o una capa de protección contra bots frente a su punto de conexión puede bloquearnos.** El caso más común es Cloudflare: si su zona tiene activado el modo Bot Fight o un desafío gestionado, nuestra solicitud recibe una página de desafío "Just a moment..." con un 403 en lugar de llegar a su servidor; y una solicitud de servidor a servidor nunca puede superar un desafío de navegador, por lo que tanto el botón **Probar** como los eventos reales fallan de la misma manera. El botón Probar le indicará cuándo sucede esto ("Cloudflare está mostrando un desafío de bot a nuestra solicitud"). Soluciónelo en Cloudflare con una regla de Seguridad / WAF que omita los desafíos para su ruta de webhook (o para el agente de usuario `Webhook-Delivery/1.0`), luego haga clic en **Probar** nuevamente.
- **Si su firewall necesita una lista de permitidos de IP en su lugar** (por ejemplo, el plan gratuito de Cloudflare, donde el modo Bot Fight simple no se puede omitir mediante una regla WAF, pero una regla de acceso IP configurada en Permitir se ejecuta antes), podemos ayudarle: cada entrega, ya sea desde el botón **Probar** o un evento en vivo, se envía desde una dirección IPv4 fija (sin rangos, sin IPv6, sin rotación). Comuníquese con el soporte y le daremos la dirección para incluir en la lista de permitidos. Mantenga la [verificación de firma](#signed-payloads-verifying-a-webhook-really-came-from-us) como su comprobación de confianza real, ya que valida cada carga útil independientemente de dónde provenga.
- **El resultado de la prueba le indica exactamente lo que respondió su punto de conexión.** Una prueba fallida ahora muestra la razón real (el estado HTTP que devolvió su punto de conexión, un tiempo de espera o que no pudimos llegar a la dirección en absoluto) en lugar de un error genérico, y una prueba en un webhook guardado se envía firmada cuando la firma está activada, exactamente igual que un evento en vivo.

### Uso de n8n, Make o Zapier ("URL de prueba" vs "URL de producción")

Las plataformas de automatización suelen ofrecerte dos direcciones de webhook diferentes, y esto suele confundir a los usuarios:

- Una **URL de prueba** (en n8n contiene `/webhook-test/`). Esta solo recibe datos mientras observa activamente el lienzo y acaba de hacer clic en **Escuchar evento de prueba** (o **Probar flujo de trabajo**). Captura un solo evento y luego deja de escuchar, por lo que hacer clic en **Probar** en <span data-t="appName">Your AI Connector</span> varias veces seguidas solo captura el primero, y solo si la ventana de escucha está activa en ese preciso momento. Para probar: primero haga clic en **Escuchar evento de prueba** en n8n, luego regrese a <span data-t="appName">Your AI Connector</span> y haga clic en **Probar** una vez.
- Una **URL de producción** (en n8n contiene `/webhook/`, sin `-test`). Esta es la que debe pegar en <span data-t="appName">Your AI Connector</span> para eventos en vivo. Solo funciona una vez que su flujo de trabajo se cambia a **Activo**. Si el flujo de trabajo no está activo, n8n rechaza la solicitud con un error "404 / webhook no registrado", aunque <span data-t="appName">Your AI Connector</span> haya enviado los datos correctamente.

En resumen: prueba con la URL de prueba mientras escuchas, pero para que el webhook siga funcionando con contactos reales, guarda la **URL de producción** en <span data-t="appName">Your AI Connector</span> y asegúrate de que el flujo de trabajo esté **Active**.

---

## Formato de datos del webhook

Cuando se dispara un webhook, <span data-t="appName">Your AI Connector</span> envía datos estructurados (JSON) a su URL de webhook. Si utiliza una plataforma de automatización como Zapier o Make, esta analiza los datos automáticamente por usted. Si está creando una integración personalizada:

```json
{
  "event": "contactCreated",
  "contact": { "id": "<contact-id>", "first_name": "Jane", "...": "..." },
  "campaign": { "id": "<campaign-id>", "name": "AI Receptionist", "status": "Live" },
  "agent": { "id": "<agent-id>", "name": "Front Desk" },
  "user": { "id": "<account-id>", "email": "owner@example.com" }
}
```

| Campo | Descripción |
|---|---|
| `event` | La cadena de evento exacta que activó la notificación (por ejemplo, `contactCreated`, `booked`). Esta **no** es la etiqueta de visualización que se muestra en la lista de eventos; cada etiqueta y su código correspondiente se encuentran en [Los 22 eventos de webhook](#the-22-webhook-events). |
| `contact` | El contacto al que se refiere el evento, o `null` para eventos que no están vinculados a un contacto (como `creditsRecharged`). |
| `campaign` | La campaña a la que pertenece el contacto, o `null` si no hay ninguna. |
| `agent` | El agente que gestiona la conversación, o `null` si no hay ninguno. |
| `user` | Información básica de identidad de la cuenta propietaria de los datos. |

> **`campaign` o `agent`: normalmente uno, no ambos.** Si su cuenta utiliza agentes, sus contactos se asignan a un agente en lugar de a una campaña, por lo que `campaign` llega como `null` y `agent` le indica cuál lo gestionó. Las cuentas antiguas basadas en campañas ven lo contrario. Lea el campo que esté relleno; no asuma que `campaign` siempre está presente.

> **El bloque `agent` llegó el 15 de agosto de 2026.** Se sitúa junto a `campaign` en los eventos vinculados a una conversación (un chat finalizado, no molestar, una reanudación, una desarchivación, una pausa de IA, un mensaje nuevo, un resumen de conversación y el webhook que puedes configurar en una etiqueta) y contiene el `id` y `name` del agente encargado, o `null` cuando no hay ningún agente involucrado. Es puramente aditivo: todos los campos que ya recibes permanecen sin cambios, por lo que cualquier receptor que hayas creado antes de esa fecha seguirá funcionando sin necesidad de actualizaciones.

Algunos eventos añaden su propio bloque adicional de nivel superior. Por ejemplo, **Cita reservada** (Appointment Booked) añade un bloque `appointment` (consulta [Webhook de Cita reservada](#appointment-booked-webhook)), **Nuevo mensaje** (New Message) añade un bloque `message` completo con el texto (consulta [Webhook de Nuevo mensaje](#new-message-webhook)), y **Entregas** (Deliveries) y **Lecturas** (Reads) añaden un bloque `message` corto solo con el ID y el estado del mensaje (consulta [Webhook de Entregas y Lecturas](#deliveries-and-reads-webhook)).

> **Las Entregas y Lecturas te indican qué mensaje es, pero no qué decía.** Contienen un bloque `message` con el `id` y el `status` del mensaje — y ese `id` es el mismo `messageId` que devuelve el [endpoint de envío de mensajes](../api/messages.md#send-a-message), por lo que puedes hacer coincidir un recibo de entrega o lectura con el mensaje exacto que enviaste —, pero no el cuerpo del mensaje. **Respuestas** (Replies) no contiene ningún bloque `message`. Si necesitas las palabras que se enviaron o recibieron, suscríbete a **Nuevo mensaje** junto con ellos.

> **Dos cosas que debe saber antes de escribir su receptor.** No hay un campo `timestamp` ni un contenedor `data`. Cada bloque se encuentra en el nivel superior del objeto JSON, como se muestra arriba.

### Los 22 eventos de webhook

Los 22 eventos de webhook, con la etiqueta de visualización que marca en la aplicación y el código `event` enviado en la carga útil. El código `event` es una cadena corta que **no** coincide con la etiqueta de visualización, por lo que debe configurar su receptor basándose en el código, no en la etiqueta:

| Etiqueta de visualización (en la aplicación) | Código `event` en el payload | Qué significa |
|---|---|---|
| Contacto creado | `contactCreated` | Se añade un nuevo contacto a tu cuenta (manualmente, mediante importación o vía API). |
| Contacto pausado | `contact_paused` | La conversación con un contacto se pausa (el bot deja de responder). |
| Contacto reanudado | `contact_resumed` | Se reanuda una conversación pausada con un contacto. |
| Contacto No molestar | `contact_do_not_disturb_changed` | Se activa el ajuste de No molestar de un contacto. |
| Contacto desarchivado | `contact_unarchived` | Un contacto archivado envía un mensaje nuevo, lo que lo devuelve a tu bandeja de entrada activa. |
| Nuevo mensaje | `new_message` | Se añade cualquier mensaje a una conversación en cualquier canal, tanto los mensajes que tu contacto te envía como los que tu IA o tu equipo le envían a él. Este es el único evento que contiene el texto real del mensaje (consulta [Webhook de Nuevo mensaje](#new-message-webhook)). |
| Respuestas | `replied` | Un contacto responde a un mensaje. |
| Lecturas | `read` | Un contacto lee un mensaje (en canales que admiten recibos de lectura). Contiene el ID del mensaje que se leyó; consulta [Webhook de Entregas y Lecturas](#deliveries-and-reads-webhook). |
| Entregas | `delivered` o `undelivered` | Un mensaje se entrega correctamente a un contacto (`undelivered` cuando la entrega falla). Contiene el ID del mensaje; consulta [Webhook de Entregas y Lecturas](#deliveries-and-reads-webhook). |
| Alerta humana | `humanAlerted` | El bot de IA determina que no puede gestionar una conversación y la marca para atención humana. |
| Chat concluido | `chat_concluded` | El bot de IA decide que una conversación ha llegado a su fin (cita reservada, cliente potencial descalificado, etc.). |
| Cita reservada | `booked` | Un contacto reserva una cita a través del sistema de reservas. |
| Créditos gastados | `creditsSpent` | Se deducen créditos de tu cuenta. |
| Créditos recargados | `creditsRecharged` | Se añaden créditos a tu cuenta mediante recarga automática o compra manual. |
| Saldo de crédito bajo | `lowCreditBalance` en una entrega de **Prueba**, `Low Credit Balance` en una real | Un aviso temprano de que tu saldo de crédito ha caído por debajo de tu umbral de alerta (100 créditos a menos que establezcas el tuyo propio). Dirigido a agencias, cuyas subcuentas gastan todas desde un mismo fondo. Contiene `balance`, `threshold` y `account_email` en lugar de un bloque de contacto, se envía como máximo una vez cada 24 horas mientras el saldo permanezca bajo, y se reactiva tan pronto como el saldo vuelve a estar por encima del umbral. |
| Tarea creada | `taskCreated` | Se crea una tarea. |
| Tarea actualizada | `taskUpdated` | Una tarea cambia sin pasar a una etapa de finalización. |
| Tarea completada | `taskCompleted` | Una tarea pasa a una etapa configurada como etapa de finalización. |
| Resumen diario creado | `dailySummaryCreated` | Se genera tu informe de resumen diario. |
| Canal conectado | `channelConnected` | **Aún no se envía: seleccionable, pero nada lo emite hoy. No construyas nada basado en esto.** Destinado a cuando un canal de mensajería termina de conectarse. |
| Difusión iniciada | `broadcastStarted` | Comienza el envío de una difusión (su estado cambia a Enviando). Se dispara una vez por inicio, incluso cuando se reanuda una difusión pausada. Contiene un bloque `broadcast` en lugar de un bloque de contacto: id, nombre, canal, estado, estado anterior, la lista a la que se dirige (`list_id`, `list_name`, `is_smart_list`), `scheduled_at`, `total_contacts`. |
| Difusión completada | `broadcastCompleted` | Una difusión finaliza (su estado cambia a Enviado o Fallido). Mismo bloque `broadcast` más `completed_at` y, cuando esté disponible, `completion_summary` (`total_sent`, `permanently_failed`, `unique_replied`, `failure_rate`, `had_errors`). Usa estos dos para conectar una Lista de Difusión Inteligente a herramientas externas. |

Nunca aparecen dos códigos más en esa lista porque no te suscribes a ellos: `contact_tags_updated`, enviado por una URL de webhook configurada en una etiqueta individual, y `summary_generated`, enviado cuando se escribe un resumen de chat para una etiqueta en la lista `subscribed_to_tags` de un webhook.

> **Canal conectado aún no se envía.** Aparece en la lista de eventos, pero actualmente nada lo emite. No desarrolle basándose en él.

Las notificaciones basadas en etiquetas y tareas utilizan sus propias formas separadas. Consulte [Etiquetas de contacto actualizadas](#contact-tags-updated-webhook) y [Tarea completada](#task-completed-webhook).

---

## Webhook de contacto creado

Se envía cuando se activa el evento **Contacto creado** (se agrega un nuevo contacto manualmente, mediante importación o mediante API).

### Nombre del evento

`contactCreated`

### Formato de carga útil

```json
{
  "event": "contactCreated",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null,
    "is_bot_active": true,
    "ad_referral": null
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  }
}
```

| Campo | Descripción |
|---|---|
| `event` | Siempre `contactCreated` para este evento. |
| `contact.id` | El ID único del nuevo contacto. |
| `contact.email` / `contact.phone_number` | El correo electrónico y teléfono del contacto, si se conocen (cualquiera de los dos puede estar vacío dependiendo del canal). |
| `contact.first_name` / `contact.last_name` | El nombre del contacto, si se conoce. |
| `contact.human_alerted` / `contact.human_alert_reason` | Si el contacto está marcado para atención humana, y por qué. |
| `contact.is_bot_active` | Si el bot de IA está activo actualmente en este contacto. |
| `contact.ad_referral` | Atribución de anuncio Meta Click-to-WhatsApp, o `null`: consulte [Atribución de anuncios Click-to-WhatsApp](click-to-whatsapp-attribution.md). |
| `campaign` | La campaña bajo la cual se creó el contacto, o `null`. |
| `agent` | El agente asignado al contacto, o `null`. |
| `user` | Información básica de identidad de la cuenta propietaria del contacto. |

> **La muestra de "Prueba" y un evento real se ven ligeramente diferentes.** El botón de prueba envía datos de marcador de posición (John Doe, una campaña de muestra). Un evento real de Contacto creado contiene los detalles reales del contacto, y algunos campos pueden estar vacíos según el canal.

---

## Webhook de nuevo mensaje

Este webhook se activa cada vez que se añade un mensaje a una conversación, en cualquier canal. Cubre ambas direcciones: los mensajes que su contacto le envía a usted y los mensajes que su IA, su equipo o una campaña le envían a él. Es el único webhook que incluye el texto del mensaje, por lo que es el que debe utilizar cuando desee reflejar las conversaciones en un sistema externo.

### Nombre del evento

`new_message`

### Formato de carga útil

```json
{
  "event": "new_message",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null,
    "is_bot_active": true,
    "ad_referral": null
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<message-id>",
    "body": "Hi, are you open on Saturday?",
    "direction": "inbound",
    "status": "received",
    "created_at": "2026-07-30T17:27:06.000Z",
    "channel": "whatsapp_web"
  }
}
```

| Campo | Descripción |
|---|---|
| `event` | Siempre `new_message` para este evento. Ten en cuenta que esta es la cadena exacta enviada, no es la etiqueta de visualización "Nuevo mensaje". |
| `contact` | El contacto a cuya conversación pertenece el mensaje. Misma forma que en [Contacto creado](#contact-created-webhook). |
| `agent` | El agente que gestiona la conversación (`id` y `name`), o `null` si no hay ningún agente involucrado. |
| `user` | Información de identidad básica para la cuenta propietaria de la conversación. |
| `message.id` | El ID único del mensaje. |
| `message.body` | El texto del mensaje. Vacío para un mensaje que solo contiene un archivo adjunto (imagen, nota de voz, documento). |
| `message.direction` | `inbound` para un mensaje del contacto, `outbound` para uno enviado por tu IA o por tu equipo desde la bandeja de entrada, y `outbound-api` para uno enviado por una campaña, una difusión, un envío de plantilla o la API. |
| `message.status` | Dónde se encuentra el mensaje en su ciclo de vida: `received` para entrante, y `queued` / `sent` / `delivered` / `read` / `failed` / `undelivered` para saliente. Este es el estado en el momento en que se creó el mensaje, por lo que un mensaje saliente suele llegar aquí como `queued` o `sent` y alcanza `delivered` después; utiliza los eventos de **Entregas** y **Lecturas** si necesitas esas transiciones posteriores. Contienen el mismo `message.id` que este bloque, por lo que puedes hacer coincidir la transición con este mensaje (consulta [Webhook de Entregas y Lecturas](#deliveries-and-reads-webhook)). |
| `message.created_at` | Cuándo se creó el mensaje, en UTC (ISO 8601). |
| `message.channel` | El canal por el que pasó el mensaje, por ejemplo `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `messenger`, `telegram`, `email` o `custom`. |

> **Todavía no hay ningún bloque `campaign` en esta carga útil.** New Message envía `contact`, `agent`, `user` y `message`. El bloque `agent` se añadió el **15 de agosto de 2026** e indica qué agente gestiona la conversación; si también necesitas el contexto de la campaña, busca el contacto a través de la API utilizando `contact.id`.

> **Los registros internos de la IA no activan este webhook.** Junto con los mensajes reales, la plataforma mantiene sus propias filas de contabilidad en una conversación (las llamadas a herramientas de la IA y los registros de turnos internos). Estos nunca se envían; solo recibirá los mensajes que fueron realmente enviados o recibidos.

---

## Webhook de Entregas y Lecturas

Estos dos eventos informan de lo que le sucedió a un mensaje después de salir de <span data-t="appName">Your AI Connector</span>: **Entregas** se dispara cuando un mensaje llega al contacto (o no logra hacerlo), y **Lecturas** se dispara cuando el contacto lo abre, en los canales que admiten recibos de lectura.

Ambos contienen un bloque `message` con el ID del mensaje al que se refiere el evento, para que puedas hacer coincidir la actualización con el mensaje exacto que enviaste.

### Nombres de eventos

`delivered` y `undelivered` para **Entregas**, `read` para **Lecturas**.

### Formato de carga útil

```json
{
  "event": "delivered",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "ad_referral": null
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<message-id>",
    "status": "delivered"
  }
}
```

| Campo | Descripción |
|---|---|
| `event` | `delivered` o `undelivered` para **Entregas**, `read` para **Lecturas**. |
| `contact` | El contacto al que se envió el mensaje. |
| `campaign` | La campaña a la que pertenece el contacto, o `null`. |
| `agent` | El agente que gestiona la conversación, o `null`. |
| `user` | Información de identidad básica para la cuenta propietaria de los datos. |
| `message.id` | El ID del mensaje al que se refiere esta actualización. Es el mismo valor que devuelve el [endpoint de envío de mensajes](../api/messages.md#send-a-message) como `messageId`, y el mismo `message.id` que contiene una notificación de [Nuevo mensaje](#new-message-webhook). |
| `message.status` | El nuevo estado, siempre la misma cadena que `event` (`delivered`, `undelivered` o `read`). |

> **Cómo hacer coincidir una actualización con el mensaje que enviaste.** Almacena el `messageId` que recibes al enviar un mensaje a través de la API. Cuando llegue una notificación de **Entregas** o **Lecturas**, busca ese ID almacenado en `message.id` dentro del payload; ese es tu recibo de entrega o lectura para ese mensaje exacto.

> **Aquí no hay texto de mensaje.** El bloque `message` solo contiene el ID y el estado. Suscríbete a [Nuevo mensaje](#new-message-webhook) si también necesitas el cuerpo.

> **El bloque `message` solo está presente cuando sabemos de qué mensaje se trataba.** En la rara actualización que no podemos vincular a un mensaje almacenado, el bloque se omite por completo en lugar de enviarse vacío; así que verifica que `message` exista antes de leer `message.id`.

> **Una notificación por cambio de estado.** Un solo mensaje saliente normalmente produce una notificación de `delivered` y luego, en canales con recibos de lectura, una de `read`. Un envío fallido produce `undelivered` en su lugar.

---

## Webhook de cita reservada

Se activa cuando un contacto reserva una cita. Se activa de la misma manera tanto si la IA la reservó durante una conversación, como si usted la reservó manualmente o si llegó a través de la API.

### Nombre del evento

`booked`

### Formato de carga útil

```json
{
  "event": "booked",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith"
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com"
  },
  "appointment": {
    "appointment_id": "<appointment-id>",
    "start_time": "2026-07-20T15:00:00.000Z",
    "end_time": "2026-07-20T15:30:00.000Z",
    "status": "confirmed",
    "room_name": "Room 1",
    "description": "Discovery call",
    "summary": "30 min intro",
    "google_calendar_event_id": null,
    "event": {
      "id": "<service-id>",
      "event_name": "Intro Call",
      "slot_duration": 30,
      "location": "Zoom",
      "meeting_link": "https://...",
      "event_type": "online"
    }
  }
}
```

| Campo | Descripción |
|---|---|
| `event` | Siempre `booked` para este evento. |
| `contact` | La persona que reservó. `email` y `phone_number` pueden estar vacíos dependiendo del canal. |
| `appointment.appointment_id` | El ID único de la reserva. |
| `appointment.start_time` / `end_time` | Inicio y fin del espacio reservado, en UTC (ISO 8601). |
| `appointment.status` | El estado actual de la reserva. |
| `appointment.room_name` | La sala en la que se realizó la reserva, si se utiliza. |
| `appointment.description` / `summary` | Detalles de texto libre capturados con la reserva. |
| `appointment.google_calendar_event_id` | El ID de Google Calendar para el evento sincronizado. A menudo es `null` en el webhook de Cita reservada, porque el evento del calendario se crea en el mismo momento en que se envía la notificación; vuelve a obtener la cita por su `appointment_id` un momento después si lo necesitas, y espera un `null` permanente en cuentas sin Google Calendar conectado. |
| `appointment.event` | El servicio que se reservó: nombre, duración del espacio, ubicación, enlace de reunión, tipo. |

> **`google_calendar_event_id` suele ser `null` en este webhook, y eso es normal.** El evento de Google Calendar se crea en el mismo momento en que sale esta notificación, por lo que el ID generalmente aún no está listo. Vuelva a obtener la cita por su `appointment_id` un momento después si lo necesita. Permanece como `null` permanentemente si la cuenta no tiene Google Calendar conectado, así que no espere por él indefinidamente.

> **El botón "Probar" no incluye el bloque `appointment`.** Úselo para confirmar que su punto final responde, luego realice una reserva real para ver la carga útil completa.

> **Dos casos en los que este webhook no se activa:** citas importadas desde un calendario externo y reservas que provienen de la integración con Formitable.

---

## Webhook de actualización de etiquetas de contacto

Se activa cuando se **aplica** una etiqueta a un contacto y dicha etiqueta tiene una URL de webhook configurada en el agente o la campaña a la que pertenece el contacto.

### Nombre del evento

`contact_tags_updated`

### Cuándo se activa

- Se aplica una etiqueta a un contacto que tiene un agente asignado, una campaña asignada o ambos.
- Al menos una de las etiquetas aplicadas tiene una URL de webhook configurada en la pestaña Etiquetas de ese agente o campaña.

Si el contacto tiene ambos y las etiquetas de la campaña llevan URLs de webhook, estas prevalecen; de lo contrario, se utilizan las del agente.

Si se aplican varias etiquetas con diferentes URL de webhook en la misma actualización, se envía una solicitud por cada URL, conteniendo cada una solo las etiquetas que corresponden a esa URL.

**Eliminar una etiqueta nunca envía una solicitud.** La mayoría de las personas dirigen estas URL a una acción (cobrar un depósito, reservar un espacio, alertar a un representante), por lo que una etiqueta que se elimina de un contacto solía volver a ejecutar esa acción. Ya no puede hacerlo. Una eliminación sigue apareciendo en `removed_tags` cuando ocurre en la misma actualización que una aplicación que va a la misma URL, por lo que una automatización que lee ambas matrices mantiene la imagen completa; lo que nunca verá es una solicitud causada únicamente por una eliminación. (Cambiado el **12 de agosto de 2026**. Antes de esa fecha, las eliminaciones también enviaban una solicitud).

### Formato de carga útil

```json
{
  "event": "contact_tags_updated",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "is_bot_active": true,
    "ad_referral": {
      "ctwa_clid": "ARAbc123...",
      "source_id": "120210000000000",
      "source_type": "ad",
      "source_url": "https://fb.me/xxxx",
      "headline": "Get 20% off today",
      "body": "Message us now to claim your discount",
      "channel": "whatsapp"
    }
  },
  "added_tags": ["qualified-lead"],
  "removed_tags": ["new-lead"],
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  }
}
```

| Campo | Descripción |
|---|---|
| `event` | Siempre `contact_tags_updated` para este webhook. |
| `contact.id` | El ID único del contacto cuyas etiquetas cambiaron. |
| `contact.email` / `contact.phone_number` | El correo electrónico/teléfono del contacto, si se conoce. |
| `contact.first_name` / `contact.last_name` | El nombre del contacto. |
| `contact.human_alerted` | Si el contacto está actualmente marcado para atención humana. |
| `contact.is_bot_active` | Si el bot de IA está actualmente activo en la conversación de este contacto. |
| `contact.ad_referral` | Presente solo cuando el contacto te contactó por primera vez a través de un anuncio o publicación de Meta Click-to-WhatsApp (CTWA). `null` en caso contrario. |
| `added_tags` | Matriz de nombres de etiquetas aplicadas en esta actualización. Nunca vacía: una aplicación es lo que activa la solicitud. |
| `removed_tags` | Matriz de nombres de etiquetas eliminadas en la misma actualización, si las hay. Una eliminación por sí sola no envía nada. |
| `agent` | El agente que gestiona la conversación del contacto (`id` y `name`), o `null` si no hay ningún agente involucrado. Añadido el **15 de agosto de 2026**. |
| `user` | Información básica de identidad de la cuenta propietaria del contacto. |

### Probar un webhook de etiqueta

Junto al campo de URL del webhook en la pestaña Etiquetas, hay un botón **Probar**. Envía una carga útil de muestra a esa URL inmediatamente, para que pueda confirmar que su automatización la recibe antes de esperar a una conversación real.

La prueba envía la misma forma de `contact_tags_updated` que se muestra arriba, utilizando un contacto de marcador de posición, con la etiqueta que está probando en `added_tags` y un `removed_tags` vacío. Lo que su automatización ve en la prueba es lo que verá en producción.

Dos cosas que debe saber:

- **Guarda la etiqueta primero.** La prueba busca la etiqueta por su nombre guardado, por lo que una etiqueta nueva o un cambio de nombre no guardado aún no se pueden probar. El botón permanece desactivado hasta que el nombre en pantalla coincida con el guardado.
- **Una prueba fallida no cuenta en contra de tu webhook.** Las pruebas nunca contribuyen al apagado automático tras fallos repetidos descrito en [Fiabilidad del webhook](#webhook-reliability).

Si la prueba falla, el mensaje le indica lo que respondió su punto final (por ejemplo, un `404` o un `500`), lo cual suele ser suficiente para detectar una URL incorrecta o un flujo de trabajo que no está activado.

---

## Webhook de tarea completada

> **Solo como referencia.** Los webhooks de tareas (como datos) están documentados aquí para desarrolladores; los eventos **Tarea creada**, **Tarea actualizada** y **Tarea completada** se pueden seleccionar en la lista de eventos estándar en el formulario de webhook como cualquier otro evento; consulte [Eventos de activación disponibles](#available-trigger-events) y [Los 22 eventos de webhook](#the-22-webhook-events).

Esta carga útil se envía cuando una tarea pasa a una etapa marcada como etapa de finalización. Una tarea que se mueve entre etapas que no son de finalización envía el formato `taskUpdated` en su lugar.

### Nombre del evento

`taskCompleted`

### Cuándo se activa

- Se actualiza una tarea.
- Su valor `stage` cambió en comparación con su valor anterior.
- La nueva etapa está configurada como una etapa de finalización en la configuración de etapas de tareas de la cuenta.

### Formato de carga útil

```json
{
  "event": "taskCompleted",
  "contact": {
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null
  },
  "user": {
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<task-id>",
    "title": "Follow up with Jane",
    "description": "Confirm pricing and send proposal",
    "type": "follow_up",
    "priority": "high",
    "stage": "<stage-id>",
    "due_date": "2026-01-20T15:00:00Z",
    "source": "ai",
    "source_detail": "<source-detail>",
    "campaign_id": "<campaign-id>",
    "linked_human_alert": "<human-alert-id>",
    "tags": ["qualified-lead"],
    "notes": "Customer requested a callback"
  }
}
```

| Campo | Descripción |
|---|---|
| `event` | Siempre `taskCompleted` para este webhook. Se envía el mismo formato de carga útil que `taskUpdated` cuando una tarea cambia sin entrar en una etapa de finalización. |
| `contact` | El contacto vinculado a la tarea, si existe. `null` cuando no está vinculado. |
| `contact.human_alert_reason` | El motivo por el cual el contacto fue marcado para atención humana, si corresponde. |
| `user` | Información básica de identidad de la cuenta a la que pertenece la tarea. |
| `message.id` | El ID único de la tarea. |
| `message.title` / `description` | El título y la descripción de la tarea. |
| `message.type` | El tipo de tarea (por ejemplo, `follow_up`, `call`, `custom`). |
| `message.priority` | La prioridad de la tarea (`low`, `medium`, `high`). |
| `message.stage` | El ID de la etapa en la que se encuentra la tarea ahora. |
| `message.due_date` | La fecha de vencimiento de la tarea, si se ha establecido. |
| `message.source` | Qué creó la tarea (`ai`, `manual`, `api`). |
| `message.source_detail` | Detalles adicionales sobre la fuente. |
| `message.campaign_id` | El ID de la campaña vinculada, o `null`. |
| `message.linked_human_alert` | El ID de la alerta humana vinculada, si existe. |
| `message.tags` | Etiquetas aplicadas a la tarea. |
| `message.notes` | Notas de formato libre sobre la tarea. |

---

## Desactivar un webhook (o eliminarlo)

Cada webhook tiene un interruptor de encendido/apagado, justo en su fila. Desactivarlo (**off**) detiene la recepción de eventos, pero mantiene todo lo que configuró: la URL, los eventos y cualquier secreto de firma. Vuelva a activarlo y continuará desde donde lo dejó; nada de lo que haya ocurrido mientras estaba desactivado se entregará posteriormente.

Úselo cuando desee que las entregas se detengan por un tiempo: su endpoint se está reconstruyendo, está depurando una integración ruidosa o está pausando una automatización.

**Eliminar** un webhook (el icono de la papelera en su fila) lo elimina definitivamente, incluido su secreto de firma. Si solo desea que las entregas se detengan, desactívelo en su lugar; la eliminación es para cuando haya terminado por completo con el endpoint.

> **Esto no es lo mismo que desactivar un webhook automáticamente.** Si desactivamos su webhook tras fallos repetidos (consulte [Fiabilidad de los Webhooks](#webhook-reliability)), el interruptor de arriba no lo volverá a activar. Una vez que su endpoint esté corregido, edite el webhook y guárdelo con una URL distinta (cualquier cambio de URL lo reactiva), o llame al [endpoint de reactivación](../api/webhooks.md) a través de la API, o póngase en contacto con el soporte técnico y lo reactivaremos por usted.

---

## Cargas útiles firmadas (verificar que un webhook realmente provino de nosotros)

Cualquiera que conozca la URL de su webhook podría enviarle una solicitud falsa. Si actúa sobre los webhooks automáticamente (actualizando la facturación, creando registros en el CRM), activar la **firma** le permite verificar que cada solicitud provino realmente de nosotros.

La firma es **opcional y está desactivada de forma predeterminada**, y se activa por cada webhook desde la vista de edición de dicho webhook (abra la fila de un webhook guardado).

### Activación de la firma

1. Abra el webhook (Configuración → Integraciones → Webhooks → haga clic en la fila de su webhook).
2. En la sección **Secreto de firma**, haga clic en **Generar**.
3. Copie el secreto (comienza con `whsec_`) y guárdelo en su sistema receptor. Trátelo como una contraseña.

Puede volver y revelar, copiar, rotar o desactivar el secreto en cualquier momento desde este mismo panel.

### Lo que enviamos

Una vez activada la firma, cada entrega para ese webhook lleva estos dos encabezados HTTP adicionales:

| Encabezado | Significado |
|---|---|
| `X-Webhook-Signature` | La firma, en el formato `v1=<hex>`. |
| `X-Webhook-Timestamp` | Cuándo lo enviamos, como una marca de tiempo Unix en segundos. |

Estos tres están en **cada** entrega, firmada o no:

| Encabezado | Significado |
|---|---|
| `X-Webhook-Delivery` | Un ID único para este evento. Permanece igual en los reintentos, por lo que es sobre lo que debe realizar la deduplicación. |
| `X-Webhook-Attempt` | Qué intento es este (`1` es el primer intento). |
| `X-Webhook-Event` | El nombre del evento, para que pueda enrutarlo sin leer el cuerpo. |

### Cómo verificar

La firma es un HMAC-SHA256 de la cadena `<timestamp>.<raw request body>`, utilizando su secreto de firma como clave.

**Verifique contra el cuerpo de la solicitud sin procesar: los bytes exactos que recibió.** Si su framework analiza el JSON y lo vuelve a serializar antes de comprobarlo, los bytes pueden cambiar y la firma no coincidirá.

Ejemplo en Node.js:

```js
const crypto = require("crypto");

function verify(rawBody, headers, secret) {
  const timestamp = headers["x-webhook-timestamp"];
  const signature = headers["x-webhook-signature"]; // "v1=<hex>"

  // Reject anything older than 5 minutes so a captured request can't be replayed later.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");

  return crypto.timingSafeEqual(Buffer.from(signature.replace("v1=", "")), Buffer.from(expected));
}
```

Ejemplo en Python:

```python
import hashlib, hmac, time

def verify(raw_body: bytes, headers, secret: str) -> bool:
    timestamp = headers["X-Webhook-Timestamp"]
    signature = headers["X-Webhook-Signature"].replace("v1=", "")

    # Reject anything older than 5 minutes so a captured request can't be replayed later.
    if abs(time.time() - int(timestamp)) > 300:
        return False

    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()

    return hmac.compare_digest(signature, expected)
```

> **Compare las firmas con una función de tiempo constante** (`timingSafeEqual` / `compare_digest`), no con `==`. No cuesta nada y evita una clase sutil de ataque.

### Rotación del secreto

Haga clic en **Rotar** para reemplazar el secreto. El cambio es inmediato: la siguiente entrega se firma únicamente con el nuevo secreto. Si su endpoint está activo, acepte **tanto** el secreto antiguo como el nuevo durante unos minutos mientras implementa el nuevo.

Desactivar la firma simplemente evita que se envíen los encabezados de firma.

---

## Reintento de entregas fallidas

De forma predeterminada, una entrega que falla no se vuelve a intentar; si su sistema no está disponible en ese momento, se pierde el evento.

Active **Reintentar entregas fallidas** en un webhook (en el formulario de creación/edición) y seguiremos intentándolo:

| Intento | Cuándo |
|---|---|
| 1 | Inmediatamente |
| 2 | 1 minuto después |
| 3 | 5 minutos después |
| 4 | 30 minutos después |
| 5 | 2 horas después |

Eso abarca aproximadamente **2 horas y 40 minutos**, por lo que un webhook puede sobrevivir a una ventana de mantenimiento o a una breve interrupción de su parte.

**Qué se reintenta:** problemas temporales: su servidor devuelve un error 5xx, un tiempo de espera agotado o un error de conexión.

**Qué no se reintenta:** si su endpoint rechaza la solicitud en sí (cualquier 4xx), no reintentamos; enviar la misma solicitud de nuevo solo produciría el mismo rechazo.

**Qué eventos se reintentan:** webhooks de etiquetas (`contact_tags_updated`), los tres eventos de tareas y el resumen diario. El resto se envían una vez, por lo que para ellos el interruptor no tiene nada sobre lo que actuar. Cada evento sigue llevando `X-Webhook-Delivery`, por lo que una regla de deduplicación los cubre todos.

> **Active los reintentos solo si su endpoint es idempotente.** Los reintentos significan que el mismo evento puede llegar más de una vez. Utilice el encabezado `X-Webhook-Delivery` para reconocer una repetición: permanece igual en cada intento para un mismo evento, por lo que puede ignorar de forma segura un ID que ya haya procesado.

Los reintentos interactúan con la desactivación automática tras fallos repetidos (consulte [Fiabilidad de los webhooks](#webhook-reliability)) de la forma que usted desea: el contador de fallos cuenta una **entrega completa**, solo después de que se hayan agotado todos los reintentos, no cada intento individual.

---

## Fiabilidad del Webhook

- <span data-t="appName">Your AI Connector</span> envía webhooks a través de una conexión segura (HTTPS). Asegúrese de que la dirección web que proporcione utilice HTTPS.
- Si su sistema devuelve un error, la entrega se considera fallida.
- Supervise el tiempo de actividad de su sistema receptor para evitar perder eventos.
- Para flujos de trabajo críticos, active [Reintento de entregas fallidas](#retrying-failed-deliveries) y considere también un mecanismo de respaldo.

> **Los webhooks se desactivan automáticamente tras fallos repetidos.** Si la URL de su webhook falla repetidamente (aproximadamente 5 errores seguidos, o 3 seguidos en caso de errores de configuración), <span data-t="appName">Your AI Connector</span> dejará de enviar eventos a esa URL automáticamente. Para reactivarlo una vez que su endpoint funcione correctamente: edite el webhook y guárdelo con una URL distinta (cualquier cambio de URL lo reactiva), o utilice el [endpoint de reactivación](../api/webhooks.md) a través de la API; guardar de nuevo con la misma URL no es suficiente. El equipo de soporte también puede reactivarlo por usted.

---

## Solución de problemas

| Problema | Solución |
|---|---|
| El webhook no se dispara | Primero compruebe que el webhook no esté **desactivado** en su fila. Luego confirme que los eventos correctos están seleccionados y que su URL es accesible desde Internet. |
| El evento de prueba funciona pero los eventos reales no | Asegúrese de que el tipo de evento específico esté habilitado. Si esperaba una solicitud cuando se aplica una etiqueta, tenga en cuenta que `subscribed_to_tags` no limita los eventos de un webhook a una etiqueta; solo reduce qué etiquetas producen una notificación de resumen de conversación. Para obtener una solicitud cuando se aplica una etiqueta específica, establezca una URL de webhook en esa etiqueta en la pestaña **Etiquetas** del agente (o campaña); consulte [Webhook de actualización de etiquetas de contacto](#contact-tags-updated-webhook). |
| No llega nada a n8n / Make / Zapier | Probablemente esté utilizando la **URL de prueba** de la plataforma, que solo escucha un único evento justo después de hacer clic en "Escuchar evento de prueba". Para eventos en vivo, guarde la **URL de producción** y cambie el flujo de trabajo a **Activo**. |
| Recibiendo eventos duplicados | Compruebe si hay varios webhooks apuntando a la misma URL. Si **Reintentar entregas fallidas** está activado, se espera una repetición siempre que su punto final aceptó un evento pero no respondió a tiempo; elimine duplicados en `X-Webhook-Delivery`. |
| La comprobación de firma siempre falla | Casi siempre porque el cuerpo se volvió a serializar antes de comprobarlo. Verifique contra el cuerpo de la solicitud **sin procesar**, firme `<timestamp>.<body>` y confirme que está utilizando el secreto actual si lo rotó recientemente. |
| Los reintentos no ocurren | Los reintentos están desactivados a menos que se habiliten en ese webhook específico. No reintentamos respuestas 4xx. |
| El bloque `campaign` es siempre `null` | Es lo esperado si su cuenta utiliza agentes: los contactos se asignan a un agente en lugar de a una campaña. Lea el bloque `agent` en su lugar; consulte [Formato de datos de webhook](#webhook-data-format). |
| Los datos están vacíos o mal formados | Verifique que su sistema receptor acepte JSON. Compruebe los registros de su servidor en busca de errores de análisis. |
| La URL del webhook devuelve errores | Pruebe su URL con una herramienta como Postman o [webhook.site](https://webhook.site). |
| El webhook dejó de dispararse por completo tras una interrupción | Los fallos repetidos desactivan automáticamente un webhook. Guardarlo de nuevo no lo vuelve a activar; arregle su punto final y luego contacte al soporte. |
| Guardar o probar da un error de permiso | Necesita el permiso de "edición" de Integraciones. Pida al propietario de la cuenta que se lo conceda. |
| La lista `subscribed_to_tags` de un webhook volvió vacía | `subscribed_to_tags` no limita los eventos de un webhook a una etiqueta; solo reduce qué etiquetas producen una notificación de resumen de conversación. La edición desde el formulario de webhook ya no borra esa lista (corregido el 21 de julio de 2026). Si un webhook perdió su lista antes de esa fecha, establezca `subscribed_to_tags` nuevamente a través de la [API de Webhooks](../api/webhooks.md); consulte [Activadores de webhook basados en etiquetas](#tag-based-webhook-triggers). |

---

## Próximos pasos

- [Integración con GoHighLevel](ghl-integration.md): utilice webhooks para integrar <span data-t="appName">Your AI Connector</span> con GHL.
- [Acceso a la API](api-access.md): combine webhooks con la API para obtener automatizaciones potentes.
- [Uso de etiquetas para clasificar contactos](../get-started/creating-tags.md): configure etiquetas que activen sus webhooks.
