Troubleshooting: outbound calls rejected with SBC_UNAVAILABLE
SBC_UNAVAILABLE (HTTP 503) is the refusal the voice API returns when it
could not hand an outbound call to the session border controller (SBC)
that terminates it. Every outbound call leaves Orbit through an SBC,
either on your own SIP trunk or on the platform’s wholesale routing, so
the cause lives on one of three sides: your trunk’s SBC, the upstream
carrier, or a transient platform blip. This page walks the ladder that
finds which, and tells you when a retry helps and when only a config
change does.
What you see
- API dispatch.
POST /api/v1/voice/calls(and the softphone dial that goes through it) answers503with the code in the error envelope:
meta.request_id now; it is the anchor support traces by.
- Dialer-dispatched outbound legs. Campaign and journey calls do not
return the 503 to you directly. The leg lands as
failedin the campaign’s call results, and the same row shows in the Voice call log (filterstatus=failed,direction=outbound, see Voice call logs). - Webhook. Each rejected leg also arrives as a
call.failedevent on your voice webhook endpoint (see Webhook events), so an integration that watchescall.failedsees the refusal even when no operator is looking at the dashboard.
Causes
Work top-down. The first three are yours or your carrier’s; the last is the platform’s.- Your trunk’s SBC is unreachable. The target SBC is down, or a DNS record or IP allow-list changed on your side (a BYOC firewall rule, a rotated egress allow-list) so the platform edge is refused. This is the most common cause on customer-managed trunks.
- Carrier-side outage on the upstream route. The SBC answers but the carrier’s next hop is down; failures arrive in a burst that matches the carrier’s maintenance window rather than any change of yours. Check your carrier’s status channel and the Orbit status page.
- TLS or profile mismatch after a trunk edit. A certificate that no longer chains, a subject name that no longer matches the host, or a codec/transport profile the carrier rejects at INVITE time. Rejects that begin exactly when you saved a trunk edit are this until proven otherwise; the TLS pass lives in SIP trunk troubleshooting.
- A transient platform media blip. The media plane that bridges your call onto the SBC occasionally loses signaling connectivity for seconds at a time, and the API answers the same clean 503. This class self-heals in moments and is the one retry-with-backoff is for; if it persists beyond a few minutes it is an incident, not a blip.
SBC_UNAVAILABLE means the platform never placed the call on the wire.
Refusals from the pre-send checks (emergency, destination, caller
identity) return their own 4xx codes instead; see the
voice pre-send gate chain for that
ladder.
Debug ladder
Run these in order; each step narrows which cause above you are in.- Read the trunk record.
GET /api/v1/voice/sip-trunks/:id, or Settings → Voice → SIP trunks in the dashboard, returnsstatus,lastRegistrationError, andlastRegistrationCheckAt. Astatusother thanregisteredwith a namedlastRegistrationError(DNS resolution,TCP/TLS connect,401,488) puts the fault on your trunk’s path; fix the named cause per the SIP trunk runbook.
- Compare timestamps. Line the first
call.failedevent up against the trunk’s last config change and itslastRegistrationCheckAt. Failures that begin the minute a trunk edit saved point at cause 3; failures that begin with no change of yours point at cause 1 or 2. - Reproduce with one manual call. Place a single call by hand, from
the softphone or one
POST /api/v1/voice/calls. If the lone call fails exactly like the dialer’s burst, the fault is per-call reachability or config, not dialer concurrency. If only the dialer fails while manual calls pass, you are on a capacity gate instead, and the capacity section of the SIP trunk runbook is the page you want. - Prove the path with an inbound test. If the trunk also carries inbound calls, place a test call into it. Inbound succeeding while outbound fails narrows the fault to the outbound route or profile; both directions failing puts it on reachability (cause 1).
Fix vs retry
The code alone does not tell the two apart; the failure pattern does. A deterministic config fault never clears on retry, and retrying it burns dialer attempts against a dead setting. A transient outage clears on its own and rewards spaced retries.
Two rules keep this safe:
- Never retry a deterministic fault as-is. An unchanged re-issue of a
refused call returns an unchanged 503, and a tight loop can trip
carrier-side rate limits that turn a misconfiguration into a block.
Edit, re-test the trunk, then re-issue once. For API-originated calls,
send an
Idempotency-Keyon the re-issue so a retry racing the recovery cannot originate the call twice (see Idempotency and billing gates). - Back off the transient class, do not flat-retry it. Spaced attempts ride a blip out; a tight loop turns the blip into a backlog.
Bring Your Own Carrier trunks
If the trunk is customer-managed (your SBC, your carrier contract), the platform fails closed: a trunk it cannot reach is refused with this code, except where your configured failover chain or the dispatch fallback described in the SIP trunk runbook routes around it. Everything on your side of the path (the SBC, its DNS, its firewall allow-lists, its certificates) is yours to fix; work the ladder above and re-test. Note the split with caller identity: an INVITE whose caller-id is outside the trunk’sallowedCallerIds list is a 403
VOICE_CALLER_ID_REJECTED, not this 503 (see the
FAQ entry).
If the trunk is platform-managed, the same 503 pages Devotel on-call
automatically; there is nothing to edit on your side and no retry budget
to wait out before opening a ticket. Either way, include the bundle
below so the first response is not a request for more data.
The bundle support needs
- The
request_idfrommeta.request_idon the 503 envelope, or from the failed row in Insights → Logs for dialer-dispatched legs. - The
trunk_id(trunk_…) the call was placed through, or “platform default” when you do not run your own trunk. - The window: first and last
call.failedtimestamp, and whether any trunk or carrier change preceded it.
What not to do
- Do not loop the retry on a config fault. An unchanged re-issue changes nothing; back off, fix, re-issue once.
- Do not edit the trunk while a burst is in flight. Changing host or credentials mid-burst mixes two failure populations and makes the timestamp comparison in the ladder meaningless.
- Do not rotate carrier credentials to chase a blip. A rotation only
answers a
401-classlastRegistrationError; on an unreachable SBC it adds a second variable.
When to escalate
Open a support ticket when you have worked the ladder, re-tested the trunk, and the 503 persists past your backoff window, or whenever a platform-managed trunk repeats the refusal. Attach the bundle above plus your organization ID (Settings → Organization). If the trunk is customer-managed and the ladder points past your edge, take thelastRegistrationError text and the timestamps to your carrier; the
platform records what it saw on its side of the handshake, and that is
the evidence your carrier’s SBC team needs.
See also
- Troubleshooting: SIP trunk registration, health, failover, and capacity — the registration, TLS, and capacity deep dive this page defers to.
- SIP trunks in the dashboard — the settings table, route-quality view, and auth ledger.
- VOICE_GATEWAY_ERROR at call-send — the sibling refusal when the voice gateway, not the SBC path, fails.
- Voice pre-send gate chain — when the refusal is a 4xx gate before the SBC rather than this 503.
- Why did my caller-ID rewrite get rejected on my own SIP trunk with
VOICE_CALLER_ID_REJECTED? — the trunk-side caller-identity refusal that is a 403, not a 503. - Error codes reference — the full envelope catalogue.