Skip to main content
Write endpoints — 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

Idempotency-Key: 8a93a5b2-6ee6-4700-a3f9-b1ccac86b252
Idempotency-Key
string
required
A unique string (UUID v4 recommended) that you generate before the first attempt of a logical write operation. 1–255 characters.
If the header is missing on a route that requires it, ReconLayer rejects the request before doing any work:
400 Missing Idempotency-Key
{
  "error": "invalid_idempotency_key",
  "message": "Idempotency-Key header is required."
}

The contract

1

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).
2

Send it on the first attempt

curl -X POST http://localhost:3001/v1/payment-intents \
  -H "Authorization: Bearer $RECONLAYER_API_KEY" \
  -H "Idempotency-Key: 8a93a5b2-6ee6-4700-a3f9-b1ccac86b252" \
  -H "Content-Type: application/json" \
  -d '{ "externalReference": "invoice-9182", ... }'
3

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.
4

ReconLayer replays the original outcome

If the original request already completed, ReconLayer returns the same status code and body it returned the first time, without creating a second record. The response includes Idempotency-Replayed: true.

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:
  1. New key — ReconLayer records the key as processing, executes the operation, then stores the response as completed (status code + body). The response includes Idempotency-Replayed: false.
  2. Same key, same body, original completed — ReconLayer returns the stored status code and body verbatim. Idempotency-Replayed: true. Nothing is re-executed.
  3. 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
    {
      "error": "idempotency_key_conflict",
      "message": "This Idempotency-Key was already used for a different request on this operation."
    }
    
  4. 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):
    409 Request still in progress
    {
      "error": "idempotency_request_in_progress",
      "message": "A request with this Idempotency-Key is already being processed."
    }
    
    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.
If the original execution itself throws, ReconLayer removes the in-progress idempotency record so a retry with the same key can run cleanly rather than getting stuck in “in progress”.

Response header

Every successful response from an idempotent write endpoint carries:
Idempotency-Replayed: true | false
Use this to distinguish “this just happened” from “this was a replay of an earlier attempt” — useful for logging and for deciding whether to fire your own downstream side effects again.

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-Key on a real POST /v1/payment-intents call.