Operate reliably
Idempotency & safe retries
Prevent duplicate operations and recover safely from network uncertainty.
Persist a key before each write
Generate one high-entropy key per logical payment creation, checkout-session creation or refund. Persist it with your operation before sending the HTTP request. Send it as Idempotency-Key, at most 255 characters.
The header is optional, but omitting it opts out of the replay guarantee. Uniqueness is scoped to the project environment across endpoints. A reused key with a different method, path or JSON body returns IDEMPOTENCY_KEY_REUSED.
What is replayed
A completed successful request replays its original response status and body, with Idempotency-Replayed: true. Default retention is 24 hours. After expiration/pruning, there is no replay guarantee.
Whitespace and JSON object-key order do not change the fingerprint. A request still in progress returns IDEMPOTENCY_IN_PROGRESS. Wait and retry unchanged.
Error responses and thrown failures are not retained as completed results. A provider call may already have created a local payment before failing. Reconcile that record by ID/reference and verify uncertain outcomes before trying a new charge.
Do not cache verification polls
The middleware honors Idempotency-Key on POST generally, including verification. Omit it for repeated POST /payments/{id}/verify polls: reusing one can replay an earlier pending result instead of asking the provider again.
Retry decision table
| Situation | Action |
|---|---|
| Network timeout / lost write response | Retrieve and reconcile the original operation, then retry unchanged with its persisted key when appropriate. |
| 409 IDEMPOTENCY_IN_PROGRESS | Wait with jitter and retry unchanged. |
| 409 IDEMPOTENCY_KEY_REUSED | Restore the original request or use a new key only for a genuinely different operation. |
| 429 | Honor Retry-After; bound retries and concurrency. |
| 422 validation/business rejection | Correct the input/state/configuration first. |
| 503 / 500 on a safe read | Bounded exponential backoff with jitter. |
| Duplicate webhook delivery | Acknowledge after durable deduplication; do not fulfil twice. |