> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Voice call lifecycle: initiated to completed, and the states in between

> How a call moves from your API request or an inbound ring through ringing, answered, and completed (or a failure outcome), who advances each transition, how the mid-call events fit in, and the status-vs-event distinction you need before you build reporting against call data.

# Voice call lifecycle

Every call that crosses Orbit — placed by your app through the API, dialed by a campaign, or dialed by a customer into one of your numbers — carries a `status` field on the call record that advances as the call moves toward completion or a failure outcome. This page explains that state machine at the concept level: what the states mean, what advances each transition, and where the edges are. Read it before you subscribe to call webhooks or build reporting against call outcomes.

This is the voice counterpart to [Delivery lifecycle](/concepts/delivery-lifecycle) for messaging. The per-payload webhook contract for every `call.*` event lives in the [webhook events reference](/reference/webhook-events); the request and response fields for placing and controlling calls live in the [Voice API reference](/api-reference/endpoints/voice). This page ties the two together without restating them.

## The happy path

An outbound call that succeeds end-to-end passes through:

`initiated → ringing → answered → completed`

Each transition is advanced by a different actor — no single party sees the whole arc:

| Transition             | Meaning                                                                                       | What advances it                                                                                                                                                                                                                                 |
| ---------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `initiated → ringing`  | The call record exists and the network has started the far end ringing.                       | The voice engine, at call placement. Calls placed through a dialer or agent queue first sit in `queued` and take this step when a worker dials them. For inbound calls this fires when the call arrives at the platform, before anyone picks up. |
| `ringing → answered`   | A party picked up — the called handset, an agent, an AI voice agent, or an answering machine. | The answer signal from the network or the receiving party.                                                                                                                                                                                       |
| `answered → completed` | The call ended cleanly after talking.                                                         | The hangup — whichever side ends it.                                                                                                                                                                                                             |

One actor sits beside this path and rewrites the tail of it:

* **The AMD screening.** On outbound calls with answering-machine detection enabled, an answer can resolve to a machine, a fax tone, or a carrier voicemail screen instead of a person. That fires a `call.hit_voicemail` event immediately, so campaigns and AI voice agents can abandon, retry, or branch without waiting for the call to end. The call itself still ends at `completed` (or a failure status) — the event is a branch signal, not a status.

Inbound calls take the same arc in the other direction: an inbound ring moves to `ringing` (with a `call.ringing` event so your dashboard can paint an incoming-call UI before anyone answers), then to `answered` when an agent, an AI voice agent, or a phone tree picks up, then to `completed` on hangup.

## Status vs. event

The distinction that matters most for integrations is between the call's **status** — a field on the call record — and the **`call.*` events** — webhooks emitted as the record advances:

| Status (on the record) | Event (webhook)                                                                            |
| ---------------------- | ------------------------------------------------------------------------------------------ |
| `ringing`              | `call.initiated` (and `call.ringing` for inbound, so you can render "incoming call" early) |
| `answered`             | `call.answered`                                                                            |
| `completed`            | `call.completed`                                                                           |
| `failed`               | `call.failed`                                                                              |
| `transferred`          | `call.transferred`                                                                         |

Three rules follow:

1. **Statuses and events track the same arc, but statuses are more granular.** Failure statuses (`no-answer`, `busy`, `canceled` on an outbound call you abandoned before answer) all surface as terminal statuses, and any of them also reports through `call.failed` webhooks. Branch on the webhook type for "something changed" and on the status for "which outcome."
2. **Mid-call events carry no status change.** A transfer inside a live call, a DTMF sequence injected mid-call, a recording paused and resumed, an agent-assisted secure-payment session — these emit `call.transferred`, `call.dtmf_sent`, `call.recording.paused`, `call.recording.resumed`, and the `call.secure_payment.*` family while the call record stays at `answered`. Use them for audit trails and dashboards; never treat them as a lifecycle advance.
3. **Screening events are branch signals, not outcomes.** `call.hit_voicemail` fires mid-arc; the status it foreshadows arrives when the call actually ends.

