On this page

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.

bash
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 POST operations. An operation that accepts it declares the header in the reference; PUT and DELETE are idempotent by definition and ignore it.
  • Required on the operations that move money: create_order, pay_order, back_project and transfer_units. Without a key they answer 400 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, 429 and 5xx (those are not stored, so retrying runs the request again).
You sendYou get
The same key and the same request, after the first finishedThe stored response again, with the header Idempotent-Replayed: true. Nothing is created or charged twice.
The same key with a different body or path422 idempotency_key_reuse. A key names one action.
The same key while the first request is still running409 idempotency_in_progress with retry_after. Wait, then retry with the same key.
No key where one is required400 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

bash
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 back

Python

python
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

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

bash
rf orders create --plan pln_goalinvoice2 --rail simulated -v      # -v prints the request, including the idempotency key

The 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

RequestSafe to retry after a timeout
GET, PUT, DELETEYes.
POST with an Idempotency-KeyYes, with the same key.
POST without a keyNot 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: