↑ ↓ to navigate · ↵ to open
Documentation menu
Getting started
Building calls
Operate
Operate
Errors
Every error uses a standard HTTP status code and a small JSON body. There's one shape for the whole API — you never need a different parser for a different endpoint.
The error body
A failed request returns the matching status code and:
{ "detail": "Call not found." }
detail is a human-readable string meant for your logs, not for parsing — switch on the status code (and, for call outcomes, the reason code), not on the text.
Status codes
| Status | Meaning | What to do |
|---|---|---|
| 400 | Bad request — a field is missing, malformed, or not one of the allowed values. | Check detail; it names the field. |
| 401 | Missing, unknown, revoked, or suspended-account API key. | Check the Authorization: Bearer header — see Authentication. |
| 402 | Insufficient wallet balance to complete the action (acquiring a number, placing a call). | Top up the wallet, then retry. See Wallet. |
| 403 | The account is suspended, or the action is blocked for this resource (e.g. a destination outside your allowlist). | Contact support if this is unexpected. |
| 404 | The resource doesn't exist, or doesn't belong to your account. | Double-check the uuid/sid — we never leak another account's resources as a 403. |
| 409 | Conflict — the resource is in the wrong state (a number already taken), or a duplicate Idempotency-Key request is still in flight. | See idempotency. |
| 429 | Too many requests — a per-account traffic cap. See Rate limits. | Back off and retry; for calls, the refusal also carries a LIMIT.* reason code explaining which cap. |
| 500 | Something broke on our end. | Safe to retry (idempotently for money-moving calls). If it persists, contact support with the request's timestamp. |
When a call itself is refused
An originate that returns 402 or 429 never creates a call — nothing was dialled, nothing was billed. That's different from a call that connects and then fails partway through: that failure shows up as a normal 200 response whose Call object carries a terminal reason_code instead. Both paths are covered by the same reason code table, so you can build one handler for "why didn't/doesn't this call work" regardless of which stage it failed at. That table is generated straight from our internal code registry, so it's always current — no separate spec to fall out of sync with.
Tip: 402 (top up) and 429 (slow down / raise your cap) are never the same code — see Events & codes for why that distinction matters for how you react.