Error Handling
All API errors use a consistent JSON structure and appropriate HTTP status codes.Response format
Errors include a top-levelerror object and a meta object:
- code: Machine-readable error code (e.g.
validation_error,not_found,rate_limit_exceeded). - message: Human-readable description.
- details: Optional object with extra context (validation fields, IDs, etc.).
- meta.request_id: Use this when contacting support.
- meta.ts: Server timestamp of the response.
HTTP status codes
| Status | Meaning |
|---|---|
400 | Bad request (malformed body or query) |
401 | Unauthorized (missing or invalid API key / JWT) |
402 | Payment required (trial not started, trial expired, subscription inactive, or insufficient credits) |
403 | Forbidden (e.g. IP not whitelisted) |
404 | Not found (resource or ID does not exist) |
422 | Validation error (schema or business rule) |
429 | Rate limit exceeded |
500 | Internal server error |
502 | Bad gateway (external provider error, e.g. voice or telephony provider) |
Common codes
- validation_error (422): Check
detailsfor field-level errors. Business rules (e.g. no outbound number assigned) also return 422. - payment_required (402): Billing or usage limit. The API returns 402 when the organization has no active trial or paid plan, the trial has ended, the subscription is inactive, or there are insufficient credits for the operation (e.g. voice clone, widget, knowledge base). Use
error.detailsfor context:- reason: One of
trial_not_started,trial_expired,subscription_inactive, orinsufficient_credits. - redirect_url: Optional URL to send the user (e.g.
/onboarding/trialto start a trial,/settings/billingto update payment). - balance / required: For
insufficient_credits, optional numeric fields indicating current balance and required amount. - Handle 402 by prompting the user to start a trial, subscribe, or upgrade, or by redirecting to the provided URL.
- reason: One of
- not_found (404): The resource or ID in the path/body does not exist.
- unauthorized (401): Provide a valid API key in the
Authorization: Bearer <key>header. - forbidden (403): Key is valid but action or origin is not allowed.
- provider_error (502): An external provider (e.g. voice or telephony) failed. Check the error message or, for calls,
context.last_erroron the call record. - rate_limit_exceeded (429): Respect
Retry-Afterand rate limit headers.
Best practices
- Use
meta.request_idin support requests and logs. - On
429, back off usingRetry-Afterand avoid tight retry loops. - Do not rely on message text for logic; use
error.codeand status codes.

