Skip to main content

Troubleshooting: SIP trunk registration, health, and failover

A trunk problem shows up one of three ways: the trunk never registers at all, it registers but keeps failing periodic health checks (flapping), or it is registered but calls still do not route the way you expect — inbound calls rejected, or failover never engaging when the primary is down. This page maps each symptom to a cause and tells you what to check before you change anything. For the dashboard walkthrough (SIP settings table, route-quality view), see Troubleshooting: SIP trunk down or calls failing; this page goes deeper on the SIP layer itself.

Trunk state basics

Each trunk you create carries a set of live diagnostic fields on top of its configuration — these are what every check on this page reads:
  • status — the cached registration verdict: registered, unregistered, or unknown (no probe data yet).
  • lastRegistrationError — the last recorded failure, with the SIP response code where the carrier returned one (for example 401, 488) or a step name where it never got that far (DNS resolution, TCP/TLS connect).
  • lastRegistrationCheckAt — when the verdict was last refreshed.
  • registrationFailureCount — consecutive failed checks since the last success. A non-zero streak on an otherwise registered trunk is the early-warning signal.
  • registrationFailingSince — the wall-clock start of the current failure streak.
Read the full record for one trunk:
Or read the ranked snapshot of every trunk, with the rows that need attention first and per-severity tallies:
Two mechanics sit behind these fields:
  • Health evaluation. The platform re-checks each enabled trunk on a cadence of about five minutes, running a real SIP REGISTER with the trunk’s stored credentials and folding the verdict back onto the trunk record. An operator-run test (POST /api/v1/voice/sip-trunks/:id/test or Test trunk in the dashboard) runs the same probe on demand and updates the same fields, so a fix you made is provable within seconds without waiting for the next poll.
  • Failover routing. When the dispatch path finds the primary trunk is anything other than registered, it walks the failover chain you configured and picks the first candidate that is enabled, has a dial address, and is itself registered. A chain with no usable candidate — or none configured — falls back to Orbit’s default outbound routing, so a misconfigured failover worsens redundancy but never blocks calls. Chain writes are cycle-checked at save time and hop-bounded at dispatch time, so a loop cannot hang dispatch.
  • Inbound auth ledger. For incoming trunks (your carrier originates calls into the platform), every failed auth attempt — digest challenge or IP allowlist — is recorded against the trunk for seven days. That ledger is the first place to look when inbound calls stop arriving while the trunk row looks healthy.

Symptom → cause

Work the table top-down — the rows cover the overwhelming majority of trunk incidents.

Reading the trunk-health endpoint

GET /api/v1/voice/sip-trunks/health returns one ranked row per trunk plus a counts block. The ranking exists so the trunk that needs attention sorts first; read the severity ladder per row: Within a severity, rows sort by consecutive-failure streak and then by staleness of the last check — a trunk that stopped being probed at all is worse news than one still answering. Use lastCheckedAt to tell “the trunk broke” apart from “the checks stopped”: if lastCheckedAt is hours old on an enabled trunk, the verdict is stale and you should force a fresh probe with the test endpoint rather than trusting the cached status. The same severity fields explain failover behavior: dispatch only uses a failover candidate in the active state (enabled and registered), so a backup sitting at degraded or down is skipped exactly as if it were unconfigured.

TLS and SRTP

Trunks configured with TLS transport (port 5061) fail differently from UDP/TCP trunks and deserve their own pass:
  • Certificate chain. The carrier’s SIP endpoint must present a complete chain to a public root. A missing intermediate opens as a TCP/TLS connect failure in lastRegistrationError even though the port is reachable — confirm with openssl s_client -connect host:5061 -servername host from any network and look for an unbroken chain.
  • SAN mismatch. The certificate’s subject-alternative names must include the exact host you configured on the trunk. A trunk pointed at sip-carrier.com while the certificate names sip1.sip-carrier.com fails the handshake the same way — align the trunk host with the certificate SAN (or get the carrier to reissue).
  • SRTP media. When the trunk negotiates TLS, media keys ride the encrypted signaling (SDES). If registration succeeds but calls connect with no audio, the carrier side is either declining SRTP or offering a keying mode the trunk did not accept — check the carrier’s media-security setting, not the codecs. The full one-way-audio / dead-air decision path lives in Troubleshooting: voice call quality.
After any TLS change, run the trunk test rather than waiting for the next poll: POST /api/v1/voice/sip-trunks/:id/test.

What not to do

  • Do not retry blindly. Re-running registration against an unanswered 401 or a timeout changes nothing and can trigger carrier-side rate limits that turn a flap into a hard block. Read the recorded error first, fix the named cause, then test once.
  • Do not rotate credentials while the trunk is flapping. A rotation mid-flap mixes two failure modes — you can no longer tell whether the next 401 is the old credential cached somewhere or the new one wrong. Stabilize the trunk first, then rotate as its own step, then test again.
  • Do not edit the failover chain while a failover event is in progress. Dispatch reads the chain per call; changing targets mid-incident makes already-routed and newly-routed calls disagree about which trunk was the backup.

When to escalate

Open a support ticket when you have worked the symptom table, forced a fresh probe, and the trunk still fails with an error this page does not explain. Include all three so we can trace the attempt without a back-and-forth:
  1. The trunk ID (trunk_…).
  2. Your organization ID (Settings → Organization, or organizationId from GET /api/v1/me).
  3. The last SIP response code or failed step from lastRegistrationError (for example 403, or DNS resolution), plus the lastRegistrationCheckAt timestamp so we can find the exact attempt.

See also