Errors
Errors are JSON: {"error": {"code": "country_not_allowed", "message": "…"}}. Branch on code, show message to developers.
| HTTP | code | Meaning / what to do |
|---|---|---|
| 400 | bad_request |
Invalid JSON or an unknown field. |
| 401 | unauthorized |
Missing, wrong, revoked key, or the project / organisation is suspended. |
| 403 | forbidden |
The key lacks the scope for this endpoint. |
| 404 | not_found |
No such message / template / webhook in this project. |
| 409 | idempotency_conflict |
Same idempotency key, different content. |
| 409 | not_cancelable |
The message already left the queue. |
| 422 | invalid_request |
A field is wrong; message says which. |
| 422 | country_not_allowed |
Only Mauritian mobiles (+230 5xxx xxxx). |
| 422 | recipient_suppressed |
The number opted out (opt-out link or STOP) or is on your do-not-contact list. |
| 429 | quota_exceeded |
Project quota reached (see /v1/usage); Retry-After header. |
| 429 | recipient_rate_limited |
Too many messages / codes to one number; wait. |
| 429 | otp_cooldown |
Wait 30 s before sending another code to that number. |
| 429 | rate_limited |
More than 50 requests per second with one key. |
| 500 | internal |
Our side. Safe to retry with the same idempotency key. |
Message failure codes (error_code on a failed message)
NO_SERVICE, RADIO_OFF (no signal / airplane mode), GENERIC_FAILURE (often: SIM out of credit or SMS bundle),
SIM_UNAVAILABLE, INVALID_NUMBER, DELIVERY_FAILED (carrier could not deliver), LIMIT_EXCEEDED (Android's own
rate limit), DISPATCH_TIMEOUT (the phone did not answer), EXPIRED_ON_DEVICE, APP_ERROR.
Phone-level failures are retried; 5 in a row pause the phone for 30 minutes and alert the organisation's admins.