Webhooks
¿Qué son los webhooks?
Sección titulada «¿Qué son los webhooks?»Los webhooks permiten que Overtaker notifique a tu plataforma cuando ocurren eventos en los tenants de tus clientes — sin necesidad de polling.
Configurar un webhook
Sección titulada «Configurar un webhook»El webhook se cuelga de una API key activa: primero generá tu key en Canal API, luego registrá la URL de destino.
curl -X POST https://api.overtaker.online/api/v1/partner/webhooks \ -H "Authorization: Bearer sk_live_xxx" \ -H "Content-Type: application/json" \ -d '{ "url": "https://tuplataforma.com/webhooks/overtaker", "events": ["message.received", "lead.created", "lead.stage_changed", "tenant.limit_warning"] }'La respuesta incluye tu webhook_secret — guardalo, lo necesitás para verificar la firma de cada evento.
Eventos disponibles
Sección titulada «Eventos disponibles»| Evento | Descripción |
|---|---|
message.received | El usuario envió un mensaje al bot |
message.sent | El bot respondió al usuario |
lead.created | Se capturó un nuevo lead |
lead.stage_changed | El lead avanzó en el funnel |
tenant.limit_warning | El tenant cruzó un umbral de aviso de su límite mensual (90% y 95%) |
tenant.limit_reached | El tenant llegó al 100% de su límite mensual |
Estructura del payload
Sección titulada «Estructura del payload»Todos los eventos comparten la misma envoltura {event, tenant_id, timestamp, data}. El campo data varía según el evento.
{ "event": "lead.created", "tenant_id": "tenant_abc123", "timestamp": "2026-05-21T10:30:00Z", "data": { "lead_id": "lead_xyz", "phone": "+56912345678", "funnel_stage": "NEW" }}Ejemplos de data por evento:
| Evento | data |
|---|---|
message.received | { "conversation_id": "...", "message_preview": "Hola...", "channel": "API" } |
message.sent | { "conversation_id": "...", "response_preview": "Hola, en qué ayudo..." } |
lead.created | { "lead_id": "...", "phone": "+56912345678", "funnel_stage": "NEW" } |
lead.stage_changed | { "lead_id": "...", "from_stage": "NEW", "to_stage": "QUALIFYING" } |
tenant.limit_warning | { "usage_percent": 90, "tenant_name": "..." } |
tenant.limit_reached | { "usage_percent": 100, "tenant_name": "..." } |
Headers de cada entrega
Sección titulada «Headers de cada entrega»| Header | Descripción |
|---|---|
X-Overtaker-Event | Nombre del evento (ej. lead.created) |
X-Overtaker-Signature | Firma HMAC-SHA256 del body (ver abajo) |
X-Overtaker-Delivery | UUID de la entrega. Estable entre reintentos — usalo como clave de idempotencia |
X-Overtaker-Version | Versión del formato de webhook (actualmente 1) |
Verificar la firma
Sección titulada «Verificar la firma»El header X-Overtaker-Signature contiene un HMAC-SHA256 del cuerpo crudo de la request, con el formato sha256=<hex>. Verificá sobre los bytes recibidos tal cual — no re-serialices el JSON, o la firma no coincidirá.
Durante una rotación de secret, el header puede traer dos firmas separadas por coma (sha256=<a>,sha256=<b>): la del secret actual y la del nuevo. Aceptá el evento si tu secret coincide con cualquiera de las dos.
import hmacimport hashlib
def verify_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool: """raw_body: bytes exactos de la request (no el dict parseado). signature_header: valor de X-Overtaker-Signature.""" expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() # El header puede traer 1 o 2 firmas: "sha256=a" o "sha256=a,sha256=b" for part in signature_header.split(","): candidate = part.strip().removeprefix("sha256=") if hmac.compare_digest(expected, candidate): return True return FalseReintentos
Sección titulada «Reintentos»Si tu endpoint no responde con 2xx, Overtaker reintenta hasta 4 veces con backoff exponencial: 10s, 30s, 2min, 10min. Cada reintento conserva el mismo X-Overtaker-Delivery, así que tu handler debe ser idempotente. Tras agotar los intentos, el evento se mueve a un dead-letter log.