Idempotency
Idempotency ensures that an API request can’t be performed multiple times by mistake. This is crucial for payment operations to prevent duplicate charges.
How It Works
- You generate a unique key for each request
- Include the key in your request header
- If you retry with the same key, you’ll get the same response
Using Idempotency Keys
Include the idempotency-key
header in your requests:
// Using the SDK
const session = await lomi.checkoutSessions.create({
merchant_id: 'your_merchant_id',
amount: 1000,
currency: 'XOF',
provider_codes: ['ORANGE_MONEY']
}, {
idempotencyKey: 'unique_request_id_123'
});
// Direct API calls
const response = await fetch('https://api.lomi.africa/v1/checkout/sessions', {
method: 'POST',
headers: {
'x-api-key': process.env.LOMI_API_KEY,
'idempotency-key': 'unique_request_id_123',
'Content-Type': 'application/json'
},
body: JSON.stringify({
// request parameters
})
});
Generating Keys
Generate unique, deterministic keys based on your business logic:
function generateIdempotencyKey(orderId: string): string {
const timestamp = Date.now();
return `order_${orderId}_${timestamp}`;
}
// Using UUID v4
import { v4 as uuidv4 } from 'uuid';
const idempotencyKey = uuidv4();
// Using order-specific information
const idempotencyKey = `order_${orderId}_${timestamp}_${amount}`;
Key Lifecycle
- Keys are valid for 24 hours
- After 24 hours, the same key can be reused
- Keys must be unique across all your requests
Error Handling
try {
const session = await lomi.checkoutSessions.create({
// ... parameters
}, {
idempotencyKey: 'unique_key'
});
} catch (error) {
if (error.code === 'idempotency_key_reused') {
// Key was used within last 24 hours
console.error('Duplicate request detected');
} else if (error.code === 'idempotency_key_invalid') {
// Invalid key format
console.error('Invalid idempotency key');
}
}
Best Practices
-
Key Generation
- Use UUIDs or order-specific information
- Include timestamp for uniqueness
- Keep keys reasonably short
-
Storage
- Store keys with request outcomes
- Clean up old keys periodically
- Index keys for quick lookups
-
Retry Logic
async function withIdempotency(fn, key, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(key); } catch (error) { if (error.statusCode === 500) { // Wait before retry await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000) ); continue; } throw error; } } } // Usage await withIdempotency( (key) => lomi.checkoutSessions.create({ // ... parameters }, { idempotencyKey: key }), 'unique_key_123' );
Common Scenarios
-
Payment Creation
const idempotencyKey = `payment_${orderId}_${amount}_${timestamp}`;
-
Refunds
const idempotencyKey = `refund_${paymentId}_${amount}_${timestamp}`;
-
Webhook Retries
const idempotencyKey = `webhook_${eventId}_${attempt}`;