call.status_changed
call.status_changed
Emitted every time a voice call on one of your Dial numbers advances to a new lifecycle status. It’s the live, thin counterpart to call.ended: call.status_changed streams each transition as it happens (a call started ringing, was answered, terminated), while call.ended is a one-shot terminal snapshot carrying outcome details like durationSeconds. Wait on call.status_changed to react the moment a call starts or is answered; keep waiting on call.ended if you only care that it finished.
The status payload mirrors the status object returned by GET /api/v1/calls/{id} — the relatedObject.url — so what you see on the stream always matches what a fetch of the call record would show.
Lifecycle states
A call moves forward through these states, never backward:
Queued → Ringing → In-Progress → Terminated
Not every call passes through every state, so don’t build a consumer that requires all four events: an outbound call that fails to connect can jump from Queued straight to Terminated, and some inbound calls first become visible to Dial once they’re already answered — their first event is In-Progress. Every call’s last event is always Terminated.
Schema
Shares the common event envelope (id, object, type, version, createdAt, relatedObject). relatedObject is { id: <callId>, type: "call", url: "/api/v1/calls/<callId>" }. The envelope’s createdAt is when the transition happened. The data payload:
Example
An inbound call being answered:
When it fires
- Once per state a call actually enters, inbound or outbound — at most four events per call, always ending with
Terminated. Deduplicate on the envelopeid; a given call emits each state at most once. - Requesting a cancel does not emit an event — cancellation is a request, not a state. When the cancelled call actually ends, the
Terminatedevent carriesterminationType: "canceled"(or, for an answered call you hung up,terminationType: "completed"withlabel: "Completed (Cancelled)"). - The
Terminatedtransition andcall.endeddescribe the same moment and both fire. They’re intentionally redundant:call.status_changedkeeps the lifecycle stream uniform,call.endedcarries the terminal extras (durationSeconds,canceled,transcriptAvailable). Consume whichever fits, or both — they have distinct eventids. - To catch inbound calls the moment they arrive, filter on
direction: "inbound"and treat the first event you see for acallIdas the arrival — that’sRingingwhen Dial observes the ring, otherwiseIn-Progress.