# Idempotency

Every mutating endpoint (`POST`, `PUT`, `PATCH`, `DELETE`) accepts an
optional `X-Idempotency-Key` header. Replaying the same key with the
**same method, path and body** within 24 hours returns the original
response, without re-executing the underlying side effect — safe for
partner billing hooks that may retry on network errors.

A key belongs to the credential that sent it: each API key, the admin
session and each client session has its own keys. The same key sent with
another credential runs as a new request and never receives the first
caller's stored response.

A secret the API shows once — a new API key or webhook secret, 2FA setup
material and backup codes, a one-time sign-in link, OAuth tokens — is not
kept in the stored answer: the fields `secret`, `otpauth_uri`,
`backup_codes`, `login_url`, `access_token`, `refresh_token`, `oauth_token`
and `password` are stored as `"***"`, so a replay repeats the outcome
without the secret. If the first answer was lost, rotate or create the
secret again.

| Behaviour | Trigger |
|-----------|---------|
| First call | Key not seen → request executes, response cached 24 h. |
| Replay (same credential, key, method, path and body) | Returns the original `status` + `body` + `X-Idempotent-Replay: true` header. |
| Replay of an answer that carried a secret shown once | Same `status` and body with the secret fields as `"***"`; the action does not run again. |
| Replay (same credential and key, **different method, path or body**) | `409 IDEMPOTENCY_KEY_REUSED` — surfaced as a partner bug. |
| Same key from **another credential** | Runs as a new request; answers are never shared between credentials. |
| Invalid key shape | `400 IDEMPOTENCY_KEY_INVALID` (must match `^[A-Za-z0-9_-]{8,64}$`). |
| 5xx on first call | **Not cached** — client may retry without conflict. |

**Recommended key:** UUID v4, generated once per logical operation and
reused across all retries of that operation.

```bash
curl -X POST \
  -H "X-WHost-Key: …"     -H "X-WHost-Timestamp: …" \
  -H "X-WHost-Nonce: …"   -H "X-WHost-Signature: …" \
  -H "X-Idempotency-Key: $(uuidgen)" \
  -d '{"username":"alice","plan_id":3}' \
  https://panel.example.com/api/v1/accounts
```

---
