Reference

Idempotency

Retry a request safely without paying twice. Stripe's convention, backed by a database constraint rather than a cache read.

A network timeout does not tell you whether the work happened. Send an Idempotency-Key and the retry is safe.

curl https://api.dawnstackai.com/v1/chat/completions \
  -H "Authorization: Bearer $DAWNSTACK_API_KEY" \
  -H "Idempotency-Key: 8f2a1c94-6e3b-4d5a-9c11-2f7e0a1b3d44" \
  -H "Content-Type: application/json" \
  -d '{"model":"llama-3.1-8b","messages":[{"role":"user","content":"Hello"}]}'
import uuid

key = str(uuid.uuid4())   # generated ONCE, reused across every retry of this request

reply = client.chat.completions.create(
    model="llama-3.1-8b",
    messages=[{"role": "user", "content": "Hello"}],
    extra_headers={"Idempotency-Key": key},
)

Generate the key once, before the first attempt, and reuse it for every retry of that same request. A key generated inside the retry loop protects nothing.

What happens on a repeat

SituationResponse
Same key, same body, first request finishedThe original response, replayed, free. Carries Idempotent-Replay: true
Same key, same body, first request still running409. Wait a moment and retry
Same key, different body422. A key identifies one request, not a slot
Same key, more than 24 hours laterTreated as new. Records expire

A replay is byte-identical to the original, including the id, the token counts and the cost. It is not re-run and it is not charged again.

The claim is a database constraint

Two consequences you can rely on:

  • A failed request releases its key. A crash does not lock you out of the retry the failure was inviting.
  • A claim that is never completed expires after five minutes. A worker that dies mid-request does not leave a key nobody can ever use.

Not with streaming

Idempotency-Key plus stream: true is a 400. Replaying a stream from cache would mean buffering every response on the chance of a retry. Refusing is honest; accepting the header and quietly ignoring it would let you believe you were protected when you were not.

When to use it

Any request where a double charge matters and a retry is plausible: a queue worker, a webhook handler, anything behind a proxy with its own timeout. It costs nothing when nothing goes wrong.