# Call Lifecycle

> How a phone call moves through SIP signalling and media setup, and how each stage maps to the CallStatus that your SDK reports.

A phone call has two views that you care about. This page lines them up. On the
wire, the call is a **SIP dialog**: an `INVITE`, some provisional responses, a
`200 OK`, an `ACK`, then media, then a `BYE`. In your code, the call is a single
`CallStatus` that walks `dialing → ringing → in_progress → completed`, or ends
early at `no_answer` or `failed`. Both views name the *same* call by the same
`sid`. This page is the map between them: what each SIP message means, when
the media path comes up, and exactly where an AI agent attaches.

You almost never touch raw SIP. The gateway speaks it for you. But raw SIP
knowledge helps when you read a status, debug a call that never connected, or
decide when it is safe to attach audio. This page tells you which SIP moment
your `CallStatus` reflects.

## The signalling sequence

A back-to-back user agent (B2BUA) in the SIP gateway sits between the caller
and the agent. It terminates the caller's dialog, runs your routing, and drives
the signalling on both legs. For a single leg, the message flow is:

```
   caller / carrier                 SIP gateway (B2BUA)
        │                                  │
        │  ── INVITE (SDP offer) ──────────▶│   dialing
        │  ◀──────────── 100 Trying ────────│   dialing   (gateway got it, working)
        │  ◀──────────── 180 Ringing ───────│   ringing   (far end is alerting)
        │  ◀──── 183 Session Progress (SDP) ─│   ringing   (early media — ringback/IVR audio)
        │  ◀──────────── 200 OK (SDP answer)─│   in_progress  (answered; media negotiated)
        │  ── ACK ─────────────────────────▶│   in_progress  (dialog confirmed)
        │  ══════════ RTP media both ways ══│════════════
        │  ── BYE ─────────────────────────▶│   completed (either side can send BYE)
        │  ◀──────────── 200 OK ─────────────│
```

> **NOTE:**
> For inbound calls, the direction is mirrored. The carrier sends the `INVITE`,
> and the gateway answers with `100` / `183` / `200`. The **state machine is
> identical**. Only the sender of each message flips.

## SIP messages → CallStatus

Your SDK never shows individual SIP messages. It collapses them into the six
statuses on `CallStatus`. The gateway applies this mapping:

| CallStatus     | SIP moment that triggers it                                   | Meaning |
|----------------|---------------------------------------------------------------|---------|
| `dialing`      | `INVITE` sent, `100 Trying`                                   | The call is placed. The far end is not yet alerting. |
| `ringing`      | `180 Ringing` **or** `183 Session Progress`                  | The far end is alerting. Early media (ringback / IVR) may already be audible. |
| `in_progress`  | `200 OK` + `ACK`                                              | The call is answered. Media flows both ways. |
| `completed`    | `BYE` after a `200 OK` (Q.850 normal clearing)               | The call connected and ended normally. |
| `no_answer`    | Ring timeout, `480`, `486 Busy`, or `408` before any `200`  | Nobody picked up, or the line was busy. The call never reached `in_progress`. |
| `failed`       | `4xx`/`5xx`/`6xx` rejection, or media setup failed           | The call could not be set up at all. |

The most important dividing line: **`in_progress` is the only status that
guarantees a live media path.** Everything before it is signalling.
`completed`, `no_answer`, and `failed` are all terminal. `completed` means the
call *connected, then ended*. `no_answer` and `failed` mean the call *never
connected*.

## Media setup: where audio actually comes up

SIP negotiates media with **SDP** (Session Description Protocol): an offer in
the `INVITE`, and an answer in a response. Two details decide when you have
audio:

- **Early media (`183` + SDP).** The gateway answers with `183 Session
  Progress` that carries an SDP answer *before* the call is picked up. This
  opens a one-way media path. The caller hears ringback, a "please hold", or an
  IVR prompt while the call is still in `ringing`. This is why an AI
  receptionist can start to talk the instant a caller connects.
- **Same SDP on `200`.** When the call is answered, the `200 OK` repeats the
  SDP already agreed in the `183`. Nothing re-negotiates, and there is no
  audio gap at pickup.

> **WARNING:**
> The gateway answers with **`183 Session Progress` carrying SDP**, not a bare
> `180 Ringing`. Some carriers drop a call (they send an unsolicited `BYE`) if
> they see a `180` with no media description. If you bridge your own carrier and
> see calls torn down at the ring stage, check this first.

On the wire, phone legs carry **G.711** (µ-law or A-law). The media plane
decodes G.711 to the runtime's **8 kHz PCM16** contract. It re-encodes on the
way back out: G.711 for a phone leg, Opus for a browser or app leg. You never
handle the codec transcoding. See the
[codec guide](/modalities/voice/transport-telephony/codecs) for which codec
rides which transport.

## Where the agent attaches

An AI agent does not wait for the call to be fully answered. The engine wires
it up *during* setup, so there is no dead air at pickup:

  1. **INVITE arrives, routing runs**
On the inbound `INVITE`, the gateway resolves the trunk and asks the routing
    engine what to do. When the decision is "hand this call to an AI agent,"
    the routing engine tells the runtime to start a session for this `sid`. The
    media leg opens on the core that owns the call.
  2. **The provider connection pre-warms**
While the call is still `ringing`, a realtime (speech-to-speech) agent opens
    its model connection ahead of answer, during the `INVITE`/SDP exchange. The
    model is then ready the moment audio flows. A cascade (ASR → LLM → TTS)
    agent opens its provider streams the same way.
  3. **Answer, and audio bridges in**
