> ## Documentation Index
> Fetch the complete documentation index at: https://docs.capa.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# 🔁 Idempotency

> Safely retry transaction-creation requests without duplicating operations using the Idempotency-Key header.

***

### Overview

When creating a transaction, a network drop, client timeout, or unexpected `5xx` response can leave you unsure whether the operation was processed. Retrying the request without a safeguard can result in duplicate transactions.

The `Idempotency-Key` header lets you retry any transaction-creation `POST` safely. If Capa receives a request with a key it has already seen, it replays the original response — no duplicate transaction is created. The header is **opt-in**: if omitted, the request is processed normally with no idempotency guarantee.

***

### Supported Endpoints

The header is recognized on the following `POST` endpoints only. All other endpoints ignore it.

* [`POST /api/partner/v2/on-ramp`](/reference/onramppartnerv2controller_createpartneronramp)
* [`POST /api/partner/v2/off-ramp`](/reference/offramppartnerv2controller_createpartnerofframp)
* [`POST /api/partner/v2/cross-ramp`](/reference/crossramppartnerv2controller_createpartnercrossramp)

***

### How It Works

1. **Generate a unique `Idempotency-Key`** (UUIDv4 recommended) for each logical operation and include it as an HTTP header.
2. **Capa processes the request** and caches the response under the `(userId, key)` pair.
3. **On retry**, send the **identical request body** with the **same key**. Capa detects the duplicate and returns the original response — the handler is not invoked again.
4. **Failed originals can be retried.** If the first attempt resulted in an error (non-2xx), the record is marked `FAILED` and a subsequent request with the same key reprocesses normally.
5. **The guarantee window is 48 hours.** After that the key expires, the record is reclaimed, and the next request is treated as a new operation. It is the caller's responsibility to avoid duplicates beyond this window.

***

### Header Reference

| Field             | Value                                                          |
| ----------------- | -------------------------------------------------------------- |
| Name              | `Idempotency-Key`                                              |
| Required          | No (opt-in)                                                    |
| Format            | 16–128 printable ASCII characters                              |
| Recommended value | UUIDv4                                                         |
| Scope             | `(userId, idempotencyKey)` — scoped per user, not per endpoint |

***

### Behavior Matrix

| Scenario                                 | Behavior                                        | HTTP Status            |
| ---------------------------------------- | ----------------------------------------------- | ---------------------- |
| New key                                  | Request is processed; response cached under key | Handler's status (2xx) |
| Same key + same body, original completed | Cached response replayed; handler not invoked   | Original status        |
| Same key + same body, original in-flight | Request rejected — wait and retry               | `409 Conflict`         |
| Same key + **different** body            | Rejected — request body hash mismatch           | `422`                  |
| Same key + original failed (non-2xx)     | Record marked `FAILED`; request reprocessed     | Handler's status       |
| Key older than 48h                       | Record reclaimed; request treated as new        | Handler's status (2xx) |

***

### Errors

| HTTP Status    | Code                       | Message                                                          |
| -------------- | -------------------------- | ---------------------------------------------------------------- |
| `400`          | `INVALID_USER_INPUT_ERROR` | Malformed `Idempotency-Key` header (format violation)            |
| `409 Conflict` | —                          | Same key is already being processed; retry after a short delay   |
| `422`          | `INVALID_USER_INPUT_ERROR` | `Idempotency-Key was already used with a different request body` |

***

### Best Practices

* **Generate a fresh UUIDv4 per logical operation.** Never hardcode or reuse keys across distinct operations.
* **Persist the key** client-side until you receive a confirmed terminal response for that operation.
* **Retry with the identical body.** Changing any field in the request body is treated as a different operation and results in a `422`.
* **Do not share a key across endpoints** for the same user. Keys are scoped to `(userId, key)`, so the same key on a different endpoint collides on a body hash mismatch.
* **Omit the header on `GET`, `PUT`, `PATCH`, and `DELETE` requests** — it has no effect on those methods.
* **Plan for the 48-hour window.** Retries after expiry are reprocessed as new requests; implement your own deduplication logic for long-lived operations.

***

### Example

```shell theme={null}
curl --request POST \
  --url https://api.sandbox.capa.fi/api/partner/v2/on-ramp \
  --header 'Content-Type: application/json' \
  --header 'partner-api-key: <your-api-key>' \
  --header 'Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000' \
  --data '{
    "userId": "user_abc123",
    "fiatCurrency": "MXN",
    "blockchainSymbol": "ETH",
    "tokenSymbol": "USDC",
    "fiatAmount": 500,
    "destinationWalletAddress": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
  }'
```

If this request times out or fails at the network level, resend the **exact same body** with the **same `Idempotency-Key`**. Capa will return the original response without creating a second transaction.
