Webhooks are how the platform notifies your systems when something happens — a call started, a session ended, a goal was achieved. 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 your project's Webhooks tab.
Event catalogue
Five events ship today:
session.started— fires when a call connects and the agent starts speaking. Carries the session id, scenario id, direction (inbound/outbound), the caller's phone number (masked, e.g.+3412•••789— the full number is available viaGET /v1/sessions/{id}) and whether it is a test session.session.ended— fires when the call ends. Carries the session id, the final status (completed/abandoned/failed), the duration and whether the goal was achieved. Fetch the full session record — transcript, slots, outcome — viaGET /v1/sessions/{id}.session.failed— fires when the session errored out. Carries the session id and the failure reason.goal.achieved— fires the moment the agent reaches the scenario's goal, mid-call, once per session. The payload includes the goal definition and the slot values captured up to that point. Use this for downstream side effects you want immediately, not at session end.intent.classified— fires when the intent classifier picks a scenario on a multi-scenario project. Useful for audit and for measuring routing accuracy.
Webhooks cover voice sessions today; events for messenger conversations and batch completion are on the roadmap.
Subscribing
In the project's Webhooks tab, create a subscription:
- URL — where you receive POSTs. Must be HTTPS.
- Events — pick from the catalogue. One event, several, or all.
The platform shows the signing secret once at creation time — copy it into your environment. You cannot retrieve it later; you can rotate, which replaces the secret immediately (update your endpoint first, then rotate).
You can have up to 10 subscriptions per project.
Payload format
Every payload is JSON and shares this envelope:
{
"event": "session.ended",
"deliveryId": "5b2c4f8a-…",
"ts": "2026-05-13T18:42:11Z",
"tenantId": "…",
"projectId": "…",
"data": { … }
}
The data object's schema is event-specific. Deliveries are at-least-once, and deliveryId is stable across retries of the same event — use it for idempotency on your side.
Signing
Every request carries these headers:
x-avp-signature—sha256=<hex>where the hex value is an HMAC-SHA256 of the raw request body, keyed with your subscription's signing secret.x-avp-event— the event type, so you can route before parsing.x-avp-timestamp— when the delivery was sent.x-avp-subscription-id— which subscription this delivery belongs to.x-avp-delivery-id— same value asdeliveryIdin the body.
Verify the signature on every request: compute the HMAC of the raw body with your secret and compare against the header. A constant-time string comparison is mandatory — naive == is timing-attackable. Reject anything that does not match.
Retries and reliability
- At-least-once delivery: the same event may arrive more than once. Use
deliveryIdfor idempotency. - Timeout: 10 seconds. If your endpoint takes longer, the delivery counts as failed.
- Retry policy: first attempt is immediate, then 5 retries with growing backoff (1 min → 5 min → 15 min → 1 h → 6 h). After the last retry the delivery is dropped and logged.
- Auto-disable: if a subscription keeps failing permanently (50+ dropped deliveries within 24 hours), the platform disables it. You re-enable it from the Webhooks tab after fixing your endpoint.
The Webhooks tab shows the delivery log for each subscription — every attempt, the response status, the latency, an excerpt of your endpoint's response. There is also a send test delivery action so you can verify your endpoint before real traffic hits it.
Inbound webhooks (the other direction)
You can also push events into live conversations. Create an inbound webhook in your project with a name; the platform gives you a URL and a dedicated signing secret (shown once).
POST /v1/projects/{project_id}/webhooks/{name}
x-avp-signature: sha256=<hex-hmac-of-raw-body>
Content-Type: application/json
Sign the raw body with the inbound webhook's secret, the same HMAC-SHA256 scheme as outbound deliveries. The body is delivered to every session of the project that is active when the request arrives, as an on_webhook_received intercept event; a script attached to that event reads the payload and decides what to do — notify the agent mid-call that an order shipped, push a price change into a live consult, trigger a tool call from outside.
Limits: 25 inbound webhook names per project. Requests to a name that does not exist return 404; sessions without an on_webhook_received handler ignore the event.