On `200 OK` + `ACK`, the call is `in_progress`. The engine decodes the
    caller audio to 8 kHz PCM16 and publishes it as the call's **uplink** track
    (`voice/<sid>/uplink`). The engine publishes the agent's replies on the
    **downlink** track (`voice/<sid>/downlink`) and paces them out to the
    caller. The agent is now on the far end of the media bridge.
  4. **The turn loop runs until teardown**
From here, the runtime drives greet → listen → think → speak until someone
    hangs up or a guardrail fires. That inner loop is its own topic — see
    [session lifecycle](/modalities/voice/runtime/session-lifecycle).

You do not write any of this attach logic for a server-side agent. Pass an
`agent` id to `originate`, or configure it on the inbound trunk. That is
enough. The gateway attaches the bridge automatically on answer. If you want to
handle the audio yourself instead, attach an
[`AudioBridge`](/modalities/voice/sdk/javascript) to the same `sid`.

## Following the lifecycle from the SDK

`originate` returns as soon as the call is placed. You get a `Call` in
`dialing`, not a call that is already connected. Read `status`, or fetch a
fresh snapshot with `calls.get`, to follow the call forward:

  
```ts
import { Voice } from "clutchcall_connect/voice";

const v = new Voice({
  baseUrl: "https://engine.firstbyte.fast",
  apiKey:  process.env.CLUTCHCALL_CREDENTIALS!,
  orgId:   "org_abc",
});

// Place the call and hand it to a server-side agent on answer.
const call = await v.calls.originate({
  to:      "+15557654321",
  from:    "+15551234567",
  trunkId: "trunk_default",
  agent:   "sales-qualifier",     // engine attaches the bridge on 200 OK
  ringTimeoutSec: 30,             // → no_answer if unanswered in 30s
});

console.log(call.status);         // "dialing"

// Poll forward (or drive this from lifecycle webhooks — see below).
const now = await v.calls.get({ sid: call.sid });
if (now.status === "in_progress") {
  // media is live; safe to attach audio, start recording, etc.
} else if (now.status === "no_answer" || now.status === "failed") {
  // never connected — retry, fall back, or log
}
```
  
  
```python
from clutchcall.voice import Voice

v = Voice(
    base_url="https://engine.firstbyte.fast",
    api_key=os.environ["CLUTCHCALL_CREDENTIALS"],
    org_id="org_abc",
)

call = v.calls.originate(
    to="+15557654321",
    from_="+15551234567",
    trunk_id="trunk_default",
    agent="sales-qualifier",       # engine attaches the bridge on 200 OK
    ring_timeout_sec=30,           # → no_answer if unanswered in 30s
)

print(call.status)                 # "dialing"

now = v.calls.get(sid=call.sid)
if now.status == "in_progress":
    ...                            # media is live
elif now.status in ("no_answer", "failed"):
    ...                            # never connected
```
  

`ringTimeoutSec` (server-clamped 5–120, default 30) is the ceiling on the
`ringing` stage. If no `200 OK` arrives in time, the gateway gives up. The call
lands on `no_answer` instead of ringing forever.

## Lifecycle events and CDRs

The gateway also emits every transition on the wire to the events pipeline, so
you do not have to poll. Each SIP milestone becomes a call event:
`initiated` (INVITE), ring, `established` (answer), holds and resumes,
`transferred` (a [REFER-based handoff](/modalities/voice/concepts/handoffs)),
and `cleared` (the final `BYE`, carrying the Q.850 cause and the call
duration). On clearing, the gateway also writes a **CDR**. Subscribe to these
events with [webhooks](/modalities/voice/api/webhooks). Read the assembled
per-call timeline in [call traces](/modalities/voice/observability/call-traces).

> **NOTE:**
> **Multi-segment calls.** When a call is handed from an AI agent to a human, or
> back, it stays one `sid`. The events pipeline folds the call into multiple
> *segments* under that one id. Each segment is tagged by the handler that owned
> it. A transfer shows up as one continuous call, not two. See
> [handoffs](/modalities/voice/concepts/handoffs).

## Hanging up

Either side ends the call with a `BYE`. When the caller hangs up, the gateway
tears the dialog down. The runtime session ends, and the call moves to
`completed`. To end the call from your side, call `hangup()`:

```ts
await call.hangup();               // gateway sends BYE → completed
```

Teardown cancels any in-flight model work, flushes the outbound audio, releases
the media leg, and emits the `cleared` event and CDR. The runtime side is
covered in
[session lifecycle](/modalities/voice/runtime/session-lifecycle#ending-and-teardown).

## Related

  - **[Inbound calls](/modalities/voice/transport-telephony/inbound)** — Receive an INVITE from the carrier and route it to an agent.
  - **[Outbound calls](/modalities/voice/transport-telephony/outbound)** — Originate calls and drive them with the paced dialer.
  - **[Handoffs](/modalities/voice/concepts/handoffs)** — Transfer, REFER, and warm handoff without a change of sid.
  - **[Session lifecycle](/modalities/voice/runtime/session-lifecycle)** — The greet → listen → think → speak loop inside in_progress.
  - **[Codec guide](/modalities/voice/transport-telephony/codecs)** — G.711 on the wire, PCM16 inside, Opus to the browser.
  - **[Call traces](/modalities/voice/observability/call-traces)** — The assembled per-call event timeline that you read after the fact.
