Skip to content
Sandbox

Idempotency

Exactly how the Idempotency-Key behaves: format, scope, 24-hour window, what is compared, what is memorised, and what happens on a retry, a conflict or concurrent requests.

View as Markdown

The Idempotency-Key header makes a request safe to retry: if the response is lost on the network, the same request sent again with the same key returns the response already computed instead of computing and billing a second time.

Format

  • 1 to 255 bytes, visible ASCII only (0x21 to 0x7E): no space, no tab, no accented character.
  • No normalisation: the value you send is the value stored, compared byte for byte.
  • An empty, too long, repeated header, or one containing a forbidden character, is refused with 400 invalid_idempotency_key, before any computation.

One UUID per logical operation is a good choice. Generate it once, before the first attempt, and keep it for every retry of that operation.

Scope and window

PropertyValue
ScopeThe workspace and environment of the API key. Every API key of a workspace shares this space; Sandbox and Production are separate.
Window24 hours from the first request.
After 24 hoursThe key becomes free again, including for a different request.

What is compared

Two requests are "the same request" when they concern the same operation (creation, or refresh of a given target), the same economic input in its canonical form and the same external_transaction_id. JSON field order, case and whitespace in descriptor, or a fraction of a second in occurred_at change nothing. A different amount, currency or identifier makes a different request.

The same key used for a create call and then for a refresh designates two different requests: the second returns 409 idempotency_key_reuse.

What happens

SituationResponse
First request with this keyProcessed normally
Same key, same request, after a 200The memorised body of the first response, Noryo-Idempotency-Replayed: true. Nothing is recomputed or billed.
Same key, different request, within 24 hours409 idempotency_key_reuse
Same key, same request, while the first is still in progressThe second waits for the first to finish, then returns its response as a replay; if the wait lasts too long, 503 busy with Retry-After
Same key, same request, after a refusal returned at settlement (402, 403 production_not_enabled, 409 transaction_id_conflict, 410, 503)Re-evaluated as a new attempt: a refusal is not memorised
Same key, different request, after such a refusal409 idempotency_key_reuse: a refusal does not free the key
Same key after a refusal that came before settlement (validation 400, 401, 403 insufficient_scope, 429)The key had not been reserved: it is still free
Same key after 24 hoursProcessed as a first request

Two rules sum up the table. Only a success is memorised: an error is replayed by recomputing, which lets you retry after a failure. The link between a key and its request never changes for 24 hours, even after an error: a key is not recycled for another payload.

What a replay contains

  • The same body, usage included: a response that was billed originally still shows billable: true. Do not count it twice.
  • The Noryo-Idempotency-Replayed: true header.
  • A new Noryo-Request-Id: every attempt has its own identifier, replays included.
  • One rate-limit token consumed, like any authenticated request.

Concurrent requests

Two identical requests sent at the same time with the same key never produce two settlements. The second waits for the first instead of being refused: it then receives the replay of the response. If the wait exceeds the delay the server allows itself, it receives 503 busy with a Retry-After: nothing was written or billed, and the same request can be sent again as it is.

{
  "type": "https://developer.noryo.app/errors/busy",
  "title": "Service busy",
  "status": 503,
  "code": "busy",
  "detail": "The service is temporarily contended. Retry after the delay given by Retry-After.",
  "request_id": "req_…"
}
JSON

Choosing keys

  • One key per logical operation, never one key per session or per customer.
  • Several services in one workspace share the key space: prefix them, for example billing-<uuid>.
  • A retry reuses the same key; a new operation takes a new one.
  • Put no personal data in the key: it is not logged in clear, but nothing justifies placing information in it.

Published on 2026-10-08 21:04 UTC (version 1).

Was this page helpful?