Idempotency

Preventing duplicate public API writes when an integration retries.

IntermediateownermanagerdeveloperUpdated 2026-09-24

Idempotency

Current V2 status (2026-09-24): This contract is live in V2 on the writes V2 exposes today: POST /api/v1/leads, POST /api/v1/clients, and PATCH /api/v1/clients/:id, plus test-key sandbox writes to leads, clients, and estimates, and POST /api/v1/webhooks with a live key. Live POST /api/v1/estimates draft creation is pending production and will also require this header. Until released, it returns 405 write_not_supported. Estimate updates, job and invoice writes, and lead updates still answer 405 write_not_supported with a live key. In V2 the key must be 1 to 255 printable characters (422 invalid_idempotency_key), a missing header returns 422 missing_idempotency_key, and two bodies count as the same request when they are the same JSON document, whatever the key order or number spelling. Live-key automation draft-save, publish, and pause operations also require this header. Test keys cannot use automation routes.

All live and sandbox external API POST and PATCH writes require an Idempotency-Key header. Workflow gateway POST queries are read-only and do not require the header. When live draft creation ships, the key will include POST /api/v1/estimates. DELETE /api/v1/webhooks/:id accepts the header as an option: send one and a retry after a lost response replays the original success instead of answering 404.

That includes every public write endpoint. In V2 today, live keys can use /api/v1/leads, /api/v1/clients, /api/v1/clients/:id, and /api/v1/webhooks; test keys can additionally write sandbox records through /api/v1/estimates and /api/v1/estimates/:id:

  • /api/v1/leads
  • /api/v1/leads/:id
  • /api/v1/clients
  • /api/v1/clients/:id
  • /api/v1/estimates
  • /api/v1/estimates/:id
  • /api/v1/jobs
  • /api/v1/jobs/:id
  • /api/v1/invoices
  • /api/v1/invoices/:id
  • /api/v1/webhooks

Live-key PATCH /api/v1/automations/:id, POST /api/v1/automations/:id/publish, and POST /api/v1/automations/:id/pause also require this header. These routes do not accept test keys. The matching MCP write tools require an idempotencyKey argument and forward it to the same idempotency ledger.

Application workflow mutations at POST /api/v1/workflows/{operation} use a durable request receipt. The first response includes meta.request_id; read its state at GET /api/v1/workflows/requests/{requestId} with either exact workflows:read or workflows:write. A mutation requires a live key with exact workflows:write scope and the current application permission for that operation. Legacy * and workflows:* do not grant these scopes.

This protects you from duplicate writes when a request times out, your worker retries, or a no-code platform like Zapier replays the same step.

How It Works

  1. Your integration sends a unique Idempotency-Key.
  2. CE Pro stores the request fingerprint and response.
  3. If you retry the same request with the same key and the same payload, CE Pro returns the original result instead of creating a duplicate record.
  4. If you reuse the same key with a different payload, CE Pro returns 409.
  5. If another request with the same key is still running, CE Pro returns 409 idempotency_in_progress.

For a workflow operation, the key claims one durable receipt and is never reclaimed. CE Pro never automatically starts a pending or indeterminate mutation again. A recognized post-claim 4xx preserves its HTTP status and includes a sanitized receipt_id with receipt_status: "indeterminate"; an unknown server failure returns 202 with the indeterminate receipt. Reusing the key with different input returns 409. Once completed, an exact retry replays the saved response and includes X-Idempotent-Replayed: true.

Header Example

Idempotency-Key: cepro-lead-20260314-001

When To Reuse A Key

Reuse the same key only when you are retrying the exact same operation.

Examples:

  • A lead-create call timed out and you want to retry it safely
  • A network hop failed after the server already processed the request
  • A workflow runner retries the same step automatically

Create a new key for every new write operation.

Use a key derived from your upstream system's stable id:

  • Form submission id
  • CRM record id
  • Queue message id
  • Workflow run id plus step id

That keeps retries safe even across worker restarts.

Error Behavior

  • Same key + same body: CE Pro replays the original response
  • Same key + different body: 409
  • Same key while the original request is still running: 409 idempotency_in_progress
  • An automation draft save with a stale expectedRevision also returns 409;

reload the workflow details and review the current version before retrying.

  • Missing key on a mutating POST or PATCH: request rejected
  • Key on DELETE /api/v1/webhooks/:id: optional; when present, a retry replays the original success

The resource-specific REST endpoints keep completed and failed idempotency records for 72 hours. Application workflow mutations use the durable receipt described below.

Workflow receipts are durable operation records. Do not retry an unresolved mutation with a new idempotency key: look up its receipt and wait for the original operation's state. Receipt lookup and replay recheck the same key, member, current permission, and location scope that claimed the receipt. Changed access hides a receipt with 404 or rejects a replay with 409. For catalog entries marked as returning secrets, only the first response can contain the sensitive value; the stored receipt and replay contain the redacted projection.

Practical Tip For No-Code Tools

If your tool supports a stable step identifier, map that into Idempotency-Key. If it does not, create a deterministic key from the external object id you are syncing.

Was this article helpful?

Still need help? Contact support