Refunds & Idempotency

Refunds follow preview → confirm → execute once. Every financial mutation requires an Idempotency-Key so a network retry can't double-charge or double-refund.

View as Markdown

Why idempotency matters

A request can time out or drop mid-flight, and you won't know whether the server actually finished processing it. If your code auto-retries without idempotency protection, the same refund could be submitted twice.

Send an Idempotency-Key header (a unique string you generate) on financial calls. Retrying with the same key and same body replays the original result instead of executing again; the same key with a different body returns 409 IDEMPOTENCY_KEY_CONFLICT.

These endpoints require an Idempotency-Key — omitting it is rejected outright (IDEMPOTENCY_KEY_REQUIRED): POST /api/Subscription, POST /api/Subscription/{id}/Cancel, POST /api/Checkout, POST /api/PaymentLink/{id}/Complete, POST /api/Payment/{id}/Attempt, POST /api/Payment/{id}/Reconcile, POST /api/Refund.

Refund flow: preview → confirm → execute once

  1. 1The dashboard's refund button first shows a preview — refundable amount, whether it's eligible.
  2. 2Only after the merchant confirms does it actually call POST /api/Refund (with an Idempotency-Key).
  3. 3A refund can't be undone once submitted; clicking "Confirm refund" twice is safely blocked by the same key — it never refunds twice.
POST/api/Refund— Request a full or partial refund on a payment
curl -sS -X POST "$BASE/api/Refund" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: refund-order-42" \
  -H "Content-Type: application/json" \
  -d '{"paymentId":"pay_...","amount":200,"reason":"customer_request"}'

When a payment's status is unknown

The Sandbox timeout scenario leaves a payment unknown — meaning "not yet determined", not "failed". Never retry the charge just because it looks like a failure — that can double-charge the customer. Call reconcile to get the final result instead.

POST/api/Payment/{id}/Reconcile— Resolve an unknown payment's final outcome