Error handling
All API errors return a consistent JSON format with an appropriate HTTP status code.
Error response format
Section titled “Error response format”Every error response follows this structure:
{ "success": false, "error": "Human-readable error message"}Successful responses omit the error field and include the relevant data directly. Some successful responses include "success": true (notably the admin API), but most 2xx responses use a bare result shape and do not wrap data in a success envelope. Treat the presence or absence of success: true on success bodies as not load-bearing; rely on the HTTP status code.
HTTP status codes
Section titled “HTTP status codes”400 Bad Request
Section titled “400 Bad Request”The request is malformed or contains invalid parameters.
| Error message | Cause | Fix |
|---|---|---|
Missing X-App-ID header | The X-App-ID header was not provided. | Include X-App-ID: your-app-id in every API request. |
Invalid X-App-ID format | App ID contains disallowed characters or exceeds 64 characters. | Use only alphanumeric, underscores, hyphens. Max 64 chars. |
Invalid request body | The JSON body could not be parsed. | Ensure valid JSON with Content-Type: application/json. |
Invalid command | The command path in the URL is not recognized. | Check the command path, e.g. answer, playback/start, record/stop. |
urls is required | A playback or play_and_get_digits command is missing urls/prompt_files. | Include an array of HTTP/HTTPS URLs in the request body. |
Invalid command_uid format | The command_uid field contains disallowed characters. | Use only alphanumeric, dots, hyphens, underscores. Max 128 chars. |
401 Unauthorized
Section titled “401 Unauthorized”Authentication credentials are missing or invalid.
| Error message | Cause | Fix |
|---|---|---|
Missing API key | The X-API-Key header was not provided. | Include X-API-Key: your-api-key in every request. |
Invalid API key | The provided API key does not match the configured key for this app. | Verify the key matches the one set via POST /admin/apps/{app_id}. |
Missing X-Admin-API-Key header | An admin endpoint was called without the admin key header. | Include X-Admin-API-Key: your-admin-key for admin endpoints. |
Invalid admin API key | The admin API key does not match the server’s ADMIN_API_KEY. | Verify the key matches the ADMIN_API_KEY env var on the server. |
403 Forbidden
Section titled “403 Forbidden”You are authenticated but not authorized to access this resource.
| Error message | Cause | Fix |
|---|---|---|
Session belongs to a different application | Your app ID does not match the session’s owning app. | Sessions are bound to the app that receives them. You can only control your own sessions. |
Room belongs to a different application | Your app ID does not match the conference room’s owning app. | Conference rooms are scoped to the app that created them. |
404 Not Found
Section titled “404 Not Found”The requested resource does not exist.
| Error message | Cause | Fix |
|---|---|---|
Session not found | No active session exists with the given UUID. | Verify the session UUID. The session may have already ended. |
Room not found | No conference room exists with the given room_id. | Verify the room_id. The room may have been destroyed. |
409 Conflict
Section titled “409 Conflict”The request conflicts with the current state of the resource.
| Error message | Cause | Fix |
|---|---|---|
Conference name already taken | A conference with the same name already exists for your app. The response includes the existing room_id. | Use a different name or use the returned room_id. |
Session is already in a different conference room | The session is in another conference. | Call conference/leave before joining a different room. |
Session is already muted / unmuted | The mute state is already what you requested. | Check the current mute state before toggling. This is an idempotency guard. |
413 Payload Too Large
Section titled “413 Payload Too Large”The request body exceeds the per-route size limit. The default limit is 1 MiB; the per-session command route (POST /api/v1/sessions/{uuid}/commands/{command}) uses a tighter 64 KiB limit because command payloads are small by design.
| Error message | Cause | Fix |
|---|---|---|
Request body too large | The body exceeds the route’s maximum size (1 MiB default; 64 KiB on session command routes). | Reduce the payload. Command payloads should contain only small fields. Do not embed audio or other large data inline. |
415 Unsupported Media Type
Section titled “415 Unsupported Media Type”The request was sent without a Content-Type header, or the header value is not application/json. Routes that decode a JSON body require the header on every request that carries a body. Action endpoints that take no body (e.g. conference/leave, /conferences/{room_id}/stop) do not require it.
| Error message | Cause | Fix |
|---|---|---|
Content-Type must be application/json | The request omits Content-Type or sets it to a non-JSON value (charset parameters like application/json; charset=utf-8 are accepted). | Set Content-Type: application/json on every request that carries a JSON body. |
429 Too Many Requests
Section titled “429 Too Many Requests”You have exceeded the rate limit. See Rate limits for details.
| Error message | Cause | Fix |
|---|---|---|
Rate limit exceeded | Too many requests from this app/IP within the rate window. | Back off and retry. Check your per-app rate_limit configuration. |
Command rate limited | A command was sent too quickly after a previous command in the same rate group. | Wait for the cooldown before sending the next command. |
500 Internal Server Error
Section titled “500 Internal Server Error”An unexpected error occurred on the server.
| Error message | Cause | Fix |
|---|---|---|
Internal error validating API key | The server could not look up the app configuration (e.g. Redis unavailable). | Server-side issue. Retry after a short delay. |
Internal server error | An unexpected condition occurred. | Retry. If it persists, contact the gateway administrator. |
503 Service Unavailable
Section titled “503 Service Unavailable”The server is not ready to handle the request.
| Error message | Cause | Fix |
|---|---|---|
Admin API not configured | The ADMIN_API_KEY environment variable is not set. | Server configuration issue. The administrator must set ADMIN_API_KEY. |
Recording not available | Recording is not enabled on this gateway. | Operator configuration issue. Contact the operator to enable the recording service. |
Best practices
Section titled “Best practices”- Always check the HTTP status code first. A 2xx status means the request was accepted. Any other status indicates an error.
- Parse the
errorfield for details. Error messages are designed to be human-readable and actionable. - Handle 429 with exponential backoff. When rate-limited, wait before retrying. Do not retry in a tight loop.
- Treat 5xx errors as transient. Retry with backoff. If the error persists, escalate to the gateway administrator.
- Do not rely on error message text for programmatic logic. Use HTTP status codes for branching. Error messages may change.