The contract
SendIdempotency-Key: <opaque-string> on a mutating request. Within
5 minutes of the first response, any retry with the same key returns
the same status code and body, byte-for-byte, without re-executing
the mutation.
The cache is scoped per (API key, Idempotency-Key), so different
accounts sending the same key never collide.
Where it applies
| Endpoint | Idempotent |
|---|---|
POST /v1/workflows | ✅ |
POST /v1/workflows/{id}/clips/{clip_id}/tracks | ✅ |
POST /v1/workflows/{id}/renders | ✅ |
POST /v1/ledger/reserve | ❌ (each call is a distinct hold) |
POST /v1/ledger/commit | ✅ (committing an unknown token is a no-op) |
POST /v1/ledger/refund | ✅ |
Pattern: generate the key once
${tool_name}-${workflow_id}-${YYYY-MM-DD}
so the same prompt on the same day collapses to one underlying mutation.
What gets cached
The cache stores{ status, body, ts }. After 5 min the entry is
evicted; the cache is capped at 500 entries (LRU). A retry after the
TTL window does re-execute, design for that.
What doesn’t get cached
Failures withcode: 'unauthenticated' or other 4xx envelopes still
bypass, we don’t want a retry blocked by a transient auth issue.