Idempotency and retries
Networks fail: a request may time out after the message was already accepted. To retry without sending the message twice, give POST /v1/messages an Idempotency-Key header.
bash
curl -X POST https://api.ace-send.com/v1/messages \
-H "Authorization: Bearer $ACE_SEND_API_KEY" \
-H "Idempotency-Key: deposit-88123-confirmation" \
-H "Content-Type: application/json" \
-d '{"to": "+5521998120937", "template": "deposit_ok", "language": "pt"}'How it works
- The key is 1–64 printable ASCII characters (no spaces). Derive it from your own event — an order id, a deposit id plus the kind of message — rather than a random value per attempt.
- A repeat with the same key and the same body within 24 hours answers the message of the first request: the same
202and the same id, with the headerIdempotent-Replayed: true. No second message is sent or charged. - The same key with another body:
409 idempotency_conflict. - A repeat while the first request is still running:
409 idempotency_in_progress— retry in a moment. - A refused request (
4xx) is not remembered: fix it and send again with the same key. - Keys are shared by all keys of the account, test and live; a key used in one mode answers
409 idempotency_conflictin the other.
When to retry
| Answer | Retry? |
|---|---|
| No answer, a timeout, a connection error | Yes, with the same Idempotency-Key |
429 | Yes, after the seconds of Retry-After |
500, 502, 503, 504 | Yes, with backoff and the same Idempotency-Key |
409 idempotency_in_progress | Yes, after a second or two |
409 insufficient_funds | After a top-up |
Other 4xx | No: fix the request first |
Back off exponentially with jitter — for example 1, 2, 4, 8 seconds plus a random part — and stop after a few attempts or when the message is no longer relevant (a one-time code a minute later).
By code:
| Code | Retry? |
|---|---|
bad_request | After fixing the request |
api_key_invalid | After fixing the request |
api_key_ip_denied | After fixing the request |
account_suspended | No |
api_key_scope | After fixing the request |
free_text_not_allowed | After fixing the request |
not_found | No |
template_not_found | After fixing the request |
method_not_allowed | After fixing the request |
payload_too_large | After fixing the request |
validation_failed | After fixing the request |
invalid_number | No |
recipient_stopped | No |
destination_unavailable | No |
message_too_long | After fixing the request |
template_unavailable | After fixing the request |
insufficient_funds | Yes, later |
idempotency_conflict | After fixing the request |
idempotency_in_progress | Yes, later |
too_many_requests | Yes, later |
daily_limit_reached | Yes, later |
server_error | Yes, later |
service_unavailable | Yes, later |