Xtopay Docs
Core Concepts

Idempotency

Safely retry failed requests without creating duplicate payments or subscriptions.

Why idempotency matters

Network failures happen. If your server sends a payment creation request and the connection drops before you receive a response, you don't know if Xtopay processed it or not. Without idempotency, retrying creates a duplicate charge.

Xtopay supports idempotent requests on all POST endpoints. Send the same Idempotency-Key header and Xtopay returns the original response without re-executing the operation.

Using idempotency keys

Add the Idempotency-Key header to any write request:

const payment = await fetch("https://api.xtopay.co/v1/payments", {
  method: "POST",
  headers: {
    "Authorization": `Basic ${encoded}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "order_001_attempt_1", // your unique key
  },
  body: JSON.stringify({ amount: 5000, currency: "GHS", ... }),
});

With the SDK:

const payment = await xtopay.payments.create(
  { amount: 5000, currency: "GHS", ... },
  { idempotencyKey: "order_001_attempt_1" },
);

Key requirements

  • Must be unique per operation — use a combination of your internal IDs (order ID + attempt number)
  • Maximum 255 characters
  • Only ASCII printable characters
  • Keys expire after 24 hours — after that, the same key can be reused for a new operation

What happens on a duplicate

If you send the same key twice with the same request body, Xtopay returns the original response with status 200 and the header Idempotency-Replayed: true.

If you send the same key with a different body, Xtopay returns 422 idempotency_key_mismatch.

import { randomUUID } from "crypto";

// Stable key for a specific business action
const key = `${orderId}_payment_${attempt}`;

// Or generate once and persist it alongside the order
const key = randomUUID();

Avoid using random UUIDs generated fresh on each retry — the whole point is that retries use the same key.

On this page