# SIP trunks

A SIP trunk is a standing relationship between two systems that carries many calls at once. An inbound trunk tells a carrier where to deliver calls for your numbers; an outbound trunk is how you hand calls back to the network. Connect's realtime voice path arrives over an inbound trunk, and a dispatch rule decides which worker meets the call.

- **Status:** Reference
- **Audience:** developer, both
- **Channels:** phone
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/technology/sip-trunk/

## What the two directions mean

|  | Inbound trunk | Outbound trunk |
|---|---|---|
| Direction of the call | Carrier → your platform | Your platform → carrier → the public network |
| The key setting | The origination URI: where the carrier sends the call | The address and credentials your platform sends to |
| Attached to | Specific numbers, linked at the carrier | An account and its permitted destinations |
| Fails as | A number that rings nowhere while looking configured | A dial that is refused, or answered by a leg that never joins |

Both directions carry a concurrency limit — the number of simultaneous calls the trunk permits. That number is a capacity constraint on your product whether or not anything in your product knows about it.

## The origination URI, exactly

The origination URI is the single field that most often looks right and is wrong. Three details decide it.

1. **It is a host and a port, not a full SIP address.** Some carrier fields want `host:5060` with no `sip:` prefix in front of it, and reject or silently ignore the prefixed form.
2. **The host is the SIP service's host, not your API server's.** On a hosted media platform the SIP host is a project-specific subdomain, which is not the hostname of the URL your application code connects to. Copying the one you already have configured is the natural mistake and it produces a trunk that accepts configuration and never delivers a call.
3. **Linking a number to the trunk is a separate step**, done at the carrier against that number. A correctly configured trunk with no number attached is indistinguishable, from your side, from no trunk at all.

> **Careful** You cannot usefully loop-test an inbound trunk by originating a call from the same media platform back into it. Test with a real call placed through the carrier, because that is the path a customer takes and it is the only one that exercises the number linkage.

## Dispatch: what meets the call

Delivery is only half of it. When a call arrives on the trunk, the receiving platform puts it in a room, and a dispatch rule says what should join that room. In Connect's realtime path the rule spawns the `connect-voice` worker, which fetches its brief and holds the conversation.

Two admission rules sit in front of that, and both refuse before any call record exists rather than after.

**No worker has checked in for ninety seconds** — The ring is refused as `not_ready`, so a drain can retry rather than the caller reaching an empty room. Before this existed, an inbound call could reach nothing at all while the Phone screen still said 'ready'.
**Every live worker is over the busy threshold** — Load is reported per core on every heartbeat, and the gate refuses above **0.85** — the same figure the worker gives the platform as its own load threshold, so admission control and the gate agree rather than contradicting each other.

A worker reporting no load at all reads as free. Refusing calls because an older worker said nothing would be a worse failure than the saturation the threshold guards against.

## Does Connect use SIP trunks?

Yes, on the realtime engine, since a workspace can set its voice engine to realtime. The business number is linked at the carrier to an inbound trunk whose origination URI is the media platform's SIP host, the dispatch rule spawns the worker, and a speech-to-speech model listens and speaks on the call.

The turn-based carrier path uses no trunk at all — it is webhooks and a response document. Both engines exist, and a workspace chooses. Outbound calls on either engine go through the same dispatch function with a recorded placer, so memory blocks, consent, autonomy and budget gate an outbound call exactly as they gate a carrier one.

Deployment behaviour is trunk-relevant too: a drain timeout of 180 seconds lets calls in progress finish before a worker exits, and the service unit allows 210 seconds before it is killed. Calls do not survive a hard stop; they survive a planned one.

## Questions

### The trunk is configured but calls never arrive. What is the order to check?

Is the number linked to the trunk at the carrier; is the origination host the SIP service's host rather than the API server's; is the value in the plain `host:port` form the field expects; and does a dispatch rule exist for the room. Each of those fails silently and none of them raises an error in your application.

### How many concurrent calls can a trunk carry?

Whatever the carrier sold you, and it is a hard ceiling. Above it, calls are refused at the carrier before your platform hears about them — which is a different failure from your own capacity gate refusing, and it is worth knowing which one you are hitting.

### Do I need a trunk to make outbound calls?

Not necessarily. A carrier will place a call for you from its own API, which is the simpler route and the one the turn-based path uses. A trunk is what you want when your own platform is holding the media and needs the call delivered to it rather than described to it.

## Related

- [SIP](https://connectbyjbrh.com/docs/technology/sip/)
- [DID — a direct inward dialling number](https://connectbyjbrh.com/docs/technology/did/)
- [Telephony carriers](https://connectbyjbrh.com/docs/technology/carrier/)
- [Realtime voice agents](https://connectbyjbrh.com/docs/technology/realtime-voice/)
- [Phone and voice in Connect](https://connectbyjbrh.com/docs/phone/)

## What this page is based on

- Source pack: phone and voice — `docs-source/sources/PHONE.md` §3 and §5 (the inbound trunk, origination URI form, dispatch rule; `not_ready`, `WORKER_BUSY_LOAD` 0.85, drain and stop timeouts)
- RFC 3261 — SIP: Session Initiation Protocol (https://www.rfc-editor.org/rfc/rfc3261)
- Connect capability registry (`docs-source/facts.py`) — `realtime_voice`, `line_health`
