Idempotency
Every write that moves money takes a key, so a retry cannot buy twice.
Every POST that moves money requires an Idempotency-Key header. Send a fresh unique
value per logical operation — a UUID is fine:
curl https://api.tizon.mobile/v1/quotes \
-H "Authorization: Bearer $TIZON_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5f1c9a3e-7b42-4d18-9e65-0c7a2d4b8e31" \
-d '{ "offer_id": "off_jp_5gb_30d", "payment_source": "wallet" }'Retrying is safe
Retry with the same key and you get the original response back, marked
Idempotent-Replayed: true. The effect is not repeated: one quote, one debit, one order,
however many times the request arrives.
This is what makes a timeout survivable. If a request dies in flight and you do not know whether it landed, send it again with the same key rather than guessing.
Reusing a key for different content
A key is bound to the request that first used it. Sending the same key with a different body is rejected:
{
"error": {
"type": "conflict",
"code": "idempotency_key_reuse_mismatch",
"message": "This Idempotency-Key was used for a different request.",
"request_id": "req_4b1c0d8e9f2a3b4c5d6e7f8091a2b3c4"
}
}So scope a key to one logical purchase. Do not reuse last hour's key for this hour's order, and do not share one key across a batch.
Failures that recorded nothing
A request that failed without effect records nothing, so the key stays usable. The
clearest case is 402 insufficient_funds: nothing was charged, nothing was created, so
once the wallet is funded you may retry the identical request with the same key and it
will go through.
The rule of thumb: if the API changed nothing, the key is still free. If it changed anything, the key is now bound to that outcome and replaying returns it.
Where keys are required
Any write that moves money or mints a payment instruction, including:
POST /v1/quotes— buying an offerPOST /v1/wallet/lightning_invoices— minting a funding invoicePOST /v1/revenue/transfersandPOST /v1/revenue/payouts
Reads never need one. The reference marks the header on each operation that takes it.