Skip to main content

Worked SIP credential samples

SIP credentials are usually the first calls a contact-center integration makes — they register each agent’s softphone or desk phone. Copy a request as written, substitute your own ids, and compare the response envelope. Successful writes return { data, meta }; failures return the { error, meta } envelope. The retry-vs-surface matrix for every class sits at the bottom of this page. A credential owns a softphone registration on the inbound SIP edge: the device REGISTERs against sip.orbit.devotel.io, inbound calls ring it, and outbound usage (if enabled) is tracked against the credential. The samples below pair cURL with Node — reads use a raw fetch; the SIP-credential surface has no typed Node SDK resource yet, so the write tabs use the orbit.request escape hatch pattern from the API recipes.

Page the credentials

GET /api/v1/sip-credentials
Lists non-deleted credentials newest-first with keyset pagination. limit defaults to 25 and caps at 200; a value above the cap is silently clamped, not rejected. When meta.pagination.has_more is true, pass meta.pagination.cursor back as the cursor query parameter for the next page. Request
Response
Every row carries the connection details a handset needs (sip_server, sip_realm, ports) so a per-row read is not required to configure a device. The plaintext password is never in a list row.

Create a SIP credential

POST /api/v1/sip-credentials
Issues a credential and returns the plaintext password exactly once — save it immediately; it is not recoverable. label is the only required field; it is lowercased and slugified into the SIP username, which stays stable across password rotations. This example wires a front-desk handset: an extension, a fixed caller ID, recording-on, and an IP allow-list. Request
Response
Point the handset at sip_server + username + the one-time password; the create response is the only place the password appears. defaultCallerIdE164 is ownership-checked — a number your organization does not own is rejected with a 403 (folded into the matrix below, since “pick a number you own” is obvious from the message).

Rotate a password

POST /api/v1/sip-credentials/{id}/rotate
Generates a new password and invalidates the old one instantly. The username does not change, so registered devices keep working after you update the password field. The new plaintext password is returned exactly once, same rule as create. Request
Response

Force-unregister a device

POST /api/v1/sip-credentials/{id}/unregister
Revokes the live registration binding — the handset drops off the network immediately, and will re-register on its next re-REGISTER (default ~60s) unless you also disable the credential with a PATCH enabled: false. Use this for a stolen phone or a sticky NAT binding. Request
Response

Errors worth branching on

These failures cover the create, rotate, unregister, and read calls above plus the update (PATCH) and delete calls on the same page. Each block is a full { error, meta } envelope as the API returns it, and the matrix at the bottom answers retry vs surface for the same classes. For the platform-wide decision table these branches plug into, see the error handling guide.

403 — scope or caller-id ownership

403
A 403 on create or rotate means the key lacks the write scope — developer and viewer roles can read credentials, and admin or owner is required to create or modify, so branch on the role and surface instead of retrying. The same 403 shape also fires when defaultCallerIdE164 names a number your organization does not own — the call is rejected before the credential is created.

409 — duplicate label or extension

409
Recreating the same label, or reusing an extension number already taken in your organization, returns this 409 CONFLICT — pick a new label or rotate the existing credential instead of blind-retrying. This is the same branch a teams-client codes on duplicate name: the client decides whether to label the device differently or PATCH the existing row.

404 — stale or foreign id

404
A 404 on get/update/rotate/unregister/delete means the sipcred_* id does not exist in your organization (or was soft-deleted) — re-list credentials and branch on the current id rather than retrying the stale one.

60-second retry matrix

Provision a SIP trunk and take the first call

A SIP credential is Orbit’s per-device trunk identity: it authenticates one user agent at the SIP edge, holds its registration, and carries the outbound controls you set on it. The worked chain below takes one device from an empty organization to a registered, calling credential, then rotates it without dropping the device. (Interconnecting a whole PBX rather than a device? Start from Connect a SIP trunk end to end instead; the credential chain below is the device-side equivalent.)

1. Issue the credential

POST /api/v1/sip-credentials
Create the credential with a label and outbound enabled. The 201 returns the per-credential registration details the device registers against: username at sip_server (digest realm sip_realm), TLS on 5061 with SRTP mandatory. The password field appears exactly once, in this response; save it before the response scrolls away. Request
Response
Configure the device with username, the one-time password, sip_server on port 5061 (TLS), and sip_realm where the client asks for a realm. That is the whole SIP account; there is nothing else to wait for. The optional userId body field links the credential to a user in your organization — its value reads back as user_id on every response row. When an inbound call rings a linked credential, that user’s phone also receives a native incoming-call push (PushKit on iOS, high-priority FCM on Android) that wakes the OS call UI even when the app is locked or force-quit, in addition to the organization-wide ring alert. A userId that is not a live member of the organization is rejected with 403 FORBIDDEN on both create and update; userId: null on a PATCH unlinks and restores alert-only behaviour. Unlinked credentials behave exactly as before. Detail: Link a SIP extension to a user.

2. Confirm the reachable state

GET /api/v1/sip-credentials/{id}
The device REGISTERs within seconds of being configured. Read the credential back and watch registered flip to true with a fresh last_register_at; a 401 loop on the device means the password was mistyped or already rotated (see the failure list in SIP credentials provisioning). Request
Response

3. Register and originate

With the binding live, the device originates outbound calls through the same registration: dial any destination from the user agent and the edge applies the credential’s caller-ID mode, spend cap, and country block list. No further API call is needed to place the call from the device itself. To originate from the API side instead, or to land a billable test call on a PBX trunk, follow SIP trunk first call walkthrough: it runs the pre-save probe, saves the trunk with the probe verdict, and confirms media end to end with POST /api/v1/voice/sip-trunks/{id}/test-call. On the credential side, the equivalent confirmation is the read above: keep registered: true and a fresh last_register_at (an OPTIONS qualify from your SBC keeps the Contact fresh between calls).

4. Rotate with an overlap window

Zero-downtime rotation is two calls against two credentials: issue the replacement, then give the old credential a future expiresAt (its scheduled disable time) so both passwords authenticate during the change window. Devices reconfigured onto the new credential register immediately; devices still on the old one keep working until expiresAt passes. Issue the replacement
Schedule the old credential’s end of life
During the overlap window (here: now until 2026-10-23 18:00 UTC) both credentials authenticate, so reconfiguring the fleet can happen device by device instead of in one cut-over. After the window, the old credential stops authenticating on its own; DELETE it then, or leave it expired until you do. For an immediate single-credential password change (lost device, leaver) use POST /{id}/rotate instead: the username stays, the old password dies at once.

Keep going