Saltar al contenido principal
Un webhook hace el camino inverso de la API: en vez de que usted consulte a Nuvia, Nuvia envía un POST a su servidor cada vez que algo sucede en su operación: llega un mensaje, se crea un contacto, el agente completa un campo.
Cada empresa tiene como máximo un webhook. No es una colección: usted configura una URL y elige qué eventos recibe. Intentar crear un segundo devuelve 409.

Configurar

POST /v1/webhooks con la URL y la lista de eventos. Scope necesario: webhooks:create.

Qué envía Nuvia

Cada entrega es un POST con estos headers: Y el cuerpo siempre tiene la misma estructura de tres campos:
  • event: el evento que disparó la entrega.
  • timestamp: ISO 8601 UTC, generado en el momento en que la entrega fue encolada.
  • data: el recurso relacionado con el evento (ver la tabla de abajo).
El cuerpo no identifica a la empresa: no existe companyId en el envelope. Si su servidor atiende a varias empresas de Nuvia, use una URL por empresa o un valor distinto en custom_headers para saber de quién es el evento.

Eventos disponibles

En los eventos de mensaje, conversación y contacto, data trae el recurso en el mismo formato que la Referencia de la API devuelve en los GET correspondientes, por ejemplo GET /v1/messages/conversation/{id} para mensajes. Las excepciones son FIELD_UPDATED, MESSAGE_FAILED y CONVERSATION_STEP_CHANGED, detalladas a continuación.
Trate data de forma tolerante: lea los campos que use e ignore el resto. Pueden aparecer campos nuevos a medida que la plataforma evoluciona, y eso no se considera una ruptura de contrato.

FIELD_UPDATED es diferente

Este evento no devuelve una entidad, sino la descripción del cambio:
field.context indica a qué pertenece el campo: contact, conversation o business. value tiene el tipo del campo: string, número, booleano o lista. conversationId solo viene cuando el cambio ocurrió dentro de una conversación.

MESSAGE_FAILED cubre falla de entrega, no falla de envío

El evento se dispara cuando WhatsApp devuelve un estado de falla para un mensaje que ya salió de Nuvia. Vale solo para el canal WhatsApp Cloud API.
Estos casos no generan ningún evento, aunque el mensaje quede con status: FAILED en la plataforma:
  • error al momento del envío, cuando la solicitud a WhatsApp falla
  • envío bloqueado por Nuvia antes de salir, como la ventana de 24h ya vencida
  • fallas en canales que no son WhatsApp Cloud API
Si su integración necesita saber que el mensaje no salió, MESSAGE_FAILED no cubre ese caso. Consulte el status del mensaje en la Referencia de la API.
El cuerpo trae el mensaje con el estado actualizado y una clave failure_reason con la causa:
code es el código de error de WhatsApp, por ejemplo 131026 para un número que no usa WhatsApp y 131047 para ventana de 24h vencida. message es el texto listo para mostrar, el mismo que el operador ve en la tarjeta de la conversación, y viene en portugués, como muestra el ejemplo de arriba. Use el code para la lógica de su integración y el message solo para mostrar. El texto puede cambiar sin aviso, el código no.
Lea el motivo en failure_reason, nunca en el campo errors del mensaje. En el cuerpo del webhook, errors llega desactualizado y casi siempre vacío, porque el evento se arma antes de que la plataforma guarde los errores. El errors completo aparece en el GET del mensaje.failure_reason es opcional: cuando WhatsApp no informa la causa, la clave no viene. Maneje su ausencia sin romper.

CONVERSATION_STEP_CHANGED entrega el cambio, no la conversación

El evento se dispara cuando la conversación cambia de etapa en el embudo, sea desde el panel, el agente de IA o la API. Solo se dispara con un cambio real de etapa.
previousStep viene null cuando la conversación todavía no estaba en ninguna etapa. origin indica qué provocó el cambio y puede no venir.
Este evento no reemplaza a CONVERSATION_UPDATED. Cuando la etapa cambia por PATCH en la conversación, quien está suscrito a los dos recibe ambos en la misma solicitud. Por el cambio de etapa dedicado, sale solo CONVERSATION_STEP_CHANGED.
Una etapa de campaña puede configurarse para mover la conversación a una etapa del embudo en el momento del envío. En ese caso la etapa cambia sin que el lead haya respondido. No use el cambio de etapa, por sí solo, como señal de interés del lead.

Identificar el remitente del mensaje

Los eventos de mensaje traen dos campos que, juntos, indican de dónde vino el mensaje: Los mensajes enviados desde la app de WhatsApp Business en coexistencia llegan por el evento MESSAGE_RECEIVED, no por MESSAGE_SENT. Por eso, para detectar la respuesta del lead, filtre por sender_type: CONTACT y message_type: INCOMING, y no solo por el nombre del evento. Si su integración envía mensajes por la API y necesita distinguirlos de los mensajes de la IA, guarde los IDs de los mensajes que ella misma envió.

Validar que la llamada vino de Nuvia

No hay firma HMAC. Nuvia no firma el cuerpo de la solicitud, así que no existe forma de verificar criptográficamente el origen.
El mecanismo disponible es custom_headers: registre un valor secreto y verifíquelo en cada solicitud.
Node.js
Use HTTPS y un valor largo y aleatorio. Como el secreto viaja en el header en cada entrega, trátelo como una credencial: rótelo con PUT /v1/webhooks/{id} si sospecha de una filtración.

Garantías de entrega

Estas son las características reales de la entrega. Léalas antes de construir algo que dependa de un webhook:
Si su servidor está fuera de línea, devuelve 5xx o agota el tiempo límite, el evento se pierde. La falla queda registrada del lado de Nuvia, pero nada se reenvía. Para datos críticos, reconcilie periódicamente con la API (por ejemplo, listando los mensajes de la conversación) en vez de confiar solo en el webhook.
Nuvia espera como máximo 10 segundos su respuesta. Responda 2xx de inmediato y haga el procesamiento en segundo plano. Si procesa antes de responder, entregas legítimas se convierten en timeout.
Los eventos de estado vienen de WhatsApp, que puede entregarlos fuera de orden (un MESSAGE_DELIVERED llegando después del MESSAGE_READ del mismo mensaje). Nuvia no los reordena. Trate cada evento por el estado que trae, sin asumir una secuencia.
MESSAGE_DELIVERED y MESSAGE_READ solo se envían cuando el estado realmente cambia. WhatsApp reenvía el mismo estado varias veces, y esas repeticiones se descartan: usted no recibe duplicados por eso. Aun así, escriba un handler idempotente: use el identificador del mensaje como clave.
Con status: "INACTIVE", o para eventos que no incluyó en events, Nuvia no encola ninguna entrega, y no hay historial para recuperar después. Reactivarlo no recupera el período detenido.

Gestionar la configuración

El GET devuelve un objeto con la configuración de la empresa, o null si no hay ninguna. No es una lista. El id usado en el PUT y en el DELETE viene de ese objeto. Después de eliminarlo, la empresa vuelve a poder crear un webhook nuevo. Para pausar temporalmente sin perder la configuración, prefiera PUT con status: "INACTIVE" en vez de eliminarlo.

Próximos pasos

Ejemplos de integración

El webhook dentro de un caso de uso completo, con respuesta automática.

Referencia de la API

Parámetros y respuestas de los endpoints de webhook.