Error Handling
All errors return JSON nested under err:
{ "err": { "message": "<message>", "code": "<symbolic_code>" } }.
code is present on validation and feature-gate errors and
defaults to INTERNAL_ERROR otherwise. HTTP status codes
follow standard semantics.
| Status | Meaning | Common causes |
|---|---|---|
| 400 | Bad Request | Validation failure, missing required field |
| 401 | Unauthorized | Missing or invalid token |
| 403 | Forbidden | Token valid but lacks the required permission or admin gate |
| 404 | Not Found | App doesn't exist OR your token can't access it (deliberately the same to avoid existence leaks) |
| 409 | Conflict | Optimistic-concurrency mismatch, idempotency-key collision, phone-number conflict |
| 429 | Too Many Requests | Rate limit hit |
| 500 | Internal | Platform error — captured in our monitoring |
Common code values:
APP_NOT_FOUND,VALIDATION_ERRORINSUFFICIENT_BALANCE,INSUFFICIENT_POOL_BALANCEEXPECTED_VALUE_MISMATCHPHONE_NUMBER_IN_USEFEATURE_FORBIDDEN(RBAC feature gate),API_KEY_SCOPE,INTERNAL_ERROR(default). Note: some ad-hoc 403s carry nocodeand fall back toINTERNAL_ERROR.
Retry recommendations:
429: backoff (start 1s, double up to 60s).500: retry once after 1s; escalate tosupport@everycallhandled.comif persistent.409on idempotency-key collision: treat as success (the prior call landed).