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.
Recommended key format
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.