Skip to navigation

Retry writes safely

Make every create safe to retry without double-charging.

Supported create calls and PaymentIntent transitions can carry an Idempotency-Key. Reuse the same key for one logical operation. Reusing it with different non-sensitive parameters returns 400 idempotency_error. When both operations use the shared response journal, reusing the key for a different endpoint or PaymentIntent also returns 400 idempotency_error without running the second operation. SetupIntent create is outside that journal, with its own key scope per merchant and test/live mode. Key K on PaymentIntent create and SetupIntent create can create one object of each type, in either order. This does not allow two different journal operations to share K.

curl
KEY=$(uuidgen)
curl https://api.devfluveo.com/v1/payment_intents \
-u sk_test_123: \
-H "Idempotency-Key: $KEY" \
-d amount=4242 \
-d currency=usd
# Retry the same request with the same $KEY to get the original response back.

Derive the key from your own operation id (an order id, a job id) so a retry after a timeout reuses it deterministically. A PaymentIntent transition that is still active or has an ambiguous outcome returns 409 idempotency_error with Retry-After; wait that many seconds and retry with the same key. Fluveo will not dispatch the transition twice.

Completed PaymentIntent transition snapshots remain replayable for at least 24 hours. The exact JSON response is encrypted at rest and capped at 64 KiB. If a stale claim needs crash recovery, Fluveo synchronizes processor state but returns 409 rather than freezing a potentially racing read as the original response. Keep retrying the same key; do not start the operation with a new key while the original outcome is ambiguous.

SetupIntent create uses its own object identity rather than the shared response journal. With the same fields and a matching stored request fingerprint, a successful internal read returns the existing object in any of these states: requires_payment_method, requires_action, processing, succeeded, or canceled. Create builds a fresh answer, not a saved response snapshot. Card number, CVC, and expiry are outside that fingerprint. An internal read error is returned as an error; a US Stripe sync timeout can still return 200 with the stored state. BR does not force a provider sync. See the full replay rules. A create-side 5xx api_error remains indeterminate and may be retried against the same key and object — see Errors.