Retries & idempotency
Which requests are safe to retry, how the gateway retries on your behalf, and how to make your own writes safe to repeat.
Networks fail. The question on a failed request is always: is it safe to send again? This page is the answer for revenexx.
What's safe to retry
- Reads —
GET,HEAD,OPTIONSare safe. Retry them freely with backoff. - Writes —
POST,PUT,PATCH,DELETEare not automatically safe. If a write times out or returns502, the request may already have been applied — retrying it blindly can double-apply.
What the gateway already does
The gateway retries for you in one narrow, safe case: when a request provably never reached the implementing app (the connection was refused, DNS failed, or the dial timed out). Once the app has received the request, the gateway does not retry it — because it can't know whether the write succeeded.
So a 502 or a timeout after the app was reached is handed back to you to decide on.
Making writes safe to repeat
There is no Idempotency-Key header. Make writes idempotent at the data level instead:
- Use a natural key. Create-or-update on a unique field (an order number, a SKU, an external id) so repeating the call converges on the same row rather than creating a duplicate.
- Check before you write. For non-unique creates, look up by a client-supplied reference first, or have your App dedupe on one.
- Prefer
PUTsemantics where the capability supports them — setting a resource to a known state is naturally repeatable; blindPOSTappends are not.
On a write that fails after it was sent (timeout or
502), don't retry automatically. Re-read the resource to see whether it landed, or rely on a natural key so a repeat is harmless.A practical pattern
Idempotent create
// Converge on a stable identity instead of blind-creating.
async function upsertByCode(code, data) {
const found = await getByCode(code) // GET — safe to retry
return found
? updateProduct(found.id, data) // PUT/PATCH — converges
: createProduct({ code, ...data }) // POST — guarded by the lookup
}