Webhooks de salida
Donde el canal de webhook de entrada recibe eventos externos para procesar, los webhooks de salida hacen lo contrario: notifican a tus sistemas cuando ocurre un evento notable en betool.
Por qué
Probablemente ya tienes:
- Un sistema de alertas (PagerDuty, Opsgenie, Slack).
- Una herramienta ITSM (Jira, ServiceNow) para gestionar tickets.
- Un dashboard personalizado que agrega tu estado operativo.
En lugar de pedir a estos sistemas que hagan polling de la API de betool, suscríbelos a webhooks de salida: se les notifica al instante cuando ocurre algo.
Configuración
- Administración → Webhooks de salida → Nueva suscripción.
- Elige:
- URL de destino — el endpoint que recibirá los POST.
- Eventos a escuchar — consulta la lista de abajo.
- Secreto HMAC — autogenerado; úsalo en el lado de tu receptor para verificar las firmas.
- (Opcional) Filtros — restringe a las ejecuciones de un pipeline concreto, a un nivel de severidad, etc.
Eventos disponibles
| Evento | Cuándo se dispara |
|---|---|
execution.failed | Una ejecución de pipeline ha fallado |
execution.requires_human | Un nodo confirmation está esperando validación |
execution.cost_threshold | Una ejecución ha superado un umbral de coste |
billing.low_balance | El saldo de créditos ha caído por debajo del umbral configurado |
billing.out_of_credits | El saldo es cero (los rechazos previos a la llamada están activos) |
audit.cross_tenant_read | Un agente externo ha leído contenido de esta organización |
webhook.delivery_failed | Un webhook de salida anterior ha fallado 3 veces |
Formato del POST
POST /your/endpoint HTTP/1.1
Content-Type: application/json
X-Betool-Event: execution.failed
X-Betool-Signature: sha256=...
X-Betool-Delivery: dlv_01HXYZ...
{
"event": "execution.failed",
"delivered_at": "2026-05-24T10:42:13Z",
"org_id": "org_...",
"data": {
"execution_id": "exec_...",
"pipeline_id": "pip_...",
"pipeline_name": "support email triage",
"failed_node": "agent: classifier",
"error_kind": "llm_timeout",
"error_message": "Provider responded after 30s timeout"
}
}
Firma HMAC
La cabecera X-Betool-Signature contiene sha256=<hmac> donde hmac = HMAC-SHA256(secret, body). Verifícala al recibirla para garantizar que la solicitud proviene realmente de betool:
import hmac, hashlib
def verify(body: bytes, signature: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)
Reintento e idempotencia
- Si tu endpoint responde 2xx, el evento se marca como entregado.
- Si no es 2xx o hay timeout, betool reintenta con backoff exponencial (1 min, 5 min, 30 min, 2 h, 12 h, 24 h — 6 intentos como máximo).
- Tras 6 fallos, el evento se marca como dead-letter y se emite un
webhook.delivery_failed(a tus demás suscripciones activas).
Cada POST lleva un identificador X-Betool-Delivery único. Si tu endpoint recibe la misma entrega dos veces (caso límite de red), trátala como idempotente.
Seguridad
- HTTPS obligatorio — las suscripciones en HTTP plano se rechazan.
- Secreto rotable — puedes regenerar el secreto en cualquier momento; los POST en curso que usen el secreto antiguo se seguirán aceptando hasta su expiración (5 min).
- IP de origen — betool publica sus IP de salida en status.betool.fr para que puedas incluirlas en la lista blanca de tu firewall.