API reference

Idempotency

Networks fail. If a request times out you cannot tell whether the platform processed it. An idempotency key lets you repeat the request safely: it is executed at most once and every repeat returns the same answer.

Every POST accepts an Idempotency-Key header of up to 255 characters.

curl -X POST https://pay.example.com/v1/refunds \
  -H "Authorization: Bearer sk_sandbox_YOUR_KEY" \
  -H "Idempotency-Key: refund-order-1001-1" \
  -H "Content-Type: application/json" \
  -d '{"payment_intent": "pi_01J9ZQ4V8K2M3N5P7R9T1W3Y5A", "amount": 2500}'

Rules

Choosing keys

Derive the key from your own business cause, not from a random value generated per attempt: order-1001-payment, refund-order-1001-1. Then a crash and restart of your worker retries with the same key and cannot double charge. Use a random UUID only when your system has no stable identifier, and store it with the order before you send the request.

Use a new key for a genuinely new attempt, for example when the customer retries with a different card after a decline.

What to retry

Outcome What to do
Timeout or connection reset (no response received) Retry with the same key.
409 idempotency_in_progress Retry with the same key after a short wait.
Any stored response (4xx, 5xx) A repeat with the same key returns the same response. Fix the request, then use a new key.
402 card decline Ask for another payment method and use a new key.
idempotency_in_progress that never ends (your process crashed mid-request) The key stays locked until it expires after 24 hours and is never taken over automatically, because re-running could duplicate a payment. Check the state of the payment first, then retry with a new key.

If you are unsure whether a payment went through, search for it (GET /v1/payment_intents?q=… matches an id, the customer e-mail or a description prefix; metadata[order_id]=1001 matches exactly) or look at the request in Developers → Logs before creating a new one.