# Idempotency and safe writes

> Retry create requests without duplicates, avoid overwriting other people's edits, and process webhook deliveries exactly once.

> Markdown version of https://kanorio.com/en/developers/basics/idempotency. Append `.md` to any developer docs URL for this format. Index: https://kanorio.com/llms.txt · MCP: https://app.kanorio.com/api/mcp

Networks fail in the middle of requests. These three mechanisms let you retry without creating duplicates or losing someone else's work.

## Idempotency keys

Create operations that are expensive to repeat accept an `Idempotency-Key` header. The reference marks them, and the OpenAPI document sets `x-kanorio-idempotent: true` on them.

```bash
curl -X POST https://app.kanorio.com/api/v1/sites/ws_example123/collections/projects/items \
  -H "Authorization: Bearer $KANORIO_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: import-2026-11-02-row-17" \
  -d '{ "slug": "riverside-bakery", "fieldData": { "title": "Riverside Bakery" } }'
```

- Choose the key yourself, from 1 to 200 characters. A UUID, or an id from your own system, works well.
- Retrying with the same key and the same body returns the original result and does not create anything new.
- The same key with a different body returns `409 IDEMPOTENCY_CONFLICT`.
- If the first request is still running, a retry returns `409 IDEMPOTENCY_IN_PROGRESS`. Wait briefly and retry.
- Keys are scoped to the site and the operation, and expire after 24 hours.

Over MCP, pass the key as the `idempotencyKey` argument of the tool.

## Optimistic concurrency

Pages, site-wide header and footer, and other content that people also edit in the dashboard use optimistic concurrency, so your script cannot silently overwrite someone's changes.

1. Read the resource and keep its timestamp: `updatedAt` for a page, `contentUpdatedAt` for globals.
2. Send it back as `ifUnmodifiedSince` with the write.
3. If the resource changed in between, the write fails with `409 CONFLICT` and the current timestamp in `details`. Read again, merge your change, and retry.

```json
{
  "ifUnmodifiedSince": "2026-11-02T08:00:00.000Z",
  "sections": [{ "id": "sec_hero_1", "type": "page-main-visual", "title": "Fresh bread daily" }]
}
```

The reference shows which operations take `ifUnmodifiedSince`.

## Drafts first

Most writes change a draft, and a separate publish operation makes them live. Pages, globals and posts work this way. Collection items publish immediately unless you send `publish: false`. A failed or repeated write therefore rarely affects what visitors see.

## Webhook deliveries

Kanorio may deliver the same event more than once, for example after a timeout or when someone resends it from the dashboard. Every delivery carries an `X-Kanorio-Delivery` id that stays the same across retries. Store the ids you have processed and return `200` for repeats. See [Webhooks](https://kanorio.com/en/developers/webhooks).
