Skip to content

Idempotency

MVP

Idempotency is an upcoming MVP feature and is not yet available in sandbox or production. This page is a draft and is subject to change before release. The replay window (TTL) below is not yet finalized.

An idempotency key lets a client safely retry a mutating request without risking a duplicate operation, such as a duplicate charge.

Network failures, timeouts, and client-side retry logic can all cause the same request to reach Flute more than once. Without an idempotency key, a retried sale or debit call could create a second transaction for the same charge. With an idempotency key, Flute recognizes the retry and returns the original result instead of processing it again.

Supported Endpoints

Idempotency support is being rolled out platform-wide to every mutating endpoint (POST, PUT, PATCH, and DELETE). The MVP focuses first on the endpoints where a duplicate request has the highest impact:

AreaEndpoints
TransactionsPOST /v2/transactions (sale/auth), .../capture, .../reversal (refund/void)
Payment SessionsPOST /v2/payment-sessions
ACHPOST /v2/transactions (ACH debit), POST /v2/transactions/credit

GET requests do not need an idempotency key. They do not change state, so repeating one is always safe.

Using an Idempotency Key

Pass the key in the Idempotency-Key request header.

curl -X POST 'https://sandbox.api.flute.com/v2/transactions' \
  -H 'Authorization: Bearer <ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: 6a1f7e2c-4b3d-4e5a-8f9c-1d2e3f4a5b6c' \
  -d '{
    "paymentProcessorId": "a2f2c2e7-0b23-4682-8f99-ab7707205461",
    "baseAmount": 100.00,
    "currencyCode": "USD"
  }'

The key is a string, up to 255 characters. A UUID (v4) is recommended, generated fresh by the client for each distinct operation.

The key is scoped to the API key used to make the request. Two different merchants or two different API keys for the same merchant can safely use the same key value without colliding.

Replay Behavior

The first request seen with a given Idempotency-Key is processed normally. Every request that follows with the same key is treated as a replay of that first request, not as a new operation.

SituationResult
Same key, identical request bodyReturns the original response, with the original status code. The operation is not repeated.
Same key, request body differs from the originalReturns 409 Conflict. The operation is not performed.
Same key, original request is still processingReturns 409 Conflict. The client should retry after a short delay.
New key, or no key providedProcessed as a new operation.

An idempotency key is not a substitute for referenceId duplicate detection. referenceId prevents the same card and amount from being charged twice. An idempotency key prevents the same HTTP request from being processed twice. Use both together for full protection against duplicate charges.

Conflict Response

A body mismatch on a reused key returns the platform's standard conflict error:

{
  "details": "The request conflicts with the current state of the resource.",
  "statusCode": 409,
  "source": "<Service>",
  "exceptionType": "ConflictException",
  "correlationId": "aa6cfcd0-0295-4a4c-b074-8c901f114fee",
  "entityId": null,
  "errorCode": "C0000",
  "title": "Resource conflict",
  "cause": "The request conflicts with the current state of the resource.",
  "resolution": "Refresh the resource state and retry the operation, or use a different idempotency key.",
  "documentationUrl": "https://developer.flute.com/"
}

Generate a new key rather than reusing one after a conflict. A key is meant to represent one specific operation attempt; reusing it for a different request body defeats that guarantee.

Key Retention

TBD

The exact replay window (how long Flute remembers a key before it can be reused) has not been finalized for the MVP release. This section will be updated once that value is set.

After the replay window expires, the same key can be reused for a new, unrelated operation. Plan client-side key generation so that a key is never intentionally reused after that window closes.

Best Practices

  • Generate a new idempotency key for each distinct operation, not each HTTP attempt. Reuse the same key across retries of that same attempt.
  • Use a UUID or another value with enough randomness to avoid collisions.
  • Store the key alongside the operation on the client side, so a retry after a crash or restart can reuse the same key instead of generating a new one.
  • Continue passing referenceId on transactions and payment sessions. It protects against duplicate charges even outside the replay window.