For developers

Idempotency

How to retry a write without selling the same basket twice.

/v1 · contract version 1.0.0 · OpenAPI reference (openapi.json)


Idempotency

Every write requires an Idempotency-Key header. It is not optional, and there is no way to opt out, because the request you will most want to retry is the one whose response you never saw, and by then it is too late to start sending a key.

Every write
Idempotency-Key: 8f2b1e4c-…  (a UUID is ideal)

The rule is one value per logical operation. Generate it once, before the first attempt, and store it with the operation. Then:

  • Same key, same body → you get the original response back, byte for byte, with the header Idempotent-Replay: true. The handler does not run again; no second order exists. That header is absent on the first, real execution, which is how you tell them apart.
  • Same key, different body → 409 v1_idempotency_key_reuse, and nothing is written. This is deliberate and it is the most important line on this page: returning the first response would tell you your order succeeded and show you somebody else’s sale as proof, and executing it would give you two orders from one intent. So it does neither. A new operation gets a new key.
  • A write that fails leaves the key unused: the row is written inside the same transaction as the effect, so a rolled back order releases its key. Fix the body and retry with the same key.

A key is 1 to 255 printable-ASCII characters, and it is scoped to your Business and to your token: two integrations in one shop can never collide on a value either of them generated, and neither can two shops. Keys are honoured for as long as the Business exists, and there is no expiry window today. If that ever changes, it will be announced before it is applied.

The writes it applies to are POST /v1/customers, POST /v1/sales, POST /v1/sales/{id}/refunds, POST /v1/sales/{id}/void, POST /v1/orders, POST /v1/orders/{id}/cancel.