> ## 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.

# AI Voice Agents via sip_forward (callers.ai, Retell, Vapi)

> Route inbound calls from your Orbit numbers to a third-party AI voice agent over SIP.

# AI Voice Agents via `sip_forward`

You can point an Orbit DID at any third-party AI voice platform that
exposes a SIP endpoint — callers.ai, Retell, Vapi, and most other
agent providers do. Orbit handles the carrier termination, billing,
and recording; the AI provider runs the conversation logic.

This guide walks through wiring up an inbound `sip_forward` route end
to end. The same shape works for self-hosted PBX targets — see the
[SIP trunk](#sip-trunks) reference for the trunk-mode alternative.

## How it works

1. Orbit owns the DID and accepts the inbound INVITE from the carrier.
2. Orbit's SBC (Jambonz) re-INVITEs the call to the AI provider's SIP
   URI on your behalf, terminating TLS at our edge.
3. RTP media is bridged through RTPengine — the AI provider never sees
   the carrier directly, and the carrier never sees the AI provider.
4. Hangup, DTMF, and recording are surfaced over the same Orbit
   webhook contract regardless of which AI vendor terminates the call.

## Step 1 — Buy a number

Pick a number for the agent. Toll-free numbers tend to work better for
contact-center scenarios because A2P 10-DLC restrictions don't apply
to inbound voice.

First, list available numbers for the country and capability you want:

```bash theme={null}
curl -s "https://api.orbit.devotel.io/api/v1/numbers/available?country=US&type=toll_free&capabilities=voice" \
  -H "X-API-Key: dv_live_sk_..."
```

Each entry in the response's `numbers` array has a `phone_number`
field. Copy the E.164 value (e.g. `+14155550123`) of the one you want,
then buy that specific number:

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/numbers/purchase \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155550123",
    "country_code": "US",
    "capabilities": ["voice"]
  }'
```

The response carries the `phone_number` field — the E.164 phone number
(e.g. `+14155550123`) you'll use in the next step. Inbound routing is
keyed by the E.164 number, **not** the `id` (`num_…`): export it as
`PHONE_NUMBER` so the path below resolves correctly.

```bash theme={null}
export PHONE_NUMBER="+14155550123"   # the `phone_number` from the response above
```

## Step 2 — Configure inbound routing → `sip_forward`

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/numbers/$PHONE_NUMBER/routing" \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "type": "sip_forward",
    "config": {
      "mode": "inline",
      "sipUri": "sip:agent_xyz@sip.vapi.ai",
      "sipUsername": "your-trunk-user",
      "sipPassword": "your-trunk-secret"
    }
  }'
```

You can omit `sipUsername` / `sipPassword` if the AI provider doesn't
require digest auth on the inbound INVITE — most do not.

## Provider URI examples

Each AI provider publishes a slightly different SIP URI shape. Use
the example for your vendor verbatim — only the token / agent ID
changes.

### callers.ai

```
sip:<token>@callers.ai
```

The `<token>` is the agent token from your callers.ai dashboard
(Settings → Phone → SIP).

### Retell

```
sip:<agent_id>@<retell-sip-host>
```

`<retell-sip-host>` is the host published in your Retell dashboard
under "Phone Numbers → BYO SIP" — it's region-specific
(Retell publishes a per-account SIP host such as
`<account-hash>.sip.<provider>.example`; copy the exact value
from your dashboard rather than hard-coding).

### Vapi

```
sip:<assistant_id>@sip.vapi.ai
```

The `<assistant_id>` is the assistant's ID from the Vapi dashboard
(Assistants → ID → Copy). Vapi's SIP endpoint accepts unauthenticated
INVITEs by default; configure an inbound credential under "SIP
Trunks" if your security posture requires digest auth.

## DTMF

Orbit forwards DTMF events to the AI provider as **RFC 4733 in-band
RTP**. All three providers above support this out of the box — no
extra configuration needed. SIP INFO DTMF is **not** forwarded; if
your agent only supports SIP INFO, contact support and we'll enable
the DTMF translator on your account.

## Audio codec compatibility

Orbit's SBC re-negotiates codecs on the way out, so the AI provider
sees only the codec it's comfortable with even if the carrier offered
something exotic.

| Codec       | Orbit ↔ Carrier | Orbit ↔ AI Provider | Notes                                               |
| ----------- | --------------- | ------------------- | --------------------------------------------------- |
| G.711 µ-law | ✅               | ✅                   | Default for US carriers, all AI providers           |
| G.711 A-law | ✅               | ✅                   | EU carriers; transcoded only when AI requires µ-law |
| Opus        | ✅               | ✅ (Vapi, Retell)    | Lowest latency; not all carriers offer it           |
| G.729       | ✅               | ❌                   | Transcoded to G.711 — adds \~10ms latency           |

## Troubleshooting

### Signature 401 on inbound INVITE

The AI provider's SIP gateway rejected your INVITE with a `401
Unauthorized` and you don't see the call in your provider dashboard.
The two common causes:

1. **Wrong token / agent\_id.** Re-copy from the provider dashboard;
   tokens are case-sensitive.
2. **Trunk auth required.** Some providers (Retell on production
   tier, Vapi if "Allow only authorized SIP origins" is on) need
   digest auth. Set `sipUsername` and `sipPassword` on the route
   config to credentials issued by the provider — Orbit stores them
   encrypted at rest.

### Audio one-way

You can hear the caller, but the caller can't hear the agent (or
vice versa). This is almost always a **codec mismatch on the AI
provider side** — the AI is sending Opus but Orbit re-INVITEd as
G.711. Open a ticket with the provider and ask them to advertise
G.711 µ-law in their SDP answer; Orbit will negotiate down to
whatever both ends agree on.

### Calls drop at exactly 32 seconds

Classic NAT keep-alive timeout: the carrier or RTPengine isn't
seeing media in one direction, so the SBC tears the call down at
the 32s default. The fix lives on the AI provider's side — they
need to send RTP keep-alives during periods of silence (e.g. while
waiting on the LLM). All three providers above support this; check
their "send RTP during silence" setting.

If the drop happens earlier (\< 5s), it's usually the carrier
rejecting the re-INVITE — open a support ticket with your call SID
and we'll pull the SBC trace.

## See also

* [SIP Trunks](/api-reference/voice#sip-trunks) — the trunk-mode
  alternative to inline `sip_forward`. Use this when one trunk fans
  out to many DIDs.
* [Inbound routing](/api-reference/numbers) — full reference for every
  route type (`agent`, `softphone_user`, `softphone_register`, `ivr`,
  `voicemail`, `queue`, `sip_forward`, `transfer`, `conference`,
  `decline`, `ring_group`, `shared_line`, `dispatch_to_voicemail_box`,
  `webhook`).
* [Webhooks](/webhooks/events) — receive `call.initiated`,
  `call.answered`, and `call.completed` events for calls forwarded
  to an AI agent.