## Failure outcomes

A call that never completes talking resolves to a terminal failure status:

* **`no-answer`** — the far end rang but nobody picked up inside the timeout.
* **`busy`** — the far end rejected the call as busy.
* **`failed`** — the network or the platform could not advance the call (routing failure, rejected destination, wallet out of credit at placement).
* **`canceled`** — your app or dialer abandoned the call before it was answered (an API cancel, a campaign stop, a queue caller hanging up).

Every one of these emits a `call.failed` webhook with the specific status on the payload, so a subscriber can keep failure-rate metrics per cause rather than per generic failure event.

## Concurrency and transfer states

A live call does not have to stay a two-party line:

* **A transfer** between agents or to an external number moves the call through `transferred` (and a `call.transferred` event per leg) while the call itself remains answered.
* **A consult-then-transfer** parks the caller on hold while the agent speaks to the target, then either bridges all three parties or completes a cold transfer — the status arc runs `answered → on_hold → consulting → answered → completed`.
* **A conference** has its own event family — `conference.created`, `conference.participant_joined`, `conference.participant_left`, `conference.ended` — because a conference room is not scoped to a single call. If your product builds "who is on this call right now" UI, consume the conference events rather than inferring membership from call statuses.
* **A recording** follows its own lifecycle beside the call: `recording.started` (or `call.recording.ready` once the file lands), `recording.failed` on a capture failure, and `call.recording.paused` / `call.recording.resumed` when an operator pauses capture mid-call. A recording event never implies a call status — a paused recording is not a held call.

## What to branch on

Integrations should switch on machine-readable fields only, never on display labels:

* **`call_id`** — the join key across every event in a call's life. All lifecycle, mid-call, and recording events for one call carry it; reconcile by id, not by arrival order.
* **event `type`** — the primary branch point on webhooks. Handle the full lifecycle set (`call.initiated`, `call.ringing`, `call.answered`, `call.completed`, `call.failed`) plus the mid-call family (`call.transferred`, `call.dtmf_sent`, `call.recording.paused`, `call.recording.resumed`, `call.hit_voicemail`, `call.disclosure.omitted`) if you subscribe to them.
* **`status` on the record** — read it from `GET /calls` responses or from the webhook payload when you need the specific terminal outcome. Keep failure-cause metrics per status, not per event type.
* **AMD / hit-voicemail** — treat `call.hit_voicemail` as "decide now," and treat the terminal status as "the call closed," so an abandoned machine call and a completed machine call are both countable.

## Common pitfalls

1. **Treating `call.initiated` as acceptance of a human conversation.** It fires at ring time for outbound and at arrival for inbound — before any answer. A call that ends `no-answer` still fired `call.initiated`. Pair it with `call.answered` before you conclude anyone spoke.
2. **Waiting for a failure-specific event per cause.** There is one `call.failed` event type for every failure outcome; the cause is the status on the payload. Branch on `data.status`, not the event type, when you separate `no-answer` (retry-worthy) from `failed` (a routing or policy problem).
3. **Assuming exactly one terminal event per call.** A mid-call event can arrive after your system has ingested `call.completed` — a late `call.recording.paused` audit line, for example. Apply webhook updates idempotently keyed on `call_id` and let the terminal status close your record.
4. **Inferring conference membership from call statuses.** A call leg entering a conference does not change the leg's status in a way you can derive occupancy from; that is exactly what the `conference.*` event family is for. Consume those events for membership, and call statuses for the leg's own outcome.
5. **Missing the early inbound signal.** For inbound calls, `call.ringing` fires before `call.answered` specifically so an incoming-call popup does not wait for pick-up. If your agent UI subscribes only to `call.answered`, agents see the call at the same moment they are supposed to answer it.

Once the state machine is clear, the per-event payloads are in the [webhook events reference](/reference/webhook-events), and the endpoint-level call fields are in the [Voice API reference](/api-reference/endpoints/voice).
