Skip to navigation

call.ended

View as Markdown

Emitted when a voice call on one of your Dial numbers wraps up. It’s the terminal snapshot: one event per call, carrying the outcome (status, durationSeconds). To follow a call while it’s happening — ringing, answered — listen for call.status_changed, which streams every lifecycle transition; its Terminated transition coincides with this event. The full call record (status, duration, transcript) is available via GET /api/v1/calls/{id} — the relatedObject.url.

Schema

Shares the common event envelope (id, object, type, version, createdAt, relatedObject). relatedObject is { id: <callId>, type: "call", url: "/api/v1/calls/<callId>" }. The data payload:

data fieldTypeDescription
callIdstringDial-issued ID for the call. Matches the id returned by GET /api/v1/calls.
fromstringCalling phone number, E.164.
tostringCalled phone number, E.164.
directionstring"inbound" if someone called your Dial number; "outbound" if the call originated from a dial call / POST /api/v1/calls.
durationSecondsinteger | nullCall duration in seconds. null if the call never connected.
statusstringFinal call status: completed, busy, no-answer, failed, or canceled. Reflects the call’s terminal outcome.
canceledbooleantrue if the call was cancelled (via the dashboard’s terminate button or Stop a call) before it ended — even if the terminal status is completed (an in-progress call that you hang up reports completed). Lets you tell a user-initiated hang-up apart from a natural completion.
failureReasonstring | nullWhy the call failed, when status is failed and Dial knows the cause: self_hosted_key_rejected, self_hosted_agent_not_found, self_hosted_at_capacity, or self_hosted_unreachable. null otherwise. Same value as the call’s failureReason. Treat an unknown value like null.
transcriptAvailablebooleanWhether a transcript exists on the call record yet. When true, a separate call.transcribed event follows once the transcript is processed.

Example

{
"id": "evt_7c1b8a2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b",
"object": "event",
"type": "call.ended",
"version": 1,
"createdAt": "2026-05-28T14:35:21.108Z",
"relatedObject": { "id": "call_01HW3X7P5QF6K2YQ9YJ7Q8R5N3", "type": "call", "url": "/api/v1/calls/call_01HW3X7P5QF6K2YQ9YJ7Q8R5N3" },
"data": {
"callId": "call_01HW3X7P5QF6K2YQ9YJ7Q8R5N3",
"from": "+14155550123",
"to": "+14155559876",
"direction": "inbound",
"durationSeconds": 47,
"status": "completed",
"canceled": false,
"failureReason": null,
"transcriptAvailable": true
}
}

When it fires

  • Every voice call on one of your Dial numbers, inbound or outbound, emits exactly one call.ended once the call reaches its terminal status.
  • Cancelling a call — via the dashboard’s terminate button or Stop a call — also produces a call.ended, carrying data.canceled: true. So a dial wait-for call.ended is always released when the call ends, however it ends.
  • Filter on direction: "inbound" if you only care about calls to your number — see Receive a voice call for the full flow.
  • The event tells you the call is done. To read the transcript or other details, fetch the call record after — data.transcriptAvailable may be false at the instant the event fires and finalize a moment later, at which point a call.transcribed event fires.