> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stella-commerce.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Idempotency

> Every mutation is safe to retry. Here's how it works.

Every mutating endpoint on Stella accepts an `Idempotency-Key`
header. Replays of the same key within 24 hours return the **cached
response from the first call** — same status code, same body, byte for
byte.

This makes flaky-network retries safe (you'll never double-charge a
customer) and is essential for AI agents whose tool-use loops often
include retry-on-error logic.

## How to use it

Generate a UUID per logical operation. Attach it to every mutation
that's part of that operation. Retries reuse the same key.

```bash theme={null}
KEY=$(uuidgen)

# First call — proceeds normally
curl -X POST \
     -H "X-Site-ID: kasa" \
     -H "X-Stella-Token: stk_live_..." \
     -H "Idempotency-Key: $KEY" \
     -H "Content-Type: application/json" \
     -d '{"variant_id": "...", "quantity": 1}' \
     https://api-dev-app.stella-commerce.com/api/storefront/cart/cart_.../items

# Retry — replays the cached response
curl -X POST ... -H "Idempotency-Key: $KEY" ...
```

## Lifetime

Cached responses live 24 hours, then a daily cleanup task deletes them.
After that window, the same key is treated as a fresh request.

## Where it's required

* All `POST`, `PATCH`, `DELETE` on `/api/storefront/cart/*`,
  `/api/storefront/customer/*`, `/api/agent/*`.
* Webhook delivery retries (Stella adds the key automatically — your
  receiver just needs to be idempotent).

## Where it's optional

* `GET` requests (idempotent by definition).
* `/api/dashboard/*` (merchant-trusted).
* `/api/sync/*` (Zunkiree integration).

If you omit the header on an endpoint that requires it, you'll get
`400 Bad Request` with `error: "idempotency_key_required"`.

## Conflict handling

If you reuse a key with a **different request body** (different
endpoint, different params), Stella returns:

```http theme={null}
HTTP/1.1 422 Unprocessable Entity
{ "error": "idempotency_key_mismatch" }
```

This is a defensive guard — it should never fire in normal use, since
you'd be reusing keys across different operations.
