> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.fluveo.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.fluveo.com/_mcp/server.

# Retry writes safely

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`**

```bash title="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](https://github.com/fluveohq/openapi).
A create-side `5xx api_error` remains indeterminate and may be retried against
the same key and object — see [Errors](/errors).