Esta página está disponible solo en inglés por ahora.
Errors
Every 4xx and 5xx response body uses the same envelope:
{
"error": {
"code": "channel_unavailable",
"message": "Channel is not connected. Re-pair to continue.",
"details": { "channel_id": "..." }
},
"request_id": "req_01J..."
}Match on code — it's the stable contract. message is human-readable and may change between releases. details is optional and code-specific.
The full code set ships in the Zod contract ERROR_CODES. The table below
is canonical.
Auth / identity
| Code | When you'll see it |
|---|---|
auth_missing | No Authorization header sent. |
auth_invalid | Bearer token doesn't match any active key. |
auth_malformed | Header present but not Bearer …, or token format wrong. |
auth_expired | Key has been revoked or expired. |
auth_no_email | Dashboard session token has no verified email. |
Channel lifecycle
| Code | When you'll see it |
|---|---|
channel_not_found | Channel UUID doesn't exist (or belongs to another customer). |
channel_access_denied | Channel-scoped API key being used against a different channel. |
channel_unavailable | Channel is in a terminal state (logged_out, stopped_by_user, disabled_by_admin, error, failed). |
channel_scoped_key | Key is scoped to a single channel but a multi-channel route was called. |
invalid_lifecycle_transition | Tried to connect an already-connected channel, etc. |
pair_code_unavailable | Channel state doesn't allow generating a pair code right now. |
pair_code_failed | Upstream rejected the pair code request. |
no_qr | QR not yet ready (channel hasn't booted), or no QR for this state. |
not_disabled | Tried to re-enable a channel that wasn't admin-disabled. |
concurrent_modification | Two writes collided on the same row; retry your read-modify-write. |
Plan / quota
| Code | When you'll see it |
|---|---|
plan_channel_limit | Plan's channel cap reached. Upgrade or delete an existing channel. |
rate_limited | Per-key rate limit exhausted. Honor Retry-After. |
worker_at_capacity | No worker has free slots right now — extremely rare; retry. |
Webhook + media
| Code | When you'll see it |
|---|---|
webhook_endpoint_not_found | Endpoint UUID doesn't exist. |
media_gone | Signed media token is valid but the bytes have aged out of cache. Re-fetch the source. |
Generic
| Code | When you'll see it |
|---|---|
invalid_request | Body or query failed Zod validation. details contains the issue list. |
not_found | Generic 404. |
bad_request | Generic 400 where no narrower code fits. |
no_op | The mutation was a no-op (already in the target state). |
other | Catch-all for upstream-provider errors. |
internal_error | Unhandled server-side exception. We're alerted; request_id is the trace key. |
Best practices
- Always log
request_id. Customer support uses it to find the exact request in our traces. - Match on
code, never onmessage. The messages are tuned for human readability and shift over time. - Treat unknown codes as transient. New codes get added; assume retryable until the docs are updated.
- For 429, honor
Retry-Afterinstead of guessing backoff.