Idempotency
Idempotency guarantees that performing the same operation multiple times produces the same result as performing it once. In the context of payment and transfer APIs, this property is critical: if a network failure occurs after you send a transfer request but before you receive the response, you can safely retry the same request without risking a duplicate transfer.
Idempotency-Key Header
To make a request idempotent, include the Idempotency-Key header with a unique identifier:
| Header | Required | Description |
|---|---|---|
Idempotency-Key | Recommended | A unique key (UUID v4) that identifies this logical operation. The server uses this key to detect and deduplicate retries. |
The key must be a string of up to 128 characters. We recommend UUID v4 for guaranteed uniqueness.
Which Endpoints Support It
Idempotency behavior varies by HTTP method:
| Method | Idempotent by Default | Idempotency-Key Supported | Notes |
|---|---|---|---|
GET | Yes | No | Read operations are naturally idempotent. Repeating a GET returns the same data. |
DELETE | Yes | No | Deleting an already-deleted resource returns a consistent result. |
POST | No | Yes | Create operations are not idempotent by default. Use Idempotency-Key to make them safe to retry. |
PUT | Yes | No | Full-resource updates are naturally idempotent. |
PATCH | Depends | Optional | Partial updates may or may not be idempotent depending on the operation. |
POST endpoints
The Idempotency-Key header is primarily designed for POST endpoints that create resources, such as /api/v1/transfer/command/create. These are the operations most vulnerable to duplication from retries.
How It Works
When you include an Idempotency-Key header in a request, the server follows this process:
1. Receive request with Idempotency-Key
2. Check if this key has been seen before
├── NEW KEY:
│ ├── Process the request normally
│ ├── Store the key, request body hash, and response
│ └── Return the response
└── EXISTING KEY:
├── Compare the request body hash with the stored one
├── If body matches → return the stored response (no reprocessing)
└── If body differs → return 409 Conflict (key collision)
3. Key expires after 24 hoursThe server stores the association between the idempotency key and the response for 24 hours. During this window, any retry with the same key and the same request body will return the original response without re-executing the operation.
Key Generation
Use UUID v4 to generate idempotency keys. Each key must be unique per logical operation.
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000Key generation by language:
Example: Preventing Duplicate Transfers
Consider a scenario where you need to create a transfer and want to ensure it is not duplicated even if you must retry.
Step 1: Generate an idempotency key before the request.
Step 2: Send the transfer creation request with the key.
Step 3: If the request fails due to a network error, retry with the same key and body.
A successful response on either the initial request or a replay:
{
"version": "1.3.0",
"timestamp": 1709337600000,
"success": true,
"code": "2000",
"message": "SUCCESS",
"data": {
"transferId": "txn_789xyz",
"status": "COMPLETED",
"amount": "100.00",
"currency": "USD"
}
}Error Handling
Key Collision (Different Body)
If you reuse an idempotency key with a different request body, the server returns 409 Conflict with error code T1023:
{
"version": "1.3.0",
"timestamp": 1709337600000,
"success": false,
"code": "T1023",
"message": "DUPLICATE_REQUEST",
"data": null
}This is a safety mechanism. Each idempotency key is bound to a specific request body hash. You cannot reuse a key to perform a different operation.
Expired Key
Idempotency keys expire after 24 hours. After expiration, the same key can be used again — but the server will treat it as a new request, not a replay. Avoid relying on key reuse after expiration; always generate a new key for new operations.
Network Errors
If you receive a network timeout or connection error (no HTTP response at all), it is safe to retry with the same idempotency key. The server either:
- Never received the request — it will process it as new.
- Received and processed it — it will return the cached response.
In both cases, no duplicate transfer is created.
Best Practices
Generate the key before the retry loop
Create the idempotency key before entering your retry logic. If you generate a new key on each retry, you lose the deduplication guarantee and may create duplicate resources.
One key per logical operation
Each distinct business operation should have its own idempotency key. Do not reuse a key from a previous transfer to create a new, different transfer. Different operations require different keys.
Key expiration window
Keys are valid for 24 hours. Design your retry logic to complete within this window. For most use cases, a retry strategy with exponential backoff (1s, 2s, 4s) and a maximum of 3-5 attempts will resolve well within this limit.
Store the key for reconciliation
When creating transfers, log the idempotency key alongside the request in your system. If you need to investigate whether a transfer was created, you can look up the key to determine whether the server processed the request.
:::caution Do not use Idempotency-Key as Nonce The Idempotency-Key and X-Nonce headers serve different purposes. The nonce is part of the HMAC signature and must be unique per HTTP request (including retries). The idempotency key must be the same across retries of the same logical operation. Never set them to the same value. :::
Next Steps
- HMAC Authentication — Learn how to sign requests with HMAC-SHA256.
- Error Handling — Full error code catalog including
T1023(DUPLICATE_REQUEST).