# Inbound Calls

> Receive calls from the phone network: how the SIP gateway answers, publishes the same voice tracks as an outbound call, and routes to an agent or a human.

When a caller dials one of your numbers, FirstByte Voice answers the carrier
for you. It hands the call to the destination that you pointed the number at: an
AI agent, a human queue, a prompt, or your own code. The one idea to remember:
**an inbound call is the same object as an outbound one.** The SIP gateway runs
the call as a back-to-back user agent (B2BUA). It decodes the carrier's audio
and publishes it onto the same tracks that an outbound call uses:

```
voice/<sid>/uplink     caller → cloud   (what the caller is saying)
voice/<sid>/downlink   cloud → caller   (what is played back)
```

As a result, every SDK primitive that you already know works on an inbound
`sid` unchanged: attach an agent, open an
[AudioBridge](/modalities/voice/api/transport), `transfer`, `hangup`. There is
**no separate inbound media API**. The only inbound-specific decision is what
happens at the moment the gateway answers the call.

## How the gateway answers

You do not send provisional or final responses yourself. The gateway sends
them, in the exact sequence that carriers expect:

  1. **100 Trying**
The gateway acknowledges the carrier's `INVITE` immediately, so the trunk
    does not retransmit.
  2. **183 Session Progress (with SDP)**
This is an early-media answer that carries the negotiated SDP. It opens the
    media path **before** the call is picked up. A ringback tone or an agent
    greeting can play during ringing.
  3. **200 OK (same SDP)**
This is the final answer. The gateway reuses the SDP that it already
    offered at `183`.

> **WARNING:**
> The answer always carries SDP on `183`/`200`. An SDP-less `180 Ringing` makes
> many carriers tear the call down with a `BYE`, so FirstByte never sends one.
> If you bring your own trunk, check that your carrier accepts early media with
> SDP — see [SIP trunking](/modalities/voice/transport-telephony/sip-trunking).

After the gateway answers, it decodes the carrier's G.711 (µ-law/A-law) audio
to the internal format. It publishes the audio on `voice/<sid>/uplink`. The
audio that you publish on `voice/<sid>/downlink` is paced back to the caller.
The full state machine — ring, answer, hold, transfer, clear — is on
[Call lifecycle](/modalities/voice/transport-telephony/call-lifecycle).

## Decide what happens on answer

Each trunk (or number) carries an **inbound rule**. The gateway reads the rule
when a call arrives:

| Rule                | What the gateway does                                                        |
| ------------------- | ---------------------------------------------------------------------------- |
| `HANDLE_AI`         | Auto-bridge the call to a server-side agent. The gateway attaches the runtime for you. |
| `PLAY_AND_HANGUP`   | Play a prompt (an audio URL), then hang up. No agent, no bridge.               |
| `NOTIFY_AND_HANGUP` | Notify your app of the incoming call, so that **you** answer and drive it.    |
| `REJECT`            | Refuse the `INVITE`. Use this for numbers that must never receive calls.      |

Most teams never set this rule directly. In the Contact Center console at
`agent.firstbyte.fast`, you assign a number (or trunk) to an agent, a skill
queue, or an IVR program. The console sets the rule for you. The rest of this
page shows each path.

## Route to an AI agent (the common case)

Point a number at an agent, and you are done. The gateway answers, attaches the
runtime, and wires the audio bridge end to end. **Your process never touches
the media.** This is `HANDLE_AI`.

  
    In **agent.firstbyte.fast**, open the number under **Numbers**. Set **On
    inbound → AI agent**. Pick the agent that you built (e.g.
    `support-frontline`). Save. The next call to that number reaches the agent.
    See [Build a voice agent](/modalities/voice/build/voice-agents).
  
  
```python
from clutchcall.method_id import InboundRule

# native-core control client, connected to your engine RPC endpoint
await client.set_inbound_routing(
    trunk_id="trunk_main",
    rule=InboundRule.HANDLE_AI,
    ai_quic_url="agent://support-frontline",   # the agent to bridge to
)
```
  
  
```go
err := client.SetInboundRouting(
    "trunk_main",
    github.com/clutchcall/clutchcall-sdk/go.InboundRule_HANDLE_AI,
    "",                       // audioUrl
    "",                       // webhookUrl
    "",                       // aiWebsocketUrl
    "agent://support-frontline", // aiQuicUrl
)
```
  

> **NOTE:**
> Programmatic `set_inbound_routing` lives in the **native SDK cores** (Python,
> Go, Rust). The browser/TypeScript SDK does not carry this low-level RPC. For
> TypeScript apps, configure inbound routing in the console (or in your
> control-plane provisioning). Then handle the resulting call with the
> high-level `Voice` client.

The agent runs entirely server-side, so the runtime handles turn-taking,
barge-in, and tool calls for you. Tune them in
[Turn detection](/modalities/voice/concepts/turn-detection) and
[Tool calling](/modalities/voice/runtime/tool-calling).

## Route to a human or a queue

To send inbound callers to people, point the number at a **skill queue** or an
**IVR program (VDN)** instead of an agent. The gateway answers. The dialplan
runs your IVR steps: announcements, digit collection, `queue_to_skill`. The ACD
picks the next eligible agent, on a browser softphone or a real SIP deskphone.
This is all configuration. You write no media code.

  - **[PBX / ACD](/modalities/voice/transport-telephony/pbx-acd)** — Skills, VDNs, IVR vectors, and the agent picker behind human routing.
  - **[AI → human handoff](/modalities/voice/transport-telephony/ai-human-handoff)** — Let an AI agent qualify the caller, then warm-transfer to a person.

A common pattern is to answer with AI first and then escalate. The agent
gathers intent and identity. It then calls a queue-transfer tool to hand the
live call to a human.

## Handle the call in your own process

Use `NOTIFY_AND_HANGUP` when your own service must answer and drive inbound
audio instead of a prebuilt agent. The gateway tells your app about each
incoming call. You answer the call. You then attach an
[AudioBridge](/modalities/voice/api/transport) to the resulting `sid`, exactly
as you would for an outbound call. This is the "inbound == outbound" payoff.

  1. **Set the rule to notify**
Configure the trunk with `NOTIFY_AND_HANGUP`. Optionally, set a
    `webhook_url`. The gateway POSTs incoming-call events to that URL.
  2. **Receive the incoming call**
Get the caller and the `sid` from your webhook. Or pull queued calls on
    the native core (`get_incoming_calls`). Those results arrive on your event
    stream.
  3. **Answer, then bridge**
Accept the leg with `answer_incoming_call`. Then subscribe `uplink` and
    publish `downlink` through an AudioBridge on that `sid`.

  
```python
from clutchcall.method_id import InboundRule

await client.set_inbound_routing(
    trunk_id="trunk_main",
    rule=InboundRule.NOTIFY_AND_HANGUP,
    webhook_url="https://ops.example.com/hooks/inbound",
)

# In your event handler, when an incoming call arrives for this trunk:
async def on_call_event(ev):
    if ev.type == "CHANNEL_CREATE":
        # Accept the leg (empty AI URLs → you drive the media yourself).
        await client.answer_incoming_call(ev.call_sid)
        # From here, open an AudioBridge on ev.call_sid and read/write frames.
```
  
  
```ts
import { Voice } from "clutchcall_connect/voice";

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

// Your webhook handed you the inbound call's sid.
export async function handleInbound(sid: string) {
  const bridge = await v.audioBridge.attach(sid, {
    codec: "pcm16",
    onUplink: (frame, tsUs) => {
      // caller audio → your ASR / model
    },
  });
  // reply → the caller
  bridge.publishDownlink(replyPcm, Date.now() * 1000);
  return bridge;
}
```
  

> **NOTE:**
> The `attach` half of the AudioBridge is written from the **server's** point of
> view. You **subscribe** `uplink` to hear the caller. You **publish** `downlink`
> to talk to the caller. This is the same handle that an outbound call gives
> you — see
> [Sessions, calls, tracks & streams](/modalities/voice/concepts/sessions-calls-tracks-streams).

## Where routing decisions live

The gateway does not hardcode any of this. On answer, the gateway asks the
engine's **dialplan** what to do with the call. The dialplan is a hot-reloaded
rule engine, keyed by DID and then by source IP. The result can be: play a
prompt, start an AI bidirectional stream, or enter an IVR vector. When you edit
a number's routing in the console, the rules update within seconds. In-flight
calls keep the behavior that they started with. Trunk `INVITE`s bypass the
registrar's access control. Everything else is gated by digest auth, source-IP
ACLs, and a spam filter (see
[SIP trunking](/modalities/voice/transport-telephony/sip-trunking)).

## Related

  - **[Number provisioning](/modalities/voice/transport-telephony/number-provisioning)** — Buy, import, and assign the numbers that callers dial.
  - **[Outbound calls](/modalities/voice/transport-telephony/outbound)** — The mirror of this page: originate calls and run the paced dialer.
  - **[Call lifecycle](/modalities/voice/transport-telephony/call-lifecycle)** — Ring, answer, hold, transfer, and clear — the full state machine.
  - **[Audio bridge API](/modalities/voice/api/transport)** — Subscribe uplink and publish downlink on any `sid`.
