Docs · Concepts
Idempotency
How Idempotency-Key makes retries safe, what is replayed, and the three ways a key can be refused.
Send Idempotency-Key: <opaque string, at most 255 characters> on any POST, PUT, PATCH or DELETE. If a request times out or you are unsure whether it landed, send it again with the same key: Folio returns the first response instead of doing the work twice.
curl -X POST "$FOLIO_API_URL/v1/teachings" \
-H "Authorization: Bearer $FOLIO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: sunday-2026-11-01-create" \
-d '{
"title": "Sunday service",
"filename": "service.mp3",
"content_type": "audio/mpeg"
}'Rules#
- Scope. A key is scoped to the credential that made the request (the API key, session or device key) and to the method and path. Two credentials can use the same string without seeing each other's responses. Requests without a valid credential are never stored.
- Same key, same body. The stored response is replayed for 24 hours, with the header
Idempotency-Replayed: true. - Same key, different body.
422 validationwitherror.meta.reasonofidempotency_key_reused. Use a new key for a different request. - Same key while the first request is still running.
409 conflictwitherror.meta.reasonofidempotency_in_progressand aRetry-Afterheader. Wait, then send the same request again. - Not stored. Responses with status
401,403,429or5xxare not stored, so a retry runs the request again. - Secrets are never replayed. A response that carries a one-time secret (a new key, a webhook signing secret, a device key) is not stored. Replaying such a request answers
409witherror.meta.reasonofidempotency_secret_unavailable. Use a new key to mint another secret. - Abandoned requests. A request that never completes is released after two minutes.
Choosing keys#
Derive the key from the thing you are doing, not from a random value you lose on retry: sunday-2026-11-01-create for the Sunday upload, invoice-1042-endpoint for an invoice's webhook. A random UUID generated once per logical operation and stored with it works too.
Verified against API version 0.0.0-dev. Generated from the live OpenAPI document.