Skip to main content

Why idempotency keys?

Network failures and timeouts can leave you uncertain whether a POST succeeded. If you retry a generation request and the original call had actually completed, you’d be charged twice. Idempotency keys let you safely retry: the same key + same body returns the original response, never a second one.

How to use

Pass an Idempotency-Key header on POST /v1/images, POST /v1/videos, or POST /v1/files. Use any opaque value, 1 to 256 characters. UUID v4 is recommended. The vendor-prefixed header Aurous-Idempotent-Key is accepted as an alias for Idempotency-Key.
curl -X POST https://api.aurous-labs.com/v1/images \
  -H "X-Api-Key: $AUROUS_API_KEY" \
  -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "a sunset over mountains", "count": 1}'
If you retry with the same key and the same body, the original response is replayed:
HTTP/1.1 201 Created
Aurous-Idempotent-Replayed: true

Rules

ScenarioBehavior
Same key, same body — original succeededReplay the cached 2xx with Aurous-Idempotent-Replayed: true (never re-billed)
Same key, same body — original failed with 4xx invalid_requestRe-evaluated, not replayed — fix the input, then retry the same key
Same key, same body — original still in flight409 idempotency_key_in_use — the first request hasn’t finished; wait and retry to get the replay
Same key, different body or route409 idempotency_key_in_use — use a fresh key
New keyProcess normally; cache the result for 24 hours
Header omittedProcess normally; never replays

Recovering after a dropped connection

If your POST times out and you don’t know whether it landed, retry with the same Idempotency-Key:
  • If the original is still running, you’ll get 409 idempotency_key_in_use. There’s no Retry-After on this response — use your own backoff (e.g. 0.5s doubling to ~8s) and retry the same key.
  • Once it reaches a terminal state, the same key returns the original response with Aurous-Idempotent-Replayed: true. Read the generation id from that body.
Two rules make this reliable:
  1. Generate and persist your Idempotency-Key before the request, keyed to your own operation record. The 409 does not echo the original generation id, so your stored key is your only handle on the in-flight call until it completes.
  2. Only retry-loop on 409 idempotency_key_in_use if you have not changed the body or route. The same code is also returned when a key is reused with a different body or route — that’s a client bug to fix, not a transient state to wait out.

Caveats

  • Keys are scoped per team — collisions across teams are impossible.
  • Keys expire after 24 hours. After that, the same key starts fresh.
  • If a request is interrupted server-side before completing (a rare mid-flight crash), its key is held until it expires (24h), then starts fresh — no manual cleanup needed.
  • Body comparison uses canonical JSON (lexicographic key order). {"a":1,"b":2} and {"b":2,"a":1} are treated as identical.
  • The header is optional; absent header behaves like a fresh non-idempotent request every time.