# Receive an Inbound Call

> Answer an inbound call. Route it to an AI agent or a human, or bridge the caller audio into your own code. All paths key on the same voice/`<sid>` tracks.

This page gives copy-paste snippets for calls that arrive from the phone
network. Hold onto one idea: **an inbound call is the same object as an outbound
one.** The SIP gateway answers the carrier for you. It publishes the caller's
audio onto the same tracks:

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

For this reason, every primitive below works on an inbound `sid` unchanged:
attach an agent, open an audio bridge, `transfer`, or `hangup`. For the full
answer sequence and routing model, read
[Inbound calls](/modalities/voice/transport-telephony/inbound). Each snippet
assumes a `Voice` client:

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

const v = new Voice({
  baseUrl: "https://engine.firstbyte.fast",
  apiKey:  process.env.CLUTCHCALL_CREDENTIALS!,
  orgId:   "org_abc",
});
```
  
  
```python
import os
from clutchcall.voice import Voice

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

## Route a number to an AI agent

This is the common case. Point a number or trunk at a server-side agent, and you
are done. The gateway answers, attaches the runtime, and connects both audio
legs. **Your process never touches the media.** On a native core, set the
trunk's inbound rule to `HANDLE_AI`. For TypeScript apps, do this in the console
at **agent.firstbyte.fast** instead.

  
```python
from clutchcall.method_id import InboundRule

# `client` is the 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:**
> `set_inbound_routing` is a low-level RPC on the **native SDK cores** (Python, Go,
> Rust). The browser/TypeScript SDK does not carry it. Configure inbound routing
> in the console or in your provisioning pipeline. Then handle the resulting call
> with the high-level `Voice` client. See
> [Build a voice agent](/modalities/voice/build/voice-agents).

## Attach an agent to a live inbound call

You possibly already have the `sid` from a webhook or your event stream. You can
bind an agent to it in the middle of the call, for example after your own IVR
gathers intent. The engine connects the bridge for you.

  
```ts
await v.agents.attach(sid, "billing-bot");
```
  
  
```python
v.agents.attach(sid, "billing-bot")
```
  

The server handles turn-taking, barge-in, and tool calls. Tune them in
[Turn detection](/modalities/voice/concepts/turn-detection) and
[Tool calling](/modalities/voice/runtime/tool-calling).

## Route to a human or a skill queue

To send callers to people, point the number at a **skill queue** or an **IVR
program (VDN)** instead of an agent. This is configuration, with no media code.
The gateway answers and runs your IVR steps. The ACD then picks the next
eligible agent on a browser softphone or a real SIP deskphone.

  - **[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)** — Answer with AI to qualify the caller, then warm-transfer to a person.

## Bridge caller audio into your own code

When you want your own service to drive the call, set the inbound rule to
`NOTIFY_AND_HANGUP`. The flow is:

1. The gateway tells your app about each incoming call.
2. You answer the call.
3. You subscribe `uplink` to hear the caller.
4. You publish `downlink` to talk back. Both go through an audio bridge 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",
)

# When an incoming call arrives on your event stream:
async def on_call_event(ev):
    if ev.type == "CHANNEL_CREATE":
        await client.answer_incoming_call(ev.call_sid)  # accept the leg
        # From here, open an audio bridge on ev.call_sid and read/write frames.
```
  
  
```ts
// Your webhook handed you the inbound call's sid.
async function handleInbound(sid: string) {
  const bridge = await v.audioBridge.attach(sid, {
    codec: "pcm16",
    sampleRate: 16000,
    onUplink: (pcm, tsUs) => myAsr.feed(pcm),   // caller audio → your recognizer
  });

  // your model / TTS emits audio → push it straight back to the caller
  myModel.onAudioOut((pcm) => bridge.publishDownlink(pcm));
  return bridge;
}
```
  

> **NOTE:**
> The `attach` bridge is written from the **server's** point of view. You
> **subscribe** `uplink` and **publish** `downlink`. This is the same handle that
> an outbound call gives you. Configure a `webhook_url` to receive incoming-call
> events. See [Webhooks](/modalities/voice/api/webhooks).

## Pick a codec to skip transcoding

For a PSTN-direct call, ask for G.711. The bridge then passes the caller's audio
through without transcoding. Ask for `pcm16` when a realtime model wants raw
audio.

```ts
// µ-law passthrough on a North-American PSTN leg — no transcode
const rec = await v.audioBridge.attach(sid, {
  codec: "g711_ulaw",
  onUplink: (frame, tsUs) => recorder.write(frame),
});
```

## Play a greeting back to the caller

Push encoded frames onto `downlink` as your TTS produces them. See
[Speak back to the caller](/modalities/voice/cookbooks/tts-back).

  
```ts
myTts.onChunk((frame) => bridge.publishDownlink(frame));
```
  
  
```python
tts.on_chunk(lambda frame: bridge.publish_downlink(frame))
```
  

## Transfer an inbound caller

The same `sid` continues across a transfer. For this reason, any recording or
analytics keyed on the `sid` stay intact. See
[Transfer to a human](/modalities/voice/cookbooks/transfer-human).

```ts
const call = await v.calls.get({ sid });
await call.transfer({ to: "+15557654321" });   // forward to a PSTN number (SIP REFER)
// or re-attach the live audio to another agent in place:
await call.transfer({ agent: "senior-agent" });
```

## Hang up and clean up

End the call. Then release the bridge to close both tracks.

```ts
await call.hangup();
await bridge.close();
```

> **WARNING:**
> Keep the `bridge` reference alive for the full duration of the call. If the
> garbage collector removes it, both tracks drop. Always call `bridge.close()`
> before `call.hangup()` so that the tracks close cleanly.

## Related

  - **[Inbound calls](/modalities/voice/transport-telephony/inbound)** — The full guide: how the gateway answers and where routing decisions live.
  - **[Stream to your ASR](/modalities/voice/cookbooks/stream-to-asr)** — Feed caller uplink into your own recognizer.
  - **[Place an outbound call](/modalities/voice/cookbooks/outbound-call)** — The mirror of this page: originate from code.
  - **[Audio bridge API](/modalities/voice/api/transport)** — Full signatures for attach, publishDownlink, and onUplink.
