Idempotency
Networks fail. If a request times out you cannot tell whether it was processed. An idempotency key lets you send the same request again and get the original result instead of doing the work twice.
Which endpoints support it#
| Endpoint | How to send the key | Behaviour on a repeat |
|---|---|---|
POST /payouts | Idempotency-Key header, 8 to 64 characters | Returns the original payout with "idempotentReplay": true and status 200 |
POST /payment-links | Idempotency-Key header or idempotencyKey body field, up to 255 characters | Returns the original link |
POST /split-recipients | externalReference field | Returns the existing recipient |
POST /payments/{id}/cancel | Not needed | Safe to repeat: a cancelled payment stays cancelled |
POST /payments/{id}/refund | Not supported | Each call is a new refund. Read the payment and check refunded_amount before retrying |
Rules for keys#
- Generate a new random value (a UUID is ideal) for each distinct operation, or derive it from your own record id, such as
order-1001. - Reuse the same key only to retry the same request.
- Keys are scoped to your business. They do not expire, so never reuse one for a different operation.
- On a repeat, the original result is returned and the new request body is not compared with the old one.
Example#
curl https://merchant.olympuspay.co/api/v1/payouts \
-X POST \
-H "Authorization: Bearer $OLYMPUS_API_KEY" \
-H "Idempotency-Key: 2c1f6ee0-6d3c-4a3e-9d9f-0c9f3b0d7a12" \
-H "Content-Type: application/json" \
-d '{ "amount": 1500.00, "currency": "BWP", "destinationType": "provider_bank" }'Run it twice. The second response has "idempotentReplay": true and the same payoutId, and your balance is debited once.
A safe retry loop#
async function withRetry(makeRequest, attempts = 4) {
for (let i = 0; i < attempts; i++) {
try {
const res = await makeRequest()
if (res.status < 500 && res.status !== 429) return res
} catch { /* network error: retry */ }
await new Promise((r) => setTimeout(r, 2 ** i * 500 + Math.random() * 250))
}
throw new Error('gave up')
}Only retry on network errors, 429 and 5xx. Never retry a 4xx without fixing the request.