Documentation

Outbound webhooks

Notify your external systems on betool events — failed execution, low balance, human validation required.

Outbound webhooks

Where the inbound webhook channel receives external events to process, outbound webhooks do the reverse: they notify your systems when a notable event occurs in betool.

Why

You probably already have:

  • An alerting system (PagerDuty, Opsgenie, Slack).
  • An ITSM tool (Jira, ServiceNow) to manage tickets.
  • A custom dashboard that aggregates your operational status.

Rather than asking these systems to poll the betool API, subscribe them to outbound webhooks: they are notified instantly when something happens.

Configuration

  1. Administration → Outbound webhooks → New subscription.
  2. Choose:
    • Target URL — the endpoint that will receive the POSTs.
    • Events to listen to — see the list below.
    • HMAC secret — auto-generated; use it on your receiver side to verify signatures.
  3. (Optional) Filters — restrict to executions of a specific pipeline, to a severity level, etc.

Available events

EventWhen it fires
execution.failedA pipeline execution has failed
execution.requires_humanA confirmation node is awaiting validation
execution.cost_thresholdAn execution has exceeded a cost threshold
billing.low_balanceThe credit balance has dropped below the configured threshold
billing.out_of_creditsThe balance is zero (pre-call refusals are active)
audit.cross_tenant_readAn external agent has read content from this organisation
webhook.delivery_failedA previous outbound webhook has failed 3 times

POST format

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"
  }
}

HMAC signature

The X-Betool-Signature header contains sha256=<hmac> where hmac = HMAC-SHA256(secret, body). Verify it on receipt to ensure the request genuinely originates from 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)

Retry & idempotency

  • If your endpoint responds 2xx, the event is marked as delivered.
  • If non-2xx or timeout, betool retries with exponential backoff (1 min, 5 min, 30 min, 2 h, 12 h, 24 h — 6 attempts maximum).
  • After 6 failures, the event is marked dead-letter and a webhook.delivery_failed is emitted (to your other active subscriptions).

Each POST carries a unique X-Betool-Delivery identifier. If your endpoint receives the same delivery twice (network edge case), treat it as idempotent.

Security

  • HTTPS required — plain HTTP subscriptions are refused.
  • Rotatable secret — you can regenerate the secret at any time; in-flight POSTs using the old secret will still be accepted until expiry (5 min).
  • Source IPs — betool publishes its outbound IPs on status.betool.fr so you can allow-list them at your firewall.