Skip to content
Warrantv0.1

Idempotency

Required on every money-moving POST.

Every POST that moves money requires an Idempotency-Key header, and a request without one is rejected before anything happens.

Idempotency-Key: 8f0c1b4e-2b1a-4d59-9d0e-3a2f7c1b9e44

Which routes require it

These seven, and they are exactly the routes that can move value:

POST /v1/warrants                    open
POST /v1/warrants/:id/verify         check, and settle on the result
POST /v1/warrants/:id/release        release in full
POST /v1/warrants/:id/partial        release part
POST /v1/warrants/:id/refund         refund
POST /v1/console/escalations/:id/resolve   a person's decision
POST /v1/x402/pay                    pay a 402 with a warrant behind it

Required, not optional. Omit it and the request fails with idempotency_key_required before any state is touched. A retry after a timeout is the normal case, not the exotic one: the caller cannot tell a lost response from a lost request, and without a key the safe action would be to do nothing, which is its own kind of failure.

Generate one key per intent, not per attempt

The key identifies the thing you want to happen, so every retry of that same intent reuses it. A fresh key on each attempt is the bug this header exists to prevent: two keys means two warrants.

What a replay returns

Reusing a key with the same request returns the original outcome. Reusing it with a different body is a conflict, because the alternative is honouring a request the caller has since changed their mind about.

POST /v1/warrants HTTP/1.1
Authorization: Bearer wr_test_...
Idempotency-Key: 8f0c1b4e-2b1a-4d59-9d0e-3a2f7c1b9e44
Content-Type: application/json

{ "amount": "9900000", "payee": "someone.else", "...": "..." }

409

{
"error": {
  "type": "conflict",
  "code": "idempotency_key_reused",
  "message": "That Idempotency-Key was already used with a different request.",
  "doc_url": "https://docs.gowarrant.xyz/api-reference/errors#idempotency_key_reused",
  "request_id": "req_41f09c2a..."
}
}
curl -X POST https://api.gowarrant.xyz/v1/warrants \
-H "Authorization: Bearer $WARRANT_API_KEY" \
-H "Idempotency-Key: 8f0c1b4e-2b1a-4d59-9d0e-3a2f7c1b9e44" \
-H "Content-Type: application/json" \
-d '{ "amount": "9900000", "payee": "someone.else" }'

The four codes

CodeStatusWhat happened
idempotency_key_required400No header on a money-moving POST.
idempotency_key_reused409Same key, different request body.
idempotency_in_flight409The original request is still running. Retry shortly.
idempotency_conflict409The key was claimed concurrently. Retry shortly.

The last two are both "try again in a moment" — they are separate codes because one means your own earlier attempt is still going and the other means a race, and the distinction matters when you are reading logs at 3am.

Keys are scoped to an organisation, so two organisations can use the same key string without colliding.