Idempotency
Every mutating endpoint accepts an Idempotency-Key header. Retries within 24 hours using the same key return the original response without re-executing the underlying operation.
How it works
When you send:
POST /v1/events
Idempotency-Key: 8e2c0b87-3e3e-4b3a-92f1-2c5b3a52d3f8
Content-Type: application/json
{ "title": "Lunch", … }ChronaPilot persists the request body fingerprint, the response, and the response status. If you retry with the same Idempotency-Key:
- Same body: the cached response is returned. The status code is preserved, and a Chronapilot-Idempotent-Replay: true header is added.
- Different body: you receive a 409 idempotency_key_in_use error.
Keys are scoped per API key + per endpoint, and expire after 24 hours. Under Connect, the scope is per connected account — the same key reused by two different end-users against the same endpoint is treated as two independent operations.
When to use it
Use idempotency keys on every mutating call from the moment you write the client. In production, retries happen — from your retry middleware, from network blips, from queue redrivers. Without an idempotency key, a retried POST is a duplicate event.
A simple pattern: generate the key on the calling side (uuidv4() per logical operation), persist it alongside the queued work, and reuse it on retries.
Generating keys
Use a v4 UUID, the ULID format, or crypto.randomUUID(). Avoid composing keys from input data — accidentally identical keys across different operations will produce false 409s.
What's idempotent without a key
- GET, HEAD, OPTIONS — always idempotent.
- DELETE — deleting a missing resource returns 404; resending the same delete is safe.
What's *not* automatically idempotent: POST and PATCH. Always send a key.
Idempotent webhook receipt
If you process a webhook twice (because we retried) and your handler is idempotent, the duplicate has no effect. We recommend tracking the event.id of each delivery in a small ledger and skipping any ID you've already processed. See Webhooks.