Idempotency
Use idempotency keys for write requests that may be retried by your backend.
Header
Idempotency-Key: order_123_stackfill_session
StackFill enforces at-most-once execution per (team, key) pair. The first write with a given key runs; any subsequent request with the same key replays the cached outcome — body and status are byte-identical to the original response. Keys are held for 24 hours from first use.
Concurrency contract
Two requests with the same Idempotency-Key that arrive at the same time are arbitrated atomically. Exactly one runs the mutation:
- The winner runs the handler and its response is cached.
- The loser receives either the cached response (if the winner has already completed) or
409 idempotency_request_in_progress(if the winner is still running). Retry the 409 after a short delay to pick up the cached outcome.
This is implemented with a durable D1-backed claim, not a best-effort marker — true at-most-once even under high concurrency.
Error retries
A handler that returns an error response (4xx or 5xx) also caches the outcome. A retry with the same key replays the original error. This is intentional: a POST /v1/renders that 5xx'd may have already partially executed (R2 bytes written, fonts embedded, Stripe customer created), and silently re-running on the same key would compound the side effect.
If you want a fresh attempt after a server-side failure, use a new key for the retry. The original key's snapshot remains available for replay until the 24h TTL expires.
Example
curl https://api.stackfill.com/v1/embed/sessions \
-H "Authorization: Bearer stackfill_live_sk_REPLACE_ME" \
-H "Idempotency-Key: cart_123_personalization" \
-H "Content-Type: application/json" \
-d '{"external_product_id":"business-card"}'
The response carries Idempotent-Replay: true on every replay and Idempotent-Replay: false on the original execution.
Common errors
| Code | Status | When |
|---|---|---|
idempotency_key_mismatch |
422 | Same key reused with a different request body |
idempotency_key_too_long |
400 | Header exceeds 255 characters |
idempotency_request_in_progress |
409 | Another request with this key is still being processed; retry shortly |
idempotency_store_unavailable |
503 | Internal claim store is temporarily unreachable; retry shortly |
See Errors.