API
Idempotency
Send an Idempotency-Key on unsafe POST requests so a retry after a timeout replays the first result instead of paying or creating twice. Required where money moves.
A network call can fail after the server acted but before you saw the answer. Retrying a plain POST could then create a second order or a second payment. An idempotency key makes the retry safe: the server remembers the first result for the key and replays it.
curl -X POST https://reuseforge.com/api/v1/orders/ord_tqjv5mw3k2na/pay \
-H "Authorization: Bearer $REUSEFORGE_TOKEN" \
-H "Idempotency-Key: 6f1c3a52-2a47-4d2b-9a7a-0d7b6f2a9d11" \
-H "Content-Type: application/json" -d '{}'Rules
- The header is
Idempotency-Key: <1 to 255 printable ASCII characters>. A random UUID is ideal. Make a new key for each distinct action, and reuse the same key for every retry of that one action. - It applies to unsafe
POSToperations. An operation that accepts it declares the header in the reference;PUTandDELETEare idempotent by definition and ignore it. - Required on the operations that move money:
create_order,pay_order,back_projectandtransfer_units. Without a key they answer400 idempotency_key_required. - Keys are remembered for 24 hours and are scoped to the caller, so two accounts can use the same key independently.
- The server stores a fingerprint of the request (method, path and canonical body) with the response, for every outcome except
401,429and5xx(those are not stored, so retrying runs the request again).
| You send | You get |
|---|---|
| The same key and the same request, after the first finished | The stored response again, with the header Idempotent-Replayed: true. Nothing is created or charged twice. |
| The same key with a different body or path | 422 idempotency_key_reuse. A key names one action. |
| The same key while the first request is still running | 409 idempotency_in_progress with retry_after. Wait, then retry with the same key. |
| No key where one is required | 400 idempotency_key_required. |
Using it
The SDKs and the CLI do this for you. They add a fresh UUID to every call whose operation declares the header and reuse it across the automatic retries of that call, so a retry cannot double-spend. To make an action safe across a process restart, choose the key yourself and persist it before you send the request.
curl
KEY=$(uuidgen) # create it once, keep it with the action
curl -X POST $API/orders -H "$AUTH" -H "Content-Type: application/json" -H "Idempotency-Key: $KEY" \
-d '{"plan_id": "pln_goalinvoice2", "rail": "simulated"}'
# the connection dropped? run the same command again with the same $KEY: you get the same order backPython
import uuid
import reuseforge
client = reuseforge.Client()
key = str(uuid.uuid4()) # persist this with your job record
order = client.create_order(plan_id="pln_goalinvoice2", rail="simulated", idempotency_key=key)JavaScript
import { ReuseForge } from '@reuseforge/sdk';
const client = new ReuseForge();
const key = crypto.randomUUID(); // persist this with your job record
const order = await client.createOrder({ plan_id: 'pln_goalinvoice2', rail: 'simulated' }, { idempotencyKey: key });CLI
rf orders create --plan pln_goalinvoice2 --rail simulated -v # -v prints the request, including the idempotency keyThe replayed answer is byte for byte the first one, so Location, ETag and the body match. You can tell a replay by Idempotent-Replayed: true. A payment is counted against the token's spend limit once: the counter moves in the same step as the state change, so a replay cannot add to it.
Which retries are safe
| Request | Safe to retry after a timeout |
|---|---|
GET, PUT, DELETE | Yes. |
POST with an Idempotency-Key | Yes, with the same key. |
POST without a key | Not after a 5xx other than 503: you cannot tell whether it happened. Check with a read first (for example list_orders) or add a key. |
The hosted MCP server derives a stable key for money tools when the client does not provide idempotency_key, so a client retrying the same request replays the first result instead of paying twice.
Last updated: