Skip to main content
Network failures are unavoidable. If a POST times out, you can’t tell whether the resource was created or not — retrying blindly risks creating a duplicate. Idempotency keys solve this. By attaching a unique key to a creating POST, you can safely retry the same request as many times as you need: the Chataigne API performs the operation exactly once and returns the original response on every replay.
An idempotency key is required on every resource-creating POST (for example, creating a location or a special closing). It is ignored on GET, PATCH, PUT, and DELETE, which are already naturally idempotent.

How it works

Send a unique value in the Idempotency-Key header. The API stores the first response associated with that key and replays it for any subsequent request that arrives with the same key.
Idempotency-Key
string
required
A unique value you generate per logical operation. Use a UUID (v4) or any other high-entropy, collision-resistant string. Keys are scoped per API key and retained for 24 hours, after which they are discarded and a request with the same key is treated as new.
ScenarioBehavior
First requestThe operation runs and the response is stored against the key.
Replay — same key, same bodyThe original response is returned with Idempotent-Replayed: true. The operation does not run again.
Mismatch — same key, different body409 with error type idempotency_error.
In-flight — same key, original still processing409 with error type conflict_error.
Expired — same key, more than 24h laterTreated as a brand-new request.
Idempotent-Replayed
boolean
Present and set to true only on replayed responses. Its absence means the request was processed for the first time. Use it to detect retries in logs and metrics.

Creating the same location twice

The example below creates a location under an organization, then issues the exact same request a second time. The second call returns the same loc_… resource — no duplicate is created.
curl https://server.chataigne.ai/v1/organizations/org_8sK2pQ4mNvT1/locations \
  -H "x-api-key: ch_org_live_9aF3kLpQ7mZ2" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1a9c2e-3b7d-4a51-9e44-2c8f0d5b71a3" \
  -d '{
    "name": "Pizzeria Centrale",
    "currency": "CHF",
    "country": "CH",
    "timezone": "Europe/Zurich"
  }'
Both requests return the same object. The replay is distinguished only by its header:
First response — 201 Created
HTTP/1.1 201 Created
X-Request-Id: req_4Qm8Zt2yLpVc
Content-Type: application/json

{
  "id": "loc_5RhT9wXk2bND",
  "object": "location",
  "organization_id": "org_8sK2pQ4mNvT1",
  "name": "Pizzeria Centrale",
  "currency": "CHF",
  "country": "CH",
  "timezone": "Europe/Zurich",
  "default_language": "fr",
  "address": null,
  "created_at": "2026-05-29T09:14:03Z",
  "updated_at": "2026-05-29T09:14:03Z"
}
Replayed response — 201 Created
HTTP/1.1 201 Created
Idempotent-Replayed: true
X-Request-Id: req_7Bn1Cv5xRwQa
Content-Type: application/json

{
  "id": "loc_5RhT9wXk2bND",
  "object": "location",
  "organization_id": "org_8sK2pQ4mNvT1",
  "name": "Pizzeria Centrale",
  "currency": "CHF",
  "country": "CH",
  "timezone": "Europe/Zurich",
  "default_language": "fr",
  "address": null,
  "created_at": "2026-05-29T09:14:03Z",
  "updated_at": "2026-05-29T09:14:03Z"
}
X-Request-Id differs between the original and the replay — each HTTP exchange gets its own request ID — but the response body is byte-for-byte the original.

Error cases

Mismatched body — idempotency_error

Reusing a key with a different request body is almost always a bug (the most common cause is regenerating data on retry instead of reusing the original payload). The API rejects it rather than silently returning a stale result.
409 Conflict
HTTP/1.1 409 Conflict
X-Request-Id: req_2Lp9Ke7vNmZ4
Content-Type: application/json

{
  "error": {
    "type": "idempotency_error",
    "code": "idempotency_key_reused",
    "message": "This Idempotency-Key was already used with a different request body.",
    "request_id": "req_2Lp9Ke7vNmZ4"
  }
}
Generate the idempotency key once, before the first attempt, and reuse the exact same key and body on every retry. Never derive the key from values that can change between attempts (timestamps, random IDs, retry counters).

Concurrent duplicate — conflict_error

If a second request arrives with the same key while the first is still being processed, the duplicate is rejected with conflict_error. This protects you from double-submits caused by impatient retries or parallel workers.
409 Conflict
HTTP/1.1 409 Conflict
X-Request-Id: req_8Wd3Hs6tBcXq
Content-Type: application/json

{
  "error": {
    "type": "conflict_error",
    "code": "idempotency_key_in_flight",
    "message": "A request with this Idempotency-Key is already in progress.",
    "request_id": "req_8Wd3Hs6tBcXq"
  }
}
When you receive conflict_error, wait briefly and retry with the same key — once the original request completes, the retry will replay its stored response.

Best practices

One key per operation

Generate a fresh key for each distinct create. Reuse it only when retrying that same operation.

Use a UUID

A v4 UUID gives you collision-free keys without coordination across processes.

Retry within 24h

Keys are retained for 24 hours. Retry inside that window to guarantee a replay rather than a new resource.

Check the replay header

Inspect Idempotent-Replayed to tell first-time creates from retries in your logs and dashboards.
Idempotency keys behave identically on the Admin API (/admin/v1). The same rules, headers, and 24-hour retention apply.