Errors
Every error uses the same envelope: status is "error", message is readable text, and error_code is a stable value to branch on.
{
"status": "error",
"message": "to_number is not valid E.164",
"error_code": "invalid_phone_number",
"data": { "field": "to_number" }
}Codes
| Code | HTTP | Meaning |
|---|---|---|
invalid_api_key | 401 | The x-api-key header is missing or the key does not exist. |
key_revoked | 401 | The key was revoked in the portal. |
key_expired | 401 | The key passed its expiry date. |
invalid_token | 401 | The portal session expired — sign in again. |
account_suspended | 403 | The workspace is suspended. Contact support. |
invalid_phone_number | 422 | A number is not E.164 (+ country code, digits only). data.field says which. |
missing_required_field | 422 | A required field is missing or empty. data.field says which. |
invalid_request | 400 | The body is not valid JSON, or a field has the wrong type. |
content_too_long | 422 | The text is longer than 10 SMS segments. |
premium_rate_blocked | 403 | Premium-rate destinations are not allowed. |
duplicate_request | 409 | This request_id was already used; data has the original message id. |
no_device_available | 503 | No online phone is paired with from_number. Open the app on the phone and check it has internet. |
new_account_limit | 429 | New workspaces can send 50 live messages in their first 24 hours. |
rate_limit_exceeded | 429 | Too many requests — wait for the Retry-After seconds. |
not_found | 404 | The id does not exist in your workspace. |
invalid_url | 422 | Webhook URL must be public HTTPS. |
invalid_events | 422 | Unknown webhook event name. |
no_recipients | 422 | A campaign has no one left to send to (all opted out or blocked). |
too_many_recipients | 422 | A campaign is limited to 10,000 recipients. |
internal_error | 500 | Unexpected server error. Retry once; if it persists, contact support. |
Retrying
429and503are safe to retry after a pause.4xxvalidation errors will fail the same way until the request is fixed.- Pass a
request_idwhen sending so a retry after a timeout can never send twice.