Un webhook es una petición POST que la API envía al endpoint registrado cuando ocurre un evento suscrito. La entrega es asíncrona: la operación que origina el evento no espera a que el receptor responda.
Cada endpoint se registra con POST /v1/webhooks, que devuelve el secreto de firma. La suscripción admite entre 1 y 10 eventos por endpoint.
Firma de las entregas
El cuerpo de cada entrega se firma con HMAC-SHA256 usando el secreto del endpoint. La firma viaja en hexadecimal, prefijada por el algoritmo:
X-{Brand}-Signature: sha256=<hex>La verificación consiste en calcular el HMAC-SHA256 del cuerpo recibido tal como llegó, sin reserializar el JSON, y compararlo con el valor de la cabecera. Una comparación en tiempo constante evita filtrar información por el tiempo de respuesta.
Cabeceras de una entrega
| cabecera | contenido |
|---|---|
X-{Brand}-Signature | sha256= seguido del HMAC en hexadecimal |
X-{Brand}-Event | Tipo de evento que originó la entrega, por ejemplo validation.completed |
X-{Brand}-Delivery-Id | Identificador de la entrega, útil para deduplicar reintentos |
X-{Brand}-Timestamp | Momento del envío, en ISO 8601 con sufijo Z |
Content-Type | application/json; charset=utf-8 |
El Delivery-Id se mantiene estable entre los reintentos de una misma entrega: es el valor que permite descartar duplicados en el receptor.
Tiempos de espera y reintentos
La conexión dispone de 5 segundos y la petición completa de 10 segundos. Agotado ese margen, la entrega se considera fallida.
Una entrega fallida se reintenta hasta 5 veces, con esperas crecientes:
| intento | espera desde el anterior |
|---|---|
| 1.º reintento | 1 minuto |
| 2.º reintento | 5 minutos |
| 3.º reintento | 30 minutos |
| 4.º reintento | 2 horas |
| 5.º reintento | 6 horas |
No todas las respuestas se reintentan. La distinción es si el fallo puede resolverse con el tiempo:
| respuesta del receptor | tratamiento |
|---|---|
2xx | Entrega correcta |
5xx, error de red o tiempo agotado | Se reintenta |
408 y 429 | Se reintentan: indican saturación temporal |
Resto de 4xx | No se reintenta. Un 400 o un 404 señalan un receptor mal configurado, y repetir la petición no lo corrige |
El cuerpo de la respuesta del receptor se conserva truncado a 2 048 bytes para el historial de entregas, consultable en GET /v1/webhooks/{id}/deliveries.
Las entregas salientes están limitadas a 10 por dominio y por minuto: un receptor con muchos eventos simultáneos los recibe escalonados, no en ráfaga.
Desactivación automática
El endpoint acumula un contador de fallos consecutivos. Una entrega correcta lo devuelve a cero.
Al alcanzar 3 fallos consecutivos, el endpoint pasa a estado auto_disabled y deja de recibir entregas. El estado se consulta en GET /v1/webhooks junto con el contador consecutive_failures.
La reactivación es manual: se hace con PUT /v1/webhooks/{id} fijando el estado en active. El valor auto_disabled no puede asignarse desde la API — solo lo establece el sistema.
Estados de una entrega
| estado | significado |
|---|---|
pending | Encolada, todavía sin intentar |
retrying | Falló y tiene reintentos pendientes |
success | El receptor respondió 2xx |
failed | Agotó los reintentos o recibió un 4xx no reintentable |
Recomendaciones para el receptor
- Responder
2xxen cuanto el cuerpo esté recibido y validado, y procesarlo después. Un receptor que procesa antes de responder consume el margen de 10 segundos y provoca reintentos innecesarios. - Deduplicar por
X-{Brand}-Delivery-Id: un reintento repite la misma entrega. - Verificar la firma antes de leer el contenido.