Skip to main content

Idempotency

A network failure leaves you not knowing whether a request arrived. Without protection, the safe-looking retry could screen the same address twice. An idempotency key makes the retry harmless: the API recognises it and answers with the result it already recorded.

Send Idempotency-Key: <value> on any request that creates something:

  • POST /v1/checks and POST /v1/checks/batch
  • POST /v1/webhooks, POST /v1/webhooks/{webhook_id}/rotate and DELETE /v1/webhooks/{webhook_id}
  • POST /v1/telegram/link-codes and DELETE /v1/telegram/links/{link_id}

The header is optional. The value is 1 to 255 printable ASCII characters with no spaces; anything else is rejected with 400 VALIDATION_ERROR and parameter: "idempotency-key". Use your own operation id (an order number, a payout id), not a random value generated per attempt: the whole point is that every attempt of one operation sends the same key.

A key is scoped to your account, the key environment (live or sandbox) and the endpoint, so the same value used on two endpoints, or under a sandbox and a live key, does not collide. Keys are remembered for 24 hours; after that the value can be reused.

What happens when a key is reused​

You sendThe API answers
The key for the first timeRuns the request and records its result under the key.
The same key and the same body, after the first request finishedReplays the recorded result: the same status code and the same resource (for a check, the same check_id). Nothing is screened and nothing is charged again.
The same key and a different body422 IDEMPOTENCY_KEY_CONFLICT. Nothing runs.
The same key while the first request is still running409 IDEMPOTENCY_REQUEST_IN_FLIGHT. Wait a moment and send it again.
The same key after the first request's lease was taken over by a concurrent retry409 IDEMPOTENCY_LEASE_LOST on the request that lost it. Send the same request again to read the recorded result.

Details that matter in practice:

  • "Same body" means the same bytes. The body is compared as sent, not after parsing, so a retry that re-serialises the JSON with a different key order or spacing counts as a different body. Store the serialised request and resend it unchanged.
  • Only successful results are recorded. A request that ends in a 4xx or 5xx is not pinned to its key, so a retry runs again, which is what you want after a transient failure. Fix the request first if the error was a 4xx.
  • A crashed request does not block the key. If the first attempt dies without answering, a retry takes the key over after 30 seconds.
  • A webhook secret is shown once. Replaying POST /v1/webhooks or a rotation returns the webhook without its secret, because the secret is never stored in readable form. If you lost the response, rotate with a new key.
  • Batch items get derived keys. Each item of a batch is keyed from the batch key and its position, so replaying a batch cannot screen an item twice.

Example​

Send the same request, with the same key and the same body, until you get an answer. The body here is the sandbox test address, which always answers pending, so run it under a sandbox key.

curl -s -X POST https://api.leeri.ai/v1/checks \
-H "Authorization: Bearer $LEERI_API_KEY" \
-H "Idempotency-Key: deposit-2291-attempt-group" \
-H "Content-Type: application/json" \
-d '{"subject":"address","asset":"BTC","address":"1PENDNGCHECKADDRESSFRSANDBXTEST99"}'

Run it twice: the second answer carries the same check_id as the first.

See Errors for how to react to the other failures.