Troubleshooting: authentication, key mode, and IP allowlist failures
Every request to the Orbit API passes through the same chain of gates: the credential resolves, the key’s expiry and revocation state is checked, the sandbox/live key mode is compared against the workspace, the source IP is matched against the allowlist, and the key’s scopes are checked against the route. A rejection tells you which gate said no — but only if you read thecode, since several gates share the
same HTTP status. This page maps every authentication rejection code
to its gate and the fix, then covers the SAML/SCIM gates enterprise
tenants hit at login and provisioning time.
Find the code on your response in the table, then jump to the section.
Several gates deliberately return generic codes. A per-key IP
allowlist block returns
INVALID_API_KEY (not IP_NOT_ALLOWED) so a
leaked key cannot enumerate your allowlist. A revoked key is reported
as EXPIRED_TOKEN with the message “The API key has been revoked.”
Read the message and code together, and treat the response
envelope’s status field as authoritative.The 401 family: UNAUTHORIZED, INVALID_API_KEY, EXPIRED_TOKEN
UNAUTHORIZED is the generic refusal: no X-API-Key header (or no
dashboard session) reached the route, the value was truncated, or it
carried a character set the key format never uses. Confirm the header
name is X-API-Key and the full key value is sent — prefixes like
dv_live_sk_ alone are not a key.
INVALID_API_KEY means the key resolved to nothing usable. Work the
causes in order:
- Wrong key value. Re-copy the key from Settings → API Keys. The full secret is shown once at creation; if you lost it, create a replacement and revoke the old one.
- Revoked key. Keys revoked in the dashboard stop authenticating immediately. Check the key’s state under Settings → API Keys.
- Per-key IP allowlist. If the key has an
allowed_ipslist and your request originates outside it, the rejection isINVALID_API_KEYby design. See the IP allowlist section below. - Workspace mismatch. A key copied from a different organization never authenticates here — create one in this workspace instead.
EXPIRED_TOKEN on an API-key request has exactly two causes:
- The key’s configured expiry time passed. Create a replacement key and update your integration; expiry cannot be extended in place.
- The key had a scheduled revocation cut-off (
revoke_at) that has arrived. The key is treated as revoked from that moment regardless of any scheduler timing — rotate to a new key.
The key-mode split: sandbox vs live
Orbit separates sandbox and live state hard: a sandbox key must never authenticate into a live workspace, and a live key must never authenticate into a sandbox workspace. The mode comes from the key prefix — adv_test_sk_ key is sandbox-mode, a dv_live_sk_ key is
live-mode — and the API compares it against the workspace the key
belongs to. On a mismatch the request fails with 403 WRONG_KEY_MODE
before any handler runs, and nothing is read or written.
The two directions and their fixes:
The day-one pattern is the first row: integrate and test with a
dv_test_sk_ key, then switch to dv_live_sk_ at go-live. Test sends
in sandbox deliver to magic numbers and simulate provider outcomes;
live keys send real traffic and debit the wallet. The
go-live checklist walks the full switch.
The IP allowlist gates
Orbit has two independent IP allowlists, and they fail differently:- Per-API-key allowlist — a list of source IPs or CIDR ranges on
one key, managed through the key’s
allowed_ipsfield. A request from a non-allowed source is rejected with401 INVALID_API_KEYbefore any other gate runs, and the rejection is deliberately indistinguishable from an unknown or revoked key. Setup, validation rules, and the audit trail are in Per-API-key IP allowlist. - Org-level allowlist — a workspace-wide list gating the dashboard
and SAML login surfaces and API requests that carry a session or
key. A request from a non-allowed source IP is rejected with
403 IP_NOT_ALLOWEDand the message “Your IP address is not in the allowlist.”
- Determine which gate. A
403 IP_NOT_ALLOWEDis the org-level list; a401 INVALID_API_KEYthat only appears from certain networks is the per-key list. - Confirm your egress IP as the API edge sees it (your NAT /
proxy’s public address —
curl https://api.orbit.devotel.io/api/v1/mefrom the same host and check which call fails where). - Compare against the list: Settings → Security for the org-level
list, or
GET /api/v1/settings/api-keys/{keyId}/allowed-ipsfor a per-key list. - Add the egress IP or its CIDR range, or clear the list (
nullor[]) to make a per-key list unrestricted again.
Public-key write attempts: 422
Public keys (dv_..._pk_), which exist to be embedded in browser or
mobile client code, are restricted to read-only scopes at creation.
Requesting a write or administrative scope — messages:write,
contacts:write, admin, the * wildcard, or the sensitive reads
billing:read / settings:read — on a public key is rejected at
create time with a 422.
This is a key-creation gate, not a per-request one: you hit it when
creating or updating the key, not when calling an endpoint. The fix is
never to find a way around it — put a secret key (dv_..._sk_) on your
backend for anything that sends or modifies data, and keep the public
key’s scopes to the minimum reads the client needs. The
FAQ: Are public keys read-only?
covers the scope split; Authentication covers key
formats end to end.
Webhook rejections: STALE_WEBHOOK (401)
STALE_WEBHOOK fires on inbound webhook and DLR receiver surfaces when
the delivery’s timestamp is missing or falls outside the allowed replay
window — it is the clock-skew and replay-attack guard for provider
callbacks, not for requests you authenticate toward the API. If your
own webhook endpoint rejects Orbit deliveries with a 401, that is your
signature verifier, and the failure classes (raw-body parsing, rotated
secrets, mutated bodies, clock skew) are covered in
Signature verification failures
and Webhook security.
SAML and SCIM gates (enterprise tenants)
These gates surface on the login and provisioning path, not on API-key traffic.SAML_USER_NOT_IN_ORG
The identity provider assertion succeeded cryptographically — the user proved who they are — but the SAML callback could not attach them to the workspace: the asserted email belongs to a different organization, or there is no invitation or SSO enforcement covering it on the callback organization.- The user must exist in the organization they sign into — invite them (or have SCIM provision them) before the first login.
- If the same email is a member of two organizations, SSO enforcement decides which one the assertion attaches to; signing in with the other organization configured as the SSO target fails with this code.
- Re-check the IdP’s org slug in the SAML login URL — pointing the IdP at the wrong workspace produces exactly this rejection.
SCIM_ROLE_CEILING_EXCEEDED
A SCIM group/role push asked Orbit to assign a role above the organization’s configuredmax_assignable_role ceiling (the default
ceiling is admin). The provisioning request is refused and nothing
is assigned.
- Map IdP groups only to roles at or below the ceiling; keep
owner-level assignment to the dashboard. - If a group genuinely needs the higher role, an owner raises the ceiling in the workspace’s SSO/SCIM settings — the ceiling is a tenant-owned control.
What to send support
If the rejection survives the fixes above, open a support ticket with:- Your tenant ID (dashboard → Settings → Organization; also
organizationIdfromGET /api/v1/me). - The error code and message exactly as returned, and the
request_idfrom the response’smetablock — these let support find the exact gate decision. - For key issues: the key prefix (
dv_live_sk_…/dv_test_sk_…) and whether the key has an IP allowlist configured. Never send the full secret value. - For an IP allowlist lockout: the source IP you are calling from as your egress sees it, and the list you believe is blocking it.
- For SAML/SCIM: the IdP (Okta, Entra ID, …), the org slug in the SAML URL, the asserted email’s domain, and for SCIM the role the IdP tried to push.
See also
- Authentication — key formats, creation, and rotation
- Per-API-key IP allowlist — setup and validation rules
- Go-live checklist — the sandbox-to-live switch
- Error codes reference — every code in the authentication group
- Signature verification failures — webhook-side 401s
- SCIM 2.0 provisioning — IdP-driven user and role provisioning