Olympus PayDevelopers

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#

EndpointHow to send the keyBehaviour on a repeat
POST /payoutsIdempotency-Key header, 8 to 64 charactersReturns the original payout with "idempotentReplay": true and status 200
POST /payment-linksIdempotency-Key header or idempotencyKey body field, up to 255 charactersReturns the original link
POST /split-recipientsexternalReference fieldReturns the existing recipient
POST /payments/{id}/cancelNot neededSafe to repeat: a cancelled payment stays cancelled
POST /payments/{id}/refundNot supportedEach 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.