Idempotency ensures that retrying a request multiple times has the same effect as making it once. This prevents accidental duplicate charges, transfers, or other critical operations.
Idempotency keys allow you to safely retry API requests without worrying about performing the same operation twice. When you include an idempotency key with a request, Devdraft will return the same result for subsequent requests with the same key.
Client errors (4xx): Generate new key for corrected request
Error Handling
try { const response = await makePayment(data, idempotencyKey);} catch (error) { if (error.status >= 500) { // Server error - retry with same key return retryRequest(data, idempotencyKey); } else if (error.status >= 400) { // Client error - fix data and use new key const fixedData = correctValidationErrors(data, error); const newKey = crypto.randomUUID(); return makePayment(fixedData, newKey); }}
Conflicting Operations:If you use the same key for different operations:
Error Response
{ "error": { "type": "idempotency_error", "message": "Keys can only be used for requests with identical parameters", "code": "idempotency_key_mismatch" }}
Resolution: Use a new idempotency key for the different operation.
// E-commerce checkout flowasync function processCheckout(orderData) { // Use order ID as part of key for context const idempotencyKey = `checkout_${orderData.orderId}_${Date.now()}`; try { const payment = await createPayment({ amount: orderData.total, currency: orderData.currency, customer_id: orderData.customerId, metadata: { order_id: orderData.orderId } }, idempotencyKey); return { success: true, paymentId: payment.id }; } catch (error) { // Safe to retry with same key on network errors if (isNetworkError(error)) { return processCheckout(orderData); // Will use same key } throw error; }}
Webhook Processing
Handling Duplicate Webhooks:
// Use webhook event ID as idempotency keyapp.post('/webhooks/devdraft', async (req, res) => { const event = req.body; const idempotencyKey = `webhook_${event.id}`; try { // Process webhook with idempotency await processWebhookEvent(event, idempotencyKey); res.status(200).send('OK'); } catch (error) { if (error.code === 'idempotency_key_used') { // Already processed this webhook res.status(200).send('Already processed'); } else { res.status(500).send('Error'); } }});
Batch Operations
Processing Multiple Items:
// Each item in batch gets unique keyasync function processBatchPayments(payments) { const results = []; for (const payment of payments) { const idempotencyKey = `batch_${batchId}_item_${payment.id}`; try { const result = await createPayment(payment, idempotencyKey); results.push({ success: true, data: result }); } catch (error) { results.push({ success: false, error: error.message }); } } return results;}