How It Works
Include anIdempotency-Key header with a unique value (e.g., a UUID) on any supported request. The API will:
- First request — process normally and cache the response for 24 hours
- Duplicate request (same key, same parameters) — return the cached response without re-executing the operation
- Key reuse with different parameters — return a
422error to prevent misuse
Idempotent-Replayed: true header — without adding the item again.
Who A Cached Response Belongs To
A cached response is only ever returned to the caller that produced it, so the request has to say who that caller is. One of these identifies them:- the customer’s access token (
Authorization: Bearer ...), for a signed-in shopper - the cart token (
X-Spree-Token), for a guest working on a cart they already hold - a secret key (
sk_...), for a server-to-server caller on the Admin API
pk_...) does not count. Every visitor to your storefront sends the same one, so a key value that two shoppers happen to share — checkout-1, an order number, a timestamp — would hand one shopper the other’s response, cart token included.
A request that carries none of the credentials above still runs exactly as it always has — it is simply never cached, so the Idempotency-Key header has no effect on it. Guests are not second-class here: a guest holds a cart token from the moment their cart exists, which covers the whole of checkout, including the steps where a duplicate costs money.
Supported Endpoints
Every one of these is replayable for a guest as well as for a signed-in shopper, because every one of them is reached with the cart’s token. The exception is creating the cart itself: there is no cart yet, so a guest has no token to present and the key is ignored — a retry may leave behind a second, empty cart. Sign the shopper in, or accept the spare cart.
Idempotency keys are ignored on
GET, DELETE, and other non-supported actions.
Key Requirements
- Must be a string of 255 characters or less
- Should be unique per distinct operation (UUIDs are recommended)
- Keys are scoped to the caller and the store, so two callers can use the same key value without conflict
- Cached responses expire after 24 hours
Response Headers
When a cached response is replayed, the API sets:Error Handling
Key Reuse with Different Parameters
If you send a request with an idempotency key that was previously used with different request parameters (different body, different path), the API returns a422 error:
Key Too Long
Keys longer than 255 characters return a400 error:
Server Errors
5xx responses are not cached. If the server fails to process your request, you can safely retry with the same idempotency key and the request will be re-executed.
SDK Usage
The Spree SDK supports idempotency keys via theidempotencyKey option:
Best Practices
- Generate a new key for each distinct operation. Use a UUID (v4) or another random identifier. Never reuse keys across different operations.
- Store the key before sending the request. If the request fails due to a network error, retry with the same key to ensure the operation is only performed once.
- Don’t use idempotency keys for GET requests. GET requests are naturally idempotent and the API ignores the header on read-only endpoints.
- Let keys expire naturally. Cached responses expire after 24 hours. Don’t rely on idempotency keys for longer-term deduplication.
Relationship with Optimistic Locking
The Store API also uses optimistic locking via thestate_lock_version field on orders. These mechanisms complement each other:
Use both together for robust checkout flows: idempotency keys protect against network retries, while
state_lock_version detects when another client has modified the order.
