Errors
Every error uses a standard HTTP status code and a small JSON body. There is one shape for the whole API. You never need a different parser for a different endpoint.
The error body
Section titled “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
Section titled “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 does not exist, or does not 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 is in flight. |
See idempotency. |
429 |
Too many requests. A per-account traffic cap. | Back off and retry; for calls the refusal also carries a LIMIT.* reason code naming which cap. |
500 |
Something broke on our end. | Safe to retry (idempotently for money-moving calls). If it persists, contact support with a timestamp. |
When a call itself is refused
Section titled “When a call itself is refused”An originate that returns 402 or 429 never creates a call. Nothing was dialled, nothing
was billed.
That is 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 this call work” regardless of which stage it failed at.