Webhooks are how the platform notifies your systems when something happens — a session ended, a goal was achieved, a slot was filled, a batch completed. You subscribe by URL; the platform POSTs a JSON payload to that URL when the event fires.
This page describes the events, the delivery contract and the signing scheme. Subscriptions are managed in Connections → Webhooks.
Event catalogue
The following events ship today. Each one carries a stable payload schema documented in the API reference.
Session lifecycle
session.started— fires when a call connects and the agent starts speaking. Carries the session id, scenario id, direction (inbound/outbound), masked phone, and the metadata you passed at trigger time.session.ended— fires when the call ends, regardless of outcome. Carries the session id, outcome (success/middle/spam), duration, and a link to the recording and transcript.session.failed— fires when the session errored out. Carries the session id and a typed failure reason.
Goal & slot progress
goal.achieved— fires the moment the agent reaches the scenario's primary goal. The payload includes the tool call that triggered success and the full slot values at that point. Use this for downstream side effects you want immediately, not at session end.slot.filled— fires whenever a slot transitions from empty to a value. Useful for real-time mirroring of partial progress (e.g. surfacing the customer name in your CRM as soon as it is captured).
Engine signals
intercept.triggered— fires when an intercept handler (silence, interruption, escalation, etc.) ran. Useful for analytics on edge-case frequency.intent.classified— fires when the initial intent classifier picks a scenario on a multi-scenario project. Useful for audit and for measuring classifier accuracy.
Outbound campaigns
outbound.batch.completed— fires when an entire CSV batch finishes processing. Carries the batch id and summary metrics (sent, completed, failed, success rate).
Subscribing
Open Connections → Webhooks → New subscription:
- URL — where you receive POSTs. Must be HTTPS.
- Events — pick from the catalogue. You can subscribe to one event, several, or all.
- Description — free-text label so you remember what this subscription is for.
The platform shows the signing secret once at creation time — copy it into your environment. You cannot retrieve it later; you can rotate (which generates a new secret and invalidates the old after a 24-hour grace).
You can have up to 10 outbound subscriptions per project, and 50 per tenant.
Payload format
Every payload is JSON and shares this envelope:
{
"id": "evt_2c4f8a…",
"type": "session.ended",
"created_at": "2026-05-13T18:42:11Z",
"project_id": "prj_…",
"tenant_id": "tnt_…",
"data": { … }
}
The data object's schema is event-specific. The full schemas live in the API reference. Use id for idempotency on your side — events are delivered at-least-once, so the same id may arrive more than once.
Signing
Every request carries:
X-AVP-Signature—t=<timestamp>,v1=<hex-hmac-sha256>where the HMAC is over<timestamp>.<raw-body>using your subscription's signing secret.X-AVP-Subscription-Id— which subscription this delivery belongs to.X-AVP-Delivery-Id— unique id for this delivery attempt (different per retry).
Verify the signature on every request. Reject any request where:
- The timestamp is more than 5 minutes off the current time (replay protection).
- The HMAC does not match.
A constant-time string comparison is mandatory — naive == is timing-attackable.
Retries and reliability
- At-least-once delivery: the same event may arrive more than once. Use the payload
idfor idempotency. - Timeout: 10 seconds. If your endpoint takes longer, treat the delivery as failed.
- Retry policy: first attempt is immediate; 5 retries with exponential backoff, capped at 6 hours total. After that the delivery is dropped and logged.
- Auto-disable: if a subscription fails 50+ times in 24 hours, the platform disables it and emails the project owner. You re-enable from the UI after fixing your endpoint.
The Webhooks tab shows the delivery log for each subscription — every attempt, every response, the latency, the body received by the platform. Useful for debugging endpoint bugs without instrumenting your side.
Inbound webhooks (the other direction)
You can also expose inbound webhooks that the agent fans out to active sessions. Useful for: notifying an in-progress call that a backend event has happened, pushing a new product price into a live consult, triggering a tool call from outside.
POST /v1/projects/{project_id}/webhooks/{name}
Authorization: Bearer <project-api-key>
Content-Type: application/json
The body is delivered to every session of that project that is active when the request arrives, as an on_webhook_received intercept event. You attach a script (in the scenario's intercept tab) that reads the payload and decides what to do with it.
Limit: 25 inbound webhook names per project. The agent ignores webhooks for names it does not have a handler for.