Session webhooks
Get a request when a call or chat starts, when it ends, and when its analysis is ready — for every flow, or per flow.
Session webhooks push each conversation's lifecycle to your own endpoint, so your systems react as it happens instead of polling for results.
Events
| Event | Sent when |
|---|---|
OnSessionBegin | A call or chat starts |
OnSessionEnd | It ends — with how it ended and what was collected |
OnAIAnalysisReady | Post-conversation analysis, such as structured outputs, has finished |
Most integrations only need OnAIAnalysisReady: it arrives after the conversation is
over and the extracted fields exist.
Where to configure them
- Workspace-wide, as the default for every flow.
- Per flow, overriding the workspace default.
For each, choose which events to send, and whether to send them for inbound sessions, outbound sessions or both.
Note
Session webhooks belong to saved flows. A call started with an inline flow over the API does not run them.
The request
urlhttpsRequiredYour endpoint. Addresses on localhost are rejected.
methodPOST | PUT | PATCH | GETPOST unless your endpoint expects something else.
headersobjectHeaders added to every request — this is where authentication for your endpoint goes,
such as an Authorization header or an API key your endpoint checks.
customBodytemplateOptional. Replace the default payload with a body shaped for the system receiving it.
Every request carries two headers:
X-Kilevel-Event-Type: OnSessionEnd
X-Kilevel-Event-Id: <unique event id>The payload
The default payload identifies the event and the session, and carries what is known at that point. An abridged example for a call:
{
"eventId": "…",
"eventName": "OnSessionEnd",
"sessionType": "call",
"flowApiId": "f_sales_voice",
"callerPhoneNumber": "+15551234567",
"callStatus": "ENDED",
"startedAt": "2026-09-14T09:12:03Z",
"endedAt": "2026-09-14T09:15:41Z",
"endedReason": "customer-ended-call",
"sessionMemory": {
"appointmentDate": "2026-09-18"
}
}sessionMemory holds the values the conversation collected. Fields present depend on the
event and the channel; treat any field you do not recognise as optional.
Handling them
- Answer with a
2xxstraight away and do the work afterwards. - Deduplicate on
X-Kilevel-Event-Id. - Fetch anything the payload does not include — the full transcript, the recording — from the API using the identifiers in the payload.