# SIP Trunk Issues

> The trunk does not register or route calls? Diagnose SBC IP and credentials, register expiry, channel limits, compliance headers, and firewall ports.

Your trunk is saved, but calls do not flow. The status chip is stuck on
**error** or **disconnected**, the carrier rejects the REGISTER, or inbound
INVITEs never reach an agent. Almost every trunk problem traces back to one of
five causes:

- The peer address or credentials do not match.
- The registration expiry is wrong.
- You hit the channel limit.
- The carrier rejects your identity headers.
- A firewall drops the packets.

Work from top to bottom. The status chip narrows the problem first. Then the
tables below map each symptom to a cause and a fix, based on the trunk fields
you set on [SIP Trunking](/modalities/voice/transport-telephony/sip-trunking).

## Start with the status chip

Open **Admin → Trunks** on [agent.firstbyte.fast](https://agent.firstbyte.fast)
and read the live chip next to the trunk:

| Chip             | Meaning                                                                 | Look at |
| ---------------- | ----------------------------------------------------------------------- | ------- |
| **connected**    | Registration (or static peering) is healthy. If calls still fail, the problem is *routing*, not the trunk. | [Routing failures](#the-trunk-is-up-but-calls-do-not-route) |
| **error**        | The trunk tried to register, and the carrier rejected it.               | [Registration failures](#the-trunk-will-not-register) |
| **disconnected** | No registration attempt completes. Usually the peer is unreachable, or a firewall drops packets. | [Firewall & ports](#firewall-and-ports) |

> **TIP:**
> A trunk that does **not** require registration (static IP peering) has no
> registration to fail. It shows healthy as soon as you save it. For those
> trunks, go straight to [routing](#the-trunk-is-up-but-calls-do-not-route). The
> gateway matches the carrier only by **source IP** and the dialed DID.

## The trunk will not register

Registration applies only when you enabled **Require SIP REGISTER** and set a
**SIP Username** / **SIP Password**. If the chip shows **error**, the carrier
answers your REGISTER with a rejection.

| Symptom                                                        | Likely cause                                                                 | Fix |
| ------------------------------------------------------------- | ---------------------------------------------------------------------------- | --- |
| The chip flips to **error** the instant you save               | The **SIP Username** / **SIP Password** is wrong, or the credential drifted after a rotation | Save the trunk again with the correct values. Passwords are **sealed** and never read back. A blank-looking field is *not* the bug. Always enter the full password again to rotate it. |
| The carrier returns *403 Forbidden* / *404 Not Found* on REGISTER | The **SIP Domain** (registration realm) does not match what the carrier expects in the `From`/`To` user@domain | Set **SIP Domain** to the exact host your carrier assigned (often the SBC host), not your workspace subdomain. |
| The trunk registers, then drops after a minute or two, then registers again | **Register Expires** is longer than the carrier's binding TTL. The carrier expires the contact before your refresh | Lower **Register Expires** (`register_expires_sec`, default `3600`) to at or below the carrier's maximum. Many carriers cap at 3600 or 300s. |
| Constant re-REGISTER churn / high signalling load              | **Register Expires** is set very low (for example, tens of seconds)         | Raise it back toward the carrier's recommended value. Short expiries multiply REGISTER traffic and do not improve reliability. |
| A *401/407* challenge loop never settles                       | Digest auth mismatch — the username, password, or realm is off by one       | Check all three against the carrier's provisioning portal. The realm in the `401` challenge must equal your **SIP Domain**. |
| The chip is **disconnected**, and the REGISTER gets no reply   | The peer is unreachable — a wrong **SBC IP** / **Destination Port**, or a firewall | See [Firewall & ports](#firewall-and-ports). |

> **WARNING:**
> SIP passwords are sealed at rest. The system never returns them when you read
> a trunk back. An empty password box in the editor is expected. It does **not**
> mean the credential was lost. To change the password, type the new secret and
> save.

## The trunk is up but calls do not route

The chip says **connected** (or the trunk is static-IP peered), but callers
still cannot reach an agent. The trunk edge is correct. The problem is
*matching*, *capacity*, or *identity*.

| Symptom                                                              | Likely cause                                                                                     | Fix |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | --- |
| An inbound INVITE arrives but is rejected before it rings (*403*)    | The carrier sends from an IP that is **not** the configured **SBC IP**. The INVITE hits the registrar ACL instead of a trunk match | Add every source IP the carrier uses to the trunk's **SBC IP** / peer address. SBCs often front a pool. A matched trunk peer bypasses the registrar ACL. An unmatched one is treated as an untrusted endpoint. |
| An inbound INVITE matches the trunk, but the caller hears nothing or drops | `inbound_rule` is still on **reject**, or no agent/skill/VDN is bound to the DID            | Set an inbound handler (**Handle with AI**, or bind a skill/VDN) — see [Inbound Calls](/modalities/voice/transport-telephony/inbound). New trunks default to **reject**. |
| Calls fail only at peak. They work off-peak                          | The **Channel Limit** is reached. Concurrent calls beyond it are rejected (busy)                  | Raise **Channel Limit** (`channel_limit`, default `50`) to match your carrier contract. A limit that is too tight *silently* sheds traffic at the busy hour. |
| Outbound calls return only *100 Trying*, then time out               | The carrier drops calls whose edge asserts caller identity                                        | Switch **Compliance Headers** from **Full** to **Minimal**. This suppresses `Remote-Party-ID`, `P-Asserted-Identity`, and `P-Access-Network-Info`. |
| The caller connects, but there is no audio (one-way or dead air)     | RTP media addressing / NAT — `external_rtp_ip` is wrong, or RTP ports are blocked                 | Check that **External RTP IP** is your public address, and that the RTP/UDP media range is open (see below). Deep-dive: [One-Way / No Audio](/modalities/voice/troubleshooting/one-way-audio). |
| The carrier sends a BYE right after the answer                       | An SDP negotiation edge case (for example, a `180 Ringing` sent without SDP where the carrier needs early media) | The gateway answers `100 Trying → 183 with SDP → 200 with the same SDP` by design. If a carrier still sends a BYE, capture the exchange in the SIP trace (below). Check the offered codecs against [Codecs](/modalities/voice/transport-telephony/codecs). |

## Firewall and ports

A **disconnected** chip, REGISTERs with no reply, or INVITEs that never arrive
almost always mean a dropped packet in transit. Check that the path is open in
**both** directions between your carrier's SBC and your workspace endpoint
`<workspace-id>.sip.firstbyte.fast`.

| Traffic            | Transport           | Port                                   | Direction                       |
| ------------------ | ------------------- | -------------------------------------- | ------------------------------- |
| SIP signalling     | UDP / TCP           | `5060` (your **Source Port**)          | Inbound from + outbound to SBC  |
| SIP over TLS       | TLS                 | `5061` (or your configured secure port) | Both, when the trunk is TLS     |
| RTP / RTCP media   | UDP                 | The negotiated media port range advertised in your SDP | Both, to/from the carrier's media IP |
| Carrier signalling | UDP / TCP           | The **Destination Port** your carrier assigned | Outbound to the SBC             |

  1. **Confirm the peer address and port**
Check **SBC IP** (or **Gateway IP**), **Source Port** (default `5060`),
    and the carrier-assigned **Destination Port**. One wrong digit here shows
    as **disconnected**, because nothing replies. If the carrier routes
    through an intermediary, set the **Outbound Proxy** (`host:port`).
  2. **Open SIP both ways**
SIP is bidirectional. If you open only the outbound path, your REGISTER
    leaves, but the firewall silently drops the carrier's 200 OK and every
    inbound INVITE. Allow UDP/TCP `5060` (and TLS `5061` for TLS trunks) to
    and from every SBC source IP.
  3. **Open the RTP media range**
Signalling can succeed while media fails. The result is connected calls
    with no audio. Open the UDP media port range your workspace advertises in
    SDP to the carrier's media address. Check that **External RTP IP** is the
    reachable public address. The internal/external split is what makes the
    trunk work behind NAT.
  4. **Watch NAT keep-alive on registration trunks**
Behind NAT, a **Register Expires** longer than your firewall's UDP idle
    timeout lets the pinhole close between refreshes. The carrier then cannot
    reach you, even though the chip last showed connected. Lower **Register
    Expires** so the refresh reopens the pinhole before it lapses.
  5. **Capture the exchange**
If the addressing and ports look correct, read the actual SIP dialog. The
    per-tenant SIP trace viewer shows the full INVITE/REGISTER exchange, the
    response codes, and the SDP for every call on the trunk — see
    [SIP / RTP Debugging](/modalities/voice/observability/sip-rtp-debugging).
    A `403` on INVITE points back to an unmatched **SBC IP**. A repeated
    `401/407` points at credentials. A `486`/`503` points at the **Channel
    Limit**.

## Quick field checklist

  **Registration rejected (error)**

- **SIP Username** / **SIP Password** exactly match the carrier. Enter the
      full password again — sealed fields never read back.
    - **SIP Domain** equals the carrier's registration realm, not your
      workspace subdomain.
    - **Register Expires** (`register_expires_sec`) is at or below the
      carrier's maximum, and above your NAT idle timeout.

  **Inbound INVITE rejected (403 / never rings)**

- Every carrier source IP is listed as an **SBC IP** / peer, so the INVITE
      matches the trunk and bypasses the registrar ACL.
    - `inbound_rule` is set to a real handler (not the default **reject**),
      and the DID is bound to an agent, skill, or VDN.

  **Calls fail at peak or time out outbound**

- **Channel Limit** (`channel_limit`) matches your carrier's contracted
      concurrent-call ceiling.
    - **Compliance Headers** is set to **Minimal** if the carrier drops
      identity-asserting calls (`100 Trying`, then a timeout).

  **Connected but no / one-way audio**

- **External RTP IP** is the reachable public address. The RTP/UDP media
      range is open both ways.
    - **Media Mode** is **Proxy**. Media anchored at the gateway is the
      NAT-safe default. **Direct** is preview, and it currently still proxies.

## Related

  - **[SIP Trunking](/modalities/voice/transport-telephony/sip-trunking)** — The full trunk-configuration walkthrough and field reference.
  - **[SIP / RTP Debugging](/modalities/voice/observability/sip-rtp-debugging)** — Read the raw SIP dialog and RTP quality for any call on the trunk.
  - **[Call Not Connecting](/modalities/voice/troubleshooting/call-not-connecting)** — When the call never reaches an agent, across all transports.
  - **[One-Way / No Audio](/modalities/voice/troubleshooting/one-way-audio)** — Signalling succeeds, but media is silent or flows in one direction.
