Webhooks
Recibe eventos en tiempo real mediante HTTP POST en tu endpoint
Última actualización el
Los webhooks reciben eventos en tiempo real mediante HTTP POST a una URL que configuras tú. Los mismos eventos también están disponibles mediante SSE. Los webhooks se configuran por organización: cada organización tiene los suyos.
Gestión
Consulta la especificación OpenAPI para los esquemas completos de petición y respuesta.
| Método | Ruta | Descripción |
|---|---|---|
| GET | /api/orgs/:orgId/webhooks | Obtener webhooks |
| GET | /api/orgs/:orgId/webhooks/delivery-stats | Obtener estadísticas de entrega |
| POST | /api/orgs/:orgId/webhooks/retry-deliveries | Reintentar entregas. Body: mode (failed o force) y, opcionalmente, id para un solo webhook. failed: solo entregas fallidas de forma definitiva, de inmediato. force: entregas pendientes y fallidas de forma definitiva, en segundo plano, ignorando los tiempos de espera. |
| GET | /api/orgs/:orgId/webhooks/:id | Obtener un webhook por ID |
| POST | /api/orgs/:orgId/webhooks | Crear un webhook |
| PATCH | /api/orgs/:orgId/webhooks/:id | Actualizar un webhook |
| DELETE | /api/orgs/:orgId/webhooks/:id | Eliminar un webhook |
Crear un webhook
POST /api/orgs/org_abc123/webhooks
Content-Type: application/json
x-api-key: tkn_xxx{
"url": "https://jouw-server.com/webhooks/tillor",
"subscribedEventKeys": ["invoice:created", "invoice:paid", "customer:updated"],
"enabled": true
}- url - Endpoint HTTPS que acepta peticiones POST
- subscribedEventKeys - Array de claves de evento o
["*"]para todos los eventos. La lista completa está en Tillor en Menú de perfil → Desarrolladores, en Añadir webhook → Eventos suscritos.
Algunos eventos son tan frecuentes que no puedes elegirlos y tampoco llegan mediante *, como el estado físico de las barreras, la escritura en la bandeja de entrada, los logs del controlador y la presencia de vehículos. No aparecen en la lista de abajo. Qué eventos puedes elegir depende también de tus permisos.
- enabled -
truepara activar la entrega
Solo puedes elegir eventos para los que tu miembro de la organización tenga el permiso adecuado (p. ej. transacciones bancarias para bankAccountTransaction:*). El comodín * solo está disponible para miembros con acceso total (*). Con una combinación no válida, la API devuelve un mensaje de error. Un webhook envía el payload completo, con los datos vinculados (como el cliente en una reserva). Por eso también debes poder leer esos dominios para crear un webhook, cambiar la URL o los eventos, o volver a activarlo.
Payload del webhook
Cada entrega de webhook es un POST con:
Encabezados:
Content-Type: application/jsonX-Webhook-Event-ID- ID único y estable de esta entrega lógica (mismo valor en los reintentos)X-Webhook-Signature- firma HMAC-SHA256 del body, formatosha256=<hex>(consulta Verificar la firma)
Body:
{
"event": "invoice:created",
"data": {},
"timestamp": 1735689600000,
"traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
"spanId": "00f067aa0ba902b7",
"triggeredBy": {
"id": "usr_63x8jp68is",
"name": "Niels"
}
}| Campo | Tipo | Descripción |
|---|---|---|
event | string | Clave del evento (p. ej. invoice:created) |
data | object | Payload específico del evento |
timestamp | number | Marca de tiempo Unix (ms) del momento en que se emitió el evento |
traceId | string | ID de traza de OpenTelemetry de la acción de Tillor que provocó este evento. Facilítalo al soporte; no es un secreto. |
spanId | string (opcional) | Span dentro de esa traza |
triggeredBy | object | null | Usuario que realizó la acción (id, name). null en acciones del sistema (cron, sincronización bancaria, …) |
Consulta Ejemplos para ver ejemplos completos de payload.
Verificar la firma
Cada webhook tiene su propio secreto de firma (64 caracteres hexadecimales, visible en la tabla de webhooks mediante Mostrar secreto de firma en Menú de perfil → Desarrolladores). Tillor firma cada POST con ese secreto para que puedas comprobar que la petición viene realmente de Tillor y que el body no se ha modificado.
Cómo firma Tillor:
- Calcula
HMAC-SHA256(signingSecret, raw_request_body)(hex en minúsculas). - Lo envía como
X-Webhook-Signature: sha256=<hex>.
Cómo verificas tú:
- Lee el body en bruto de la petición (antes de analizar el JSON; si no, el hash no coincidirá).
- Calcula tú mismo
HMAC-SHA256(signingSecret, raw_body)en hex. - Compara con el valor que sigue a
sha256=en el encabezadoX-Webhook-Signaturecon una comparación de tiempo constante.
import crypto from "node:crypto";
function verifyTillorWebhook(rawBody, headerSignature, signingSecret) {
const expected = crypto.createHmac("sha256", signingSecret).update(rawBody).digest("hex");
const received = headerSignature.replace(/^sha256=/, "");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(received, "hex");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Trata el secreto como una contraseña
Puedes mostrar el secreto de firma en Tillor mediante Mostrar secreto de firma en la tabla de webhooks. Guárdalo como secreto (variable de entorno, vault) y no lo registres nunca en logs. ¿Sospechas una fuga? Elimina el webhook y crea uno nuevo; así obtienes un secreto nuevo.
Comportamiento de entrega y reintentos
- Responde con un estado 2xx para confirmar el éxito.
- Si una entrega falla (no 2xx, error de red o destino bloqueado), Tillor la reintenta automáticamente con intervalos cada vez más largos. Cada intento reutiliza el mismo payload, la misma firma y el mismo ID de evento (idempotente).
| Intento | Tiempo de espera desde el intento anterior |
|---|---|
| 1 | inmediato |
| 2 | 1 segundo |
| 3 | 2 segundos |
| 4 | 4 segundos |
| 5 | 8 segundos |
| 6 | 5 minutos |
| 7 | 30 minutos |
| 8 | 2 horas |
| 9 | 6 horas |
| 10 | 24 horas |
- Si uno de los intentos tiene éxito (2xx) → la entrega queda completada.
- Si tampoco tiene éxito el intento 10 (tras 24 h) → la entrega se marca definitivamente como fallida y no se reintenta más.
- Si mientras tanto el webhook se desactiva, Tillor deja de reintentar.
Idempotencia
Cada reintento reutiliza el mismo X-Webhook-Event-ID y X-Webhook-Signature. Deduplica de tu lado con ese encabezado para que un reintento exitoso tras un 200 lento no provoque un procesamiento duplicado.
Avisos por fallos persistentes
Si las entregas a un endpoint de webhook siguen fallando, Tillor envía como máximo dos avisos por incidente (por endpoint):
- Tras 5 minutos de fallos persistentes - correo electrónico a la dirección de correo de la organización (
supportEmail, o si noemail) y a los miembros de la organización con permiso para modificar los ajustes de la organización, además de una notificación push (si está activada) para esos miembros. El correo indica desde cuándo fallan las entregas. Las fechas del correo usan la zona horaria de Configuración > General (por defectoEurope/Brussels). - Al fallar definitivamente - los mismos destinatarios reciben un aviso cuando el primer evento de ese incidente se marca como fallido de forma definitiva tras todos los intentos.
No recibes un aviso por cada evento fallido. En cuanto todas las entregas fallidas de un endpoint se resuelven (entregadas con éxito), un nuevo incidente empieza de nuevo con las mismas reglas.
En Menú de perfil → Desarrolladores, la tabla de webhooks muestra por endpoint un estado de entrega compacto (cantidades pendientes de reintento y fallidas de forma definitiva). Haz clic en el icono ℹ para ver los detalles, incluido el mensaje de error completo y el payload del intento más reciente.
- Reintentar entregas fallidas (↻): solo las entregas fallidas de forma definitiva de ese webhook.
- Forzar reintento (⚡): todas las entregas pendientes y fallidas de forma definitiva de ese webhook, independientemente de los tiempos de espera programados. Tillor lo inicia en segundo plano para que las colas grandes (p. ej. miles de eventos) se procesen con seguridad.
- Forzar reintento de todos, arriba a la derecha junto a Añadir webhook: lo mismo para todos los webhooks activados de la organización.
Tipos de evento
Las claves de evento usan el formato entity:action o entity:subresource:action. La lista completa, con el permiso de cada evento y un ejemplo de payload, está en el índice de eventos. Esa página se genera a partir del código y por tanto siempre está completa. Las mismas claves están en Tillor en Menú de perfil → Desarrolladores, en Añadir webhook → Eventos suscritos.
Webhooks frente a SSE
| Caso de uso | Recomendación |
|---|---|
| Integración en el servidor | Webhooks - Tu servidor recibe los POST |
| Registro sencillo | Webhooks - Configuración mínima |
| Panel en tiempo real, actualizaciones en vivo en una app | SSE - Una conexión, baja latencia. |
| Muchos tipos de evento, filtrado en el cliente | SSE - Usa el parámetro de consulta events para limitar el tráfico. |
Relacionado
- OpenAPI - especificación completa de la API
- API HTTP - API REST y claves de API
- SSE - los mismos eventos mediante Server-Sent Events
- Automatizaciones - enviar mensajes propios desde una automatización