All errors return a JSON body with an error code and a human-readable message:
Use the error field for programmatic handling. Use message for logging and debugging — it is not guaranteed to be stable across releases.
Error codes
Handling errors in TypeScript
Retrying on 429 and 5xx
429 Too Many Requests — the response includes a Retry-After header (in seconds) and a retryAfter field in the JSON body. Wait at least that long before retrying.
500 Internal Error — these are transient. Use exponential backoff with jitter: wait 1s, then 2s, then 4s, up to a reasonable cap. Do not retry indefinitely.
Example exponential backoff in TypeScript:
Idempotency
The /v1/messages/send and /v1/sms/send endpoints are not automatically idempotent. If you retry a send operation, you may deliver the message twice. To avoid duplicate sends:
- Track delivery state on your side before retrying
- Only retry on 5xx errors, not on 429s for sends — instead, queue and respect the
Retry-After window
- For transactional sends, use a unique identifier in your request body that you check before resending
Next: Rate limits → Last modified on March 19, 2026