state tells you where it is right now, the failureReason tells you why it ended badly, and the timestamps tell you what actually happened on the line. This page is the decoder. Poll session status while the call is live. After it ends, read the same fields plus the session detail.
The states of an outbound call
Three things to know before you build on these:
- Every middle hop is optional. Carriers differ in what they report — a call can jump straight from
dispatchedtoanswered. Never wait for a specific intermediate state. ringingmeans the carrier sent ring progress, not that a phone audibly rang. Some carriers report it milliseconds before a failure.answeredis not proof a human spoke. The line opening sets it — voicemail and phantom answers included. The proof of a human is theansweredAttimestamp, which is stamped only on real callee speech.
created → active → completed instead, and inbound phone calls arrive already active. Neither gets answeredAt or durationSec — those belong to outbound.
Reading the fields
While the call is live, poll session status and readstate. Ignore outcome until the call is terminal: on a call that’s still dialing or ringing, it reads no_answer as a placeholder, not a verdict.
After the call, the same endpoint carries the verdict: state, failureReason, outcome, connected, and endedBy. That last one is agent, callee, or system, or absent when nothing stamped the row. The Call end reasons page has the rules, and the campaign retry policy. For the transcript, tool calls, grade, and recording, read the session detail.
There is no webhook for dial progress, and no call.failed event. call.completed fires when the attempt ends, failed dials included, so polling is the only way to watch a dial unfold.
The timestamps
createdAt— the record exists. For outbound, this is the dispatch moment.dialingAt/ringingAt— carrier progress, when reported.connectedAt— the line opened.answeredAt— a human actually spoke. Outbound only, best-effort.endedAt— hangup.durationSec—answeredAttoendedAt. Absent wheneveransweredAtis.
connectedAt and answeredAt is where phantom answers live: connectedAt set with answeredAt absent means the line opened and nobody spoke.