POST /v1/payment-intents, POST /v1/evidence/provider, POST /v1/evidence/onchain, and other state-changing routes — require an Idempotency-Key header. ReconLayer uses it to make retries safe: the same key with the same request body always replays the original result instead of executing again.
The header
A unique string (UUID v4 recommended) that you generate before the first attempt of a logical write operation. 1–255 characters.
400 Missing Idempotency-Key
The contract
Generate a key per logical operation
Before your first attempt at, say, “create payment intent for invoice-9182”, generate one
Idempotency-Key. Store it alongside the operation in your own system (e.g. next to the queued job or outbound request).On timeout, network error, or 5xx: retry with the SAME key and SAME body
Do not generate a new key. Send the identical request body again, with the identical
Idempotency-Key.How it works under the hood
For each idempotent write, ReconLayer keys a stored record by(organizationId, operation, idempotencyKey) and hashes the request body. When a request arrives:
-
New key — ReconLayer records the key as
processing, executes the operation, then stores the response ascompleted(status code + body). The response includesIdempotency-Replayed: false. -
Same key, same body, original completed — ReconLayer returns the stored status code and body verbatim.
Idempotency-Replayed: true. Nothing is re-executed. -
Same key, different body — ReconLayer rejects the request. The stored request hash doesn’t match the new body’s hash:
409 Idempotency key reused with a different body
-
Same key, original still in flight (or never completed) — another request with this key is currently being processed (or the prior attempt crashed before completing):
Retry after a short backoff — once the original attempt finishes, the same key will either replay its result or, if it had failed cleanly, be available to retry.409 Request still in progress
Response header
Every successful response from an idempotent write endpoint carries:Scope: per organization and per operation
The idempotency key is scoped to(organizationId, operation, idempotencyKey). The same key string used by two different organizations, or for two different operations (e.g. payment_intents.create vs. evidence.provider.create), is treated independently — there is no cross-operation collision. Even so, using a fresh, unique key per logical operation (e.g. a UUID v4) is the simplest way to stay correct.
Idempotency vs. business-level uniqueness
Idempotency-Key deduplicates the same request being retried. It does not, by itself, deduplicate two different requests that describe the same business entity — that’s handled separately via fields like externalReference on payment intents. See API Design Principles → Business-level uniqueness for how the two interact: a brand-new Idempotency-Key with a previously-seen externalReference returns the existing payment intent with "outcome": "reused" rather than a duplicate.
Next steps
- API Design Principles — idempotency in the context of the wider write model.
- Errors — the full error envelope and status code catalog.
- Quickstart — a worked example that sets
Idempotency-Keyon a realPOST /v1/payment-intentscall.
