Webhooks
A webhook is a delivery action defined within a configuration. When an operator produces a result that meets the action's condition, the platform POSTs a JSON envelope to the action's webhook_url. Unlike the session event stream — which delivers everything — webhooks deliver only the results your actions select.
You define a webhook action with a webhook_url, an optional set of webhook_headers, and an optional condition. See Actions for conditions and once_per_session.
The envelope
Every delivery has the same shape:
{
"session_id": "abc-123",
"configuration_id": "5f1c…",
"customer_metadata": { "your_ref": "xyz" },
"fired_at": "2026-06-17T10:30:00.000Z",
"type": "operator_result",
"action": { "index": 2, "once_per_session": true },
"data": { },
"evaluated": {
"fraud-confidence": { "result": { "value": 84 }, "confidence": 0.91, "call_elapsed_seconds": 42.0 }
}
}
type— the kind of operator event that triggered delivery:operator_resultoroperator_error.data— the full operator event that triggered the action. This is the same payload the session stream carries: see theoperator_resultandoperator_errorshapes.evaluated— a per-operator summary (result,confidence,call_elapsed_seconds) of every operator the condition tested, so you can see exactly what satisfied it.nullfor an unconditional action.customer_metadata— echoed verbatim from the value you supplied when the session was created;nullif none was set.action.index— the action's position in the configuration. When several actions post to the same URL, use it together withsession_idto tell deliveries apart.fired_at— thetimestamp_utcof the triggering operator event.
Unconditional actions also fire on operator_error, where data has no result. Conditions that test result never match an error, so a conditional action only delivers operator_result. Read type before reading data.
Delivery
Each delivery is a single HTTP POST with a JSON body (Content-Type: application/json) and any webhook_headers you configured on the action. Your endpoint should return a 2xx status promptly — do slow work asynchronously after acknowledging. The platform waits up to 10 seconds for a response.
Retries
| Outcome | Behaviour |
|---|---|
| 2xx / 3xx | Treated as delivered. |
| 4xx | Permanent failure — not retried (a client error won't be fixed by retrying). Check your endpoint and headers. |
| 5xx, timeout, or network error | Retried with backoff. |
Retried deliveries are attempted up to 3 times: the initial attempt, then again after roughly 5 seconds, then after roughly 30 seconds. If all three fail, the delivery is abandoned and logged.
Delivery is at-least-once. A retry can deliver the same event more than once, and an endpoint that is slow to acknowledge (but eventually succeeds) may still be retried. Make your handler idempotent — deduplicate on the triggering event id (data.event_id) together with action.index. For at-most-once-per-call business logic, set once_per_session on the action.
Securing your endpoint
Deliveries are not signed. To verify a request genuinely came from the platform:
- Set a secret on the action's
webhook_headers— for example{ "Authorization": "Bearer <your-shared-secret>" }— and check it on every request. - Serve your endpoint over HTTPS.
- Don't trust the payload's identifiers for authorisation on their own; gate on the shared secret first.