Idempotency
A request can time out after the API has already acted on it. To retry a
write without doing it twice, send an Idempotency-Key header: any
unique string of up to 255 printable ASCII characters, such as a UUID
you generate for each operation.
curl -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Idempotency-Key: 6f1c2e9a-8b3d-4c47-9a51-0d2f7e4b8c13" \ -H "Content-Type: application/json" \ -d '{ … }' \ https://api.limitry.com/v1/…The first request with a key runs normally. A retry with the same key
and the same request gets the first response again, with the same
status and body, and doesn’t run the operation a second time. A
replayed response carries the header Idempotency-Replayed: true.
What the SDKs, the CLI and the MCP server do
Section titled “What the SDKs, the CLI and the MCP server do”- Every write sends a key. If you don’t pass one, the client makes one for that call.
- The client retries a failed attempt with the same key. That covers a
network error, a timeout, a
5xx, a429, and a409with the codeidempotency_in_progress. It tries each call up to 3 times in all, waiting forRetry-Afterwhen the API sends one. ARetry-Afterlonger than 20 seconds comes back to you as the error instead. - Pass your own key when you might run the whole call again
yourself, such as a job that reruns or a webhook you receive twice.
Send the same key both times:
- TypeScript:
{ idempotencyKey: id }as the last argument. - Python:
request_options={"idempotency_key": id}. - CLI:
--idempotency-key <key>. A command that makes several writes derives one key per write from yours, so running it again with the same key repeats none of them. - MCP: every tool that changes something takes an optional
idempotencyKeyargument.
- TypeScript:
- Turn the retries off with
maxRetries: 0in TypeScript ormax_retries=0in Python.
Checks and reservations
Section titled “Checks and reservations”- Checks follow the same rules. The same key and the same check get
the first decision back, marked with
Idempotency-Replayed: true, and count nothing again. That holds for a check across several subjects too. The same key with a different check gets409 idempotency_key_reused. guardandreservesend a key for you. They send a check that fails fast once more with the same key, within the timeguardandreservewait. If a reservation’s check gets no answer in time, your work runs under the fail mode. Afterwards,reserveasks again with the same key and releases any reservation Limitry had made, so it isn’t left taken until it expires.guardfinishes what timed out. When its check gets no answer in time and the limit fails open,guardsends it once more in the background with the same key andlimitry-finish-only: 1: Limitry finishes a check it began, and decides nothing afresh (204when there was none).- Committing and releasing are safe to repeat without a key. The same commit or
release gets the same answer. Committing again with a different cost
gets
400.
The rules
Section titled “The rules”- Writes only. The header applies to
POST,PUT,PATCHandDELETE. Reads are safe to repeat anyway, and ignore it. - One key per request. Using a key again for a different request,
with a different endpoint or body, fails with a
409and the codeidempotency_key_reused. Generate a new key for each operation, and reuse it only to retry that operation. - A retry during the first request waits. If the first request is
still running, the retry gets
409 idempotency_in_progressand aRetry-Afterheader. Retry after that many seconds. - We keep only a final answer. Every retry gets back a success, or
an error a retry would get again, such as a
400or a404. The errors a retry can get past aren’t kept, so a retry with the same key runs again:- a
5xx; - a
402, once you’ve upgraded your plan; - a
409; - a
429, once there’s room again.
- a
- Per credential, environment and workspace, for an hour on a check and 24 hours on everything else (a commit, a release, a credit, a reset). A key used again after that is a new request, with one exception: a credit’s key is remembered for good, so a new credit sent with a key already used for a credit is ignored, however long after. Never reuse a credit’s key. A key belongs to the API key or token that sent it, so two integrations never collide. A personal access token’s keys are separate in each workspace and each environment.
- We protect stored answers. We keep a hash of your key, never the key itself, and we encrypt the stored answer with a key derived from yours. Only a retry that sends your key can read it back.
Sending a key yourself is optional: the SDKs, the CLI and the MCP server send one on every write.