Errors and limits

Error shape

Errors return a JSON body with a stable machine-readable code alongside the HTTP status:

{
  "error": {
    "code": "not_found",
    "message": "Workflow not found",
    "request_id": "3f2a9c0e8b7d4e1f9a6b5c4d3e2f1a0b"
  }
}

Branch on the code, not on the message text - messages are written for humans and follow the request's Accept-Language, so they change.

Responses also carry the same id in an X-Request-ID header. Include it when you contact support about a failed request.

Two responses do not use this shape:

  • Request validation. A body, path or query parameter that fails schema validation returns 422 with a detail list, one entry per problem: {"detail": [{"type": "missing", "loc": ["body", "name"], "msg": "Field required", ...}]}.
  • Unknown routes. A path or method that does not exist returns {"detail": "Not Found"} (or "Method Not Allowed").

Status codes

StatusMeaning
400The request was malformed or a value was invalid.
401Missing or invalid API key (authentication_required). An API key sent as Authorization: Bearer is also a 401.
402Out of credit (insufficient_credit) or over a plan limit (quota_exceeded). Retrying will not help until the balance or plan changes.
403Authenticated, but not allowed to do this (permission_denied).
404It does not exist, or it is not in this organization.
409It conflicts with the current state - e.g. an agent already in the environment you promote it to.
413An uploaded file is too large (file_too_large).
422The request was understood but the content was not valid.
429Too many requests (rate_limited), or too many live calls at once (concurrency_limit).
5xxSomething went wrong on our side, or at an upstream model or telephony provider (502, 503).

A resource in another organization returns 404, not 403. That is deliberate: telling you something exists but is not yours is itself a disclosure.

Rate limits

Requests can be rate limited per organization, per API key and per client address. On a rate_limited response, wait for the number of seconds in the Retry-After header before trying again, and back off exponentially with jitter if it repeats - not a tight loop.

Treat 429 as a signal rather than a number to hard-code: the ceilings are not a fixed part of the API contract.

Concurrency

Separately from request rate, an organization can be capped on how many voice calls run at once. Over that ceiling a new call is refused rather than queued. An outbound phone call is refused only when it connects, not when you request it, so pace an outbound burst yourself. Campaigns already pace themselves against it.

Retrying

5xx and 429 are worth retrying. 4xx other than 429 will fail again the same way, so fix the request instead.

There is no idempotency key: a request that reached the server before your client gave up has run, and retrying it runs it again. That matters most for anything that places a call. Before retrying a POST /calls that timed out, check the call list for the first attempt.