Idempotency
Idempotency lets you retry a request (after a timeout or network blip) without it being processed twice. The Public API provides it in four forms, depending on the endpoint.
Usage reporting — idempotency key required
Usage reporting (the Meters endpoint) requires an
x-api-idempotency-key header on every submission. A missing key is rejected
with 400.
Code
- Reuse the same key when retrying the same submission — the duplicate
is acknowledged with
status: "duplicate"instead of being recorded twice. - Keys are valid for at least 30 days. Expired keys are cleaned up shortly after the window ends; once a key is cleaned up, reusing it is treated as a new submission.
- Keys can be up to 255 characters long.
- Use a fresh key for each new submission. A UUID is a good key.
- Keys are scoped per tenant, so two callers can never collide on the same key value.
Endpoints that require the key mark the header parameter as required in the API Reference.
Checkout confirmation — idempotency key required
POST https://api.ledgerbee.com/api/v1/checkout/confirm also requires an
x-api-idempotency-key header. A missing key is rejected with 400 and code
IDEMPOTENCY_KEY_REQUIRED.
The key is bound to the request's sessionId. Retrying with the same key and
the same sessionId returns the original response body in full, with
x-idempotent-replay: true. Reusing the key for a different sessionId is
rejected with 422 and code IDEMPOTENCY_KEY_REUSED, so use a fresh key for
each checkout session.
Naturally idempotent endpoints
Some endpoints are idempotent by design through their identifiers rather than
a header — for example, customer provisioning upserts by
customer.customerNumber, so re-sending the same provision request resolves to
the same customer instead of creating a duplicate. The endpoint descriptions in
the API Reference call this out where it applies.
All other mutating endpoints — optional key
Every other mutating Public API endpoint (POST, PUT, PATCH, DELETE)
accepts x-api-idempotency-key as an optional header. Send a fresh key
with each new operation when you want retry protection, and reuse the same key
only when retrying that same operation:
Code
The first successful request runs normally. Retrying with the same key does
not repeat the operation. The replay response carries the original status code
and the header x-idempotent-replay: true.
Endpoints whose response is the outcome of the operation replay the original response body in full:
- creating a billing group, and adding or removing a member
- creating a shipment
- settling open entries
- creating a journal entry or a batch of journal entries (v2)
- booking a draft journal entry (v1 and v2)
- adding a document to a journal entry (v1) or a draft journal entry (v2)
- submitting a batch of authority extracts
Every other endpoint replays a minimal body identifying what was created:
Code
id is the created resource's id, or null when the operation didn't create
a single addressable resource (batch endpoints, action endpoints) — fetch the
full object with a GET if you need it. A replay of a 204 No Content
response returns 204 with the replay header and no body.
Failure states
| Situation | Response | What to do |
|---|---|---|
The original request failed with 4xx/5xx | The key is not burned | Retry with the same key — the operation runs again |
| A duplicate arrives while the original is still in progress | 409 with code IDEMPOTENT_REQUEST_IN_PROGRESS | Wait briefly, then retry with the same key |
| The key was already used on a different endpoint | 422 with code IDEMPOTENCY_KEY_REUSED | Use a fresh key — one key maps to one operation. This includes a usage-report key reused elsewhere, a checkout-confirmation key reused for a different sessionId, and an authority-extract key reused for a different batchId |
| The key is missing on an endpoint that requires it | 400 with code IDEMPOTENCY_KEY_REQUIRED | Send x-api-idempotency-key |
| The key exceeds 255 characters | 400 with code IDEMPOTENCY_KEY_TOO_LONG | Shorten the key — a UUID is a good key |
Keys are tenant-scoped, retained for at least 30 days, and can be up to 255 characters long — the same window and cap as usage reporting.
Protocol endpoints (OAuth token and revocation, SCIM, MCP, and the portal SSO handoff and session endpoints) manage their own request semantics and don't accept the key. The API Reference shows the header parameter on every endpoint that does.