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.
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.
How It Works
- Generate a unique
Idempotency-Key (UUIDv4 recommended) for each logical operation and include it as an HTTP header.
- Capa processes the request and caches the response under the
(userId, key) pair.
- 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.
- 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.
- 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.
| 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) |
| 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
curl --request POST \
--url https://staging-api.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.