# Idempotency

An idempotency key lets a client safely retry a request without causing a duplicate operation.
A duplicate operation could be a duplicate charge or a duplicate transaction.
Network failures, timeouts, and retry logic can cause a client to send the same request twice.
Flute uses the idempotency key to recognize a retry and return the original result.

## What Idempotency Means

Idempotency means an operation gives the same result whether it runs once or many times.
An idempotent request is safe to retry, because a retry does not create a new operation.
Flute supports idempotency through an optional request header named `Idempotency-Key`.
The client generates this key and sends it with each mutating request.
A mutating request is any request that creates, updates, or cancels a resource.

This header is available on Flute v2 endpoints only.
It is not yet available on Flute v1 endpoints.

## Where Idempotency Applies

Use an idempotency key on any endpoint that changes data, especially one that moves money.
The table below lists every endpoint that currently accepts the `Idempotency-Key` header.

| Area | Endpoint |
|  --- | --- |
| Payment Links | `POST /v2/payment-links` |
| Payment Links | `POST /v2/payment-links/{paymentLinkId}/share` |
| Payment Sessions | `POST /v2/payment-sessions` |
| Payment Sessions | `POST /v2/payment-sessions/{paymentSessionId}/cancel` |
| POS Transactions | `POST /v2/pos/transactions` |
| POS Transactions | `POST /v2/pos/transactions/{posTransactionId}/cancel` |
| POS Transactions | `POST /v2/pos/transactions/reversal` |
| Settlements | `POST /v2/settlements/batches/close` |
| Transactions | `POST /v2/transactions` |
| Transactions | `POST /v2/transactions/{transactionId}/capture` |
| Transactions | `POST /v2/transactions/{transactionId}/reversal` |
| Transactions | `POST /v2/transactions/credit` |
| Transactions | `POST /v2/transactions/{transactionId}/tip-adjustment` |
| Transactions | `POST /v2/transactions/{transactionId}/ach-hold` |
| Transactions | `POST /v2/transactions/{transactionId}/ach-release` |


## How Clients Should Use It

Generate a unique key for each new operation, not for each request attempt.
A version 4 UUID works well, because it is unique and hard to guess.
Send the key in the `Idempotency-Key` request header.
Reuse the same key only when retrying the same operation after a failure.
Do not reuse a key for a new, unrelated operation.
Store the key with the operation on the client side.
This allows a retry after a crash to reuse the correct key.

## Response Behavior

Flute checks each key against any request it has already processed.

| Situation | Result |
|  --- | --- |
| Same key, same request body | Flute returns the original response again. No new operation runs. |
| Same key, request still processing | Flute returns `409 Conflict`. Retry again after a short delay. |
| Same key, different request body (`422 Unprocessable Content`) | Flute rejects the retry. Generate a new key for the different request. |
| New key, or no key at all | Flute treats the request as a new operation. |
| Server error, such as `500 Internal Server Error` | Flute does not store the key. A retry with the same key runs the operation again. |


## Code Example

The following example creates a transaction with an idempotency key.

```bash
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",
    "referenceId": "REF-ORDER-1042"
  }'
```

A network timeout occurs, so the client sends the exact same request again.
The client reuses the same key and the same request body.
Flute returns the original response, and no second transaction is created.

## Retention Window

TBD
The length of the retention window is not yet published.
This section will be updated once that value is confirmed.

After the retention window closes, the same key can be reused for a new operation.
Plan key generation so a key is never intentionally reused after that window closes.