DocsAdvanced guidesIdempotency Keys

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

  1. You generate a unique key for each request
  2. Include the key in your request header
  3. 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

  1. Key Generation

    • Use UUIDs or order-specific information
    • Include timestamp for uniqueness
    • Keep keys reasonably short
  2. Storage

    • Store keys with request outcomes
    • Clean up old keys periodically
    • Index keys for quick lookups
  3. 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

  1. Payment Creation

    const idempotencyKey = `payment_${orderId}_${amount}_${timestamp}`;
  2. Refunds

    const idempotencyKey = `refund_${paymentId}_${amount}_${timestamp}`;
  3. Webhook Retries

    const idempotencyKey = `webhook_${eventId}_${attempt}`;

Next Steps