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

# SIP trunk health and connectivity diagnostics

> Read the Health tab and the step-by-step connectivity diagnostics panel on a Devotel Orbit SIP trunk — interpret each probe step, map a failure to its remediation, and know when to escalate.

# SIP trunk health and connectivity diagnostics

When a SIP trunk stops carrying traffic, the first signal is usually a
silent one: calls stop landing, or the registration counter ticks up while
the accepted counter does not. The Health tab and the step-by-step
diagnostics panel surface that signal before it becomes a missed call,
and they tell you which step of the connection failed so you can fix the
right thing.

This page covers the BYOC (Bring-Your-Own-Carrier) onboarding wizard's
Health tab and the step-by-step diagnostics panel for a single trunk. For
the conceptual symptom-to-action troubleshooting tree, see
[Troubleshooting: SIP trunk down or calls failing](/channels/voice/sip-trunks-troubleshooting);
for first-time setup, see
[SIP trunk first call: the agreement-to-confirmation walkthrough](/guides/sip-trunk-first-call-walkthrough).

## Where the diagnostics live

Two surfaces share one data source: the persisted registration
diagnostics on the trunk row.

1. **Health tab** — open **Voice → SIP trunks**, then select a trunk. The
   **Health** tab shows the live registration verdict, the last check
   timestamp, and a ranked list of every trunk on the account so the one
   that needs attention lands first.
2. **Troubleshoot button** — on the trunk overview, **Troubleshoot** runs a
   fresh connectivity probe against the trunk's stored host, port,
   transport, and credentials, then renders the ordered step-by-step
   breakdown inline. The same probe runs automatically when you create a
   trunk through the BYOC onboarding wizard, so the first Health view is
   already populated.

The Health snapshot ranks trunks needs-attention first: a trunk whose
registration status is `unregistered` ranks above one that is
`registered`, and within each severity a longer failure streak ranks
above a shorter one. A trunk that has not been probed in a while ranks
above one checked recently, so a silently-stale trunk does not hide.

## What the diagnostics panel shows

For an outbound trunk, **Troubleshoot** runs a real `REGISTER` through the
probe carrier against the trunk's configured registrar. The response
carries an ordered `steps` array — one row per phase the probe walked
through — and a single `status` verdict:

```json theme={null}
{
  "data": {
    "trunk_id": "sip_8f3c2d1a",
    "status": "unreachable",
    "latency_ms": null,
    "tested_at": "2026-10-10T09:14:22Z",
    "error": "Registrar rejected the digest credentials — verify the username and password.",
    "error_code": "register_failed",
    "steps": [
      { "key": "resolve", "status": "ok" },
      { "key": "credentials", "status": "ok" },
      { "key": "provision", "status": "ok" },
      { "key": "gateway", "status": "ok" },
      { "key": "register", "status": "failed" }
    ]
  },
  "meta": { "request_id": "req_8f3c2d1a", "timestamp": "2026-10-10T09:14:22Z" }
}
```

Each step has one of four statuses:

* `ok` — the step completed successfully.
* `failed` — the step ran and returned a definitive failure. The steps
  before it are `ok`; the steps after it are `skipped` because the probe
  stopped.
* `pending` — the step was attempted but returned no verdict before the
  probe budget elapsed. This is the timeout case: every setup step passed,
  but the registrar did not answer the `REGISTER` in time.
* `skipped` — the step was never reached because an earlier step stopped
  the probe.

A healthy trunk answers `status: "registered"` with every step `ok` and a
non-null `latency_ms` — the round-trip of the accepted `REGISTER`.

For an inbound trunk, **Troubleshoot** runs a static configuration check
instead of a live probe (the customer's PBX initiates calls into Orbit, so
there is no outbound `REGISTER` to place). It returns `status: "ok"` when
the row is internally consistent — the IP allowlist parses, digest
credentials are present where `authMode` requires them, and at least one
auth path is ready — or `status: "misconfigured"` with an `issues` list
naming each blocker.

## Reading each step

The five steps run in order. The step that failed tells you where the
connection broke; the remediation is different for each.

<Steps>
  <Step title="resolve">
    DNS resolution of the trunk host. Orbit resolves the configured `host`
    before opening a SIP socket. **Pass** means the hostname resolved to a
    public IP. **Fail** means the hostname could not be resolved — a typo in
    the host, an expired DNS record, or a registrar that is only reachable
    over an internal network Orbit does not share. Check the host field on
    the trunk for a typo and confirm the hostname is publicly resolvable.
  </Step>

  <Step title="credentials">
    Presence of digest credentials on the trunk. **Pass** means both a
    username and a password are stored. **Fail** means one is missing — the
    trunk was saved without authentication, or the password was rotated on
    the registrar but not on the trunk. Set the username and password on
    the trunk to match what the registrar expects.
  </Step>

  <Step title="provision">
    Provisioning of a transient probe carrier on the softswitch. **Pass**
    means the probe carrier was created. **Fail** means the probe service
    was unavailable — the softswitch account was not configured at the
    platform level, or the provisioning call returned an error. This is a
    platform-side condition, not a trunk misconfiguration; retry in a
    moment, and if it persists, escalate.
  </Step>

  <Step title="gateway">
    Attachment of a SIP gateway pinned to the trunk's `host` and `port`.
    **Pass** means the gateway was attached. **Fail** means the gateway
    could not bind — most often a transport mismatch (`udp` versus `tcp`
    versus `tls`) between the trunk's configured `transport` and what the
    registrar's port accepts. Confirm the transport and port match the
    registrar's published SIP endpoint.
  </Step>

  <Step title="register">
    The `REGISTER` round-trip itself. **Pass** means the registrar accepted
    the register and returned `200 OK`. **Fail** means the registrar
    returned a definitive rejection — a `401`/`403`/`407` challenge the
    digest credentials could not satisfy, or a `423` asking for a shorter
    expiry. **Pending** means the registrar did not answer within the probe
    budget: the setup steps all passed, but the `REGISTER` got no
    response — a firewall dropping the SIP port, a NAT pinhole closed, or a
    registrar too slow to answer.
  </Step>
</Steps>

## Common failure topology

Each row maps a failure topology to the step it surfaces on and the next
action to take.

| Failure topology | Step that fails | What it means | Next step |
| - | - | - | - |
| Registrar unreachable (DNS typo, expired record, private host) | `resolve` | The configured `host` did not resolve to a public IP. | Correct the `host` field; confirm the hostname is publicly resolvable from outside your PBX network. |
| Unsupported transport (udp/tcp/tls mismatch) | `gateway` | The configured `transport` and `port` do not match a port the registrar accepts. | Match the transport and port to the registrar's published SIP endpoint; prefer `tls` on 5061 where supported. |
| Wrong From-domain / realm | `register` | The registrar rejected the digest because the realm it hashes against does not match the trunk's configured realm. | Set the SIP realm on the trunk to the value the registrar hashes against, not the server hostname. |
| Digest rejected (wrong username or password) | `register` | The registrar returned `401`/`407` and the stored credentials did not satisfy the challenge. | Correct the registration username and password on the trunk to match what the registrar issued; rotate both sides together. |
| NAT pinhole closed / firewall dropping the SIP port | `register` (pending) | The setup steps passed but the `REGISTER` got no answer within the probe budget — the SIP port is not reachable from Orbit's edge. | Allow inbound SIP from Orbit's edge IPs on the configured port; if the registrar is behind a NAT that closes the pinhole, switch to `tcp` (or `tcp` + SRTP) so the connection stays open. |
| SDP / codec mismatch | (surfaces on the first live call, not the probe) | The `REGISTER` succeeds but media has no common codec. | Set the trunk's codec list to a set the registrar supports (e.g. `opus`, `pcmu`) and retest with a live call. |

### Worked example — a 401 loop

A trunk reports `status: "unreachable"` with `error_code:
"register_failed"` and the `register` step `failed`; every earlier step is
`ok`. The registrar is reachable and the gateway attached, but the digest
challenge was not satisfied. The stored registration username did not
match what the registrar expected. Correcting the registration username
on the trunk and running **Troubleshoot** again returns `status:
"registered"` with a non-null `latency_ms`.

### Worked example — a NAT pinhole

A trunk reports `status: "unreachable"` with the `register` step
`pending` and every setup step `ok`. The registrar is reachable and the
gateway attached, but the `REGISTER` never got an answer. The customer's
PBX sits behind a NAT that closes the UDP pinhole between registrations.
Switching the trunk's `transport` from `udp` to `tcp` (with SRTP for
media) keeps the connection open through the NAT; the next
**Troubleshoot** returns `status: "registered"`.

## API surface

The panel is fed by two endpoints under `GET /api/v1/voice/sip-trunks`:

* **`GET /api/v1/voice/sip-trunks/health`** — the ranked Health snapshot.
  Returns `{ trunks: [...], counts: {...} }` with one row per trunk sorted
  needs-attention first, plus a `counts` block tallying rows by severity
  (`down`, `degraded`, `active`, `unknown`) for the dashboard tiles.

  ```bash theme={null}
  curl "https://api.orbit.devotel.io/api/v1/voice/sip-trunks/health" \
    -H "X-API-Key: $ORBIT_API_KEY"
  ```

* **`POST /api/v1/voice/sip-trunks/:id/test`** — the step-by-step probe.
  Runs a live `REGISTER` for an outbound trunk (or a static configuration
  check for an inbound trunk) and returns the `status`, the ordered `steps`
  breakdown, and the sanitised `error` text. The verdict refreshes the
  trunk's live freshness diagnostics on the row.

  ```bash theme={null}
  curl -X POST "https://api.orbit.devotel.io/api/v1/voice/sip-trunks/sip_8f3c2d1a/test" \
    -H "X-API-Key: $ORBIT_API_KEY"
  ```

Both endpoints require an owner, admin, or developer role API key. Every
response rides the standard envelope — `data` carries the payload and
`meta.request_id` is the correlation ID support asks for when you open a
ticket.

## BYOC onboarding wizard

The first-time setup flow — the BYOC onboarding wizard — runs the same
probe before it lets you save a trunk, then marks the trunk ready once the
configuration gates pass. The wizard's readiness check is a configuration
shape-check, not a network probe: it confirms the IP allowlist parses and
at least one auth path (allowlist and/or digest credentials) is configured
for the trunk's `authMode`. For an inbound trunk, no `REGISTER` is ever
placed — the customer's PBX initiates calls into Orbit — so readiness is
about configuration, not reachability.

Once the wizard's gates pass, the trunk is stamped ready and the Health tab
reflects it. For the full first-time setup thread, see
[SIP trunk first call: the agreement-to-confirmation walkthrough](/guides/sip-trunk-first-call-walkthrough).

## When to escalate

The diagnostics panel resolves the common cases — a typo, a credential
mismatch, a transport mismatch, a closed pinhole — without a support
ticket. Escalate when:

* the `provision` step fails repeatedly, which indicates a platform-side
  condition rather than a trunk misconfiguration;
* the `register` step stays `pending` after you have confirmed the
  firewall allows Orbit's edge IPs on the configured port and the transport
  matches the registrar;
* the Health tab shows a trunk as `down` but the trunk's own PBX logs show
  a healthy registration.

For the conceptual symptom-to-action tree and the failover chain, see
[Troubleshooting: SIP trunk down or calls failing](/channels/voice/sip-trunks-troubleshooting).

## Tenant scope

The diagnostics panel and the Health snapshot are scoped to your own
tenant. The probe runs against the trunk's stored host, port, transport,
and credentials — all of which are your own configuration. Diagnostic
steps never expose shared infrastructure credentials: the auth material
(the digest password, the CDR-webhook signing secret) is masked on every
read, and the probe response carries only the stable step tokens and a
sanitised operator-facing error sentence. A wrong trunk ID from another
tenant is indistinguishable from a wrong ID in your own and reads `404`;
ownership is never leaked across tenants.

## See also

* [Troubleshooting: SIP trunk down or calls failing](/channels/voice/sip-trunks-troubleshooting)
* [SIP trunk first call: the agreement-to-confirmation walkthrough](/guides/sip-trunk-first-call-walkthrough)
* [Connect a SIP trunk end to end](/guides/sip-trunk-setup)
* [Connect a SIP trunk (BYOC)](/guides/sip-trunk-connection)
* [Number health](/numbers/health)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.