Event reference

The body of every webhook event, the call record it carries, and how to handle ordering.

Every event is a JSON POST to your endpoint. See Webhooks for signing, retries and the delivery log.

Call events

call_started, call_ended and call_analyzed share one body:

json
{
  "event": "call_ended",
  "call_id": "6f1d0c2e-0b8a-4c7e-9d58-2a1e3f4b5c6d",
  "agent_id": "46fd9050-816b-452c-b590-68d19e6e7340",
  "call": { }
}

call is the full call record as it was when the event was sent.

EventNotes
call_startedThe call connected.
call_endedSent as soon as the call ends. analysis is still null.
call_analyzedSent after call_ended, once analysis has run, and only for calls that produced a transcript. analysis is filled in.

Transcript updates

transcript_updated is sent after each turn while the call is live. It adds three fields:

json
{
  "event": "transcript_updated",
  "call_id": "…",
  "agent_id": "…",
  "call": { },
  "role": "user",
  "turn_index": 4,
  "transcript": [
    { "role": "agent", "text": "Thanks for calling.", "timestamp": "2026-11-07T22:15:40.425782" },
    { "role": "user", "text": "I'd like to book a cleaning.", "timestamp": "2026-11-07T22:15:44.100000" }
  ]
}
  • role is who spoke the turn that triggered this event.
  • turn_index goes up by one per event within a call. Keep the highest one you have seen.
  • transcript is the whole transcript so far, so a delivery you missed or received out of order still leaves you correct.

This event is high volume. Subscribe only if you need live text. It is not sent for an agent that has transcript storage turned off.

Transfer events

transfer_started, transfer_bridged, transfer_cancelled and transfer_ended add a transfer object. Fields appear only when known.

json
{ "event": "transfer_started", "call_id": "…", "agent_id": "…", "call": { },
  "transfer": { "target": "+14155550100", "mode": "warm" } }
FieldMeaning
targetThe number the call is going to.
modecold or warm.
reasonWhy a transfer was cancelled: a carrier status such as busy or no-answer, or a failure reason.
EventWhen
transfer_startedThe agent asked for the call to be transferred.
transfer_bridgedThe other person answered and was connected. For a cold transfer this arrives when the transferred leg finishes, followed at once by transfer_ended.
transfer_cancelledThe transfer did not connect: busy, no answer, failed, or could not be placed.
transfer_endedA connected transfer finished.

Chat events

chat_started, chat_ended and chat_analyzed carry chat_id and chat (the full chat with its messages) instead of call_id and call.

Campaign events

campaign_started, campaign_paused, campaign_resumed, campaign_completed and campaign_cancelled go to webhook endpoints only, and carry a campaign object instead of call.

The call record

The same object appears in these events and in the API's call responses.

FieldTypeMeaning
idstringThe call's id.
agent_id, agent_namestringThe agent. agent_id is empty if the call had none.
agent_versionnumberThe version the call ran. 0 is the live draft.
statusstringactive, queued, completed or failed.
call_statusstringThe same state as ongoing, registered, ended or error.
call_typestringphone_call or web_call.
directionstringinbound or outbound.
metadataobjectYour data, set when the call was created or later.
dynamic_variablesobjectThe variables the call started with.
started_at, ended_atstringUTC, ISO 8601 with no timezone suffix. ended_at is null while ongoing.
start_timestamp, end_timestampnumberEpoch milliseconds.
duration_s, duration_msnumberLength of the call.
from_number, to_number, phone_numberstringThe numbers involved.
call_sidstringThe carrier's call id, or empty.
transcriptarrayOne entry per turn: role (user or agent), text, timestamp. Empty when transcript storage is off, or after retention has purged it.
transcript_textstringThe same transcript as Agent: … and User: … lines.
recording_urlstring or nullA short-lived signed link. Download promptly instead of storing it.
disconnection_reasonstring or nullWhy it ended. See below.
in_voicemailbooleanWhether it reached a machine.
analysisobject or nullPost-call analysis. See below.
call_costobject or nullSet when the call is finalized. See below.
end_to_end_latency_msnumber or nullAverage time from the caller finishing to the agent's first audio.
latencyobject or nullPer-stage percentiles (e2e, llm, tts, endpointing), each with p50, p90, p95, p99, min, max, num.

Disconnection reasons

user_hangup, agent_hangup, call_transfer, voicemail_reached, inactivity, max_duration_reached, manual_stopped, dial_no_answer, flow_dead_end, flow_loop_guard and error. Treat the list as open: new reasons can be added, so handle an unknown value.

Analysis

FieldMeaning
call_summaryOne to three sentences.
user_sentimentPositive, Neutral or Negative.
call_successfultrue or false.
variablesValues for the fields you defined in post_call_analysis_data, keyed by name.
model, extracted_atThe model used, and when.
errorSet if extraction failed. variables may then be partial.

Cost

Amounts are integers in units of $0.0001, so combined_cost: 1700 is $0.17.

FieldMeaning
combined_costThe total for the call.
total_duration_secondsBilled length.
total_duration_unit_priceThe combined per-minute rate.
product_costsOne entry per part of the price, each with product (such as platform), unit_price and cost.

See Billing and pricing for what the parts are.

Handling events well

  • Verify first. Check the signature against the raw body before you parse anything.
  • Deduplicate. The same delivery can arrive more than once. Use X-Dialgem-Delivery.
  • Expect disorder. call_analyzed can be followed by a late retry of call_ended. Compare ids and timestamps rather than arrival order.
  • Answer quickly. Return 2xx once the event is stored and work after.