Skip to main content
500CallsDocs
Browse the docs

Idempotency and retries

Networks fail. If a send times out you cannot tell whether we received it, and sending it again could text your customer twice. An Idempotency-Key header makes a retry safe.

Send a key with every POST

HTTP
POST /v1/sms/messages HTTP/1.1Authorization: Bearer 500c_live_…Content-Type: application/jsonIdempotency-Key: order-78123-otp

A key is 1 to 64 characters from A-Z, a-z, 0-9, _ and -. Use a value from your own records, such as an order ID, so a retry after a crash uses the same key. Every POST takes one, and every send should carry one.

What a retry gets

Within 24 hours of the first request finishing, a request with the same key gets:

You sendYou get
The same bodyThe first response again, byte for byte, with Idempotent-Replayed: true. Nothing is sent or charged twice
A different body409 idempotency_key_reused
The same body while the first request is still running409 conflict: wait a second, then retry

A key belongs to one endpoint: the same key on /v1/sms/messages and on /v1/sms/messages/bulk counts as two keys, and a cancel's key belongs to that message's cancel. The deprecated POST /v1/messages shares the keys of POST /v1/sms/messages, so a retry can move from one path to the other.

Only successes are kept

A key keeps its response only when the request succeeded. When the first request with a key fails, with a 4xx or a 5xx, nothing is kept and the key is free again: fix the request if it was refused, then retry with the same key. A 409 from the table above is different: it refuses only the later request, and the key stays with the first one.

Which errors to retry

CodeRetry?
rate_limited (429)Yes, after the Retry-After seconds
service_unavailable (503)Yes, after the Retry-After seconds, with the same key
internal_error (500)Yes, with the same key
conflict (409) while a key is in progressYes, after a second
insufficient_balance (402)After you top up
Any other 4xxNo: fix the request first

Back off between retries: wait 1 second, then 2, then 4 and so on, up to a minute. Retry a timeout with no response the same way, with the same key.