Idempotency Key Support
Prevent duplicate transactions when network issues cause uncertain request outcomes
Overview
The Preczn API supports idempotent operations for select POST, PATCH, and DELETE endpoints via the Idempotency-Key HTTP header. This feature prevents duplicate resource creation when requests are retried due to network interruptions or timeouts.
While use of idempotency keys is optional, we strongly recommend including them on all transaction requests to protect against duplicate charges.
Why Use Idempotency Keys
Network communication is inherently unreliable. Even when your request successfully reaches Preczn and is processed, the response may fail to reach you due to:
- Gateway timeouts (504 errors)
- Network interruptions
- Load balancer timeouts
- Connection resets
Critical Scenario: The 504 Timeout TrapA common and costly mistake: Your transaction request receives a 504 Gateway Timeout, leading you to assume the request failed. In reality, the transaction completed successfully on Preczn's backend—the timeout only affected the response.
Without an idempotency key: If you retry the request, you risk creating a duplicate transaction and charging the customer twice.
With an idempotency key: Retrying the same request with the same key returns the original successful response, confirming the transaction completed without creating a duplicate.
When to Always Use Idempotency Keys
| Scenario | Risk Without Key | Protection With Key |
|---|---|---|
| 504 Gateway Timeout | Duplicate transaction if retried | Safe to retry; returns original response |
| 502 Bad Gateway | Unknown if processed; may duplicate | Safe to retry; no duplicate created |
| Connection reset | Request may have completed | Safe to retry with confidence |
| Client timeout | Transaction may have succeeded | Retry returns actual outcome |
How It Works
Idempotent Behavior: When you include an idempotency key, the system checks if a successful request with that same key was already processed within the past 24 hours. If found, the original response is returned regardless of subsequent resource changes. New or expired keys trigger normal request processing.
Time-to-Live (TTL): Each idempotency key remains valid for 24 hours from the initial request timestamp.
Implementation
Include the Idempotency-Key header in your requests:
POST /v1/transactions HTTP/1.1
Host: api.preczn.com
Content-Type: application/json
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
{
"amount": 1000,
"currency": "USD",
...
}Best Practices
1. Generate UUID Keys
Create a unique UUID/GUID for each distinct operation:
const idempotencyKey = crypto.randomUUID();2. Include on First Attempt
Always include the idempotency key from the initial request, not just on retries. This ensures the key is registered before any potential failure occurs.
// ✅ Correct: Key included on first attempt
async function createTransaction(data) {
const idempotencyKey = crypto.randomUUID();
return await fetch('/v1/transactions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey
},
body: JSON.stringify(data)
});
}3. Retry with the Same Key on Timeouts
Key PointWhen you receive a 504, 502, or any timeout error, always retry using the same idempotency key. This is the entire purpose of the feature—it lets you safely retry without risking duplicates.
async function createTransactionWithRetry(data, maxRetries = 3) {
const idempotencyKey = crypto.randomUUID();
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('/v1/transactions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey // Same key for all attempts
},
body: JSON.stringify(data)
});
if (response.ok) {
return await response.json();
}
// Retry on 502, 503, 504 errors
if ([502, 503, 504].includes(response.status) && attempt < maxRetries) {
await sleep(1000 * attempt); // Exponential backoff
continue;
}
throw new Error(`Request failed: ${response.status}`);
} catch (error) {
if (error.name === 'TimeoutError' && attempt < maxRetries) {
await sleep(1000 * attempt);
continue; // Retry with same idempotency key
}
throw error;
}
}
}4. Store Keys for Reconciliation
Persist idempotency keys with your transaction records. If you need to verify whether a transaction completed, you can retry with the stored key to get a definitive answer.
5. Avoid Key Reuse Across Operations
Never reuse idempotency keys for different operations or endpoints. Each unique business operation should have its own key.
// ❌ Wrong: Reusing key for different transactions
const sharedKey = crypto.randomUUID();
await createTransaction(order1, sharedKey);
await createTransaction(order2, sharedKey); // Will return order1's response!
// ✅ Correct: Unique key per transaction
await createTransaction(order1, crypto.randomUUID());
await createTransaction(order2, crypto.randomUUID());Supported Endpoints
NoteNot all endpoints support idempotency. Consult the API Reference for the complete list of supported endpoints. Generally, all transaction-related POST endpoints support idempotency keys.
Updated 20 days ago
