Olympus PayDevelopers

Accept payments

Customers pay through a hosted page that Olympus Pay runs for you, so card and bank details never touch your servers. You create a payment link or a QR code, send the customer to it, and follow the payment with the API and webhooks.

The lifecycle of a payment#

pending  ->  processing  ->  succeeded  ->  partially_refunded  ->  refunded
   |              |
   |              +-------->  failed
   +----------------------->  cancelled
StatusMeaning
pendingCreated, the customer has not completed checkout
processingSubmitted to the payment provider, awaiting confirmation
succeededPaid in full, nothing refunded
partially_refundedPaid, and part has been refunded
refundedPaid, and all of it has been refunded
failedDeclined or abandoned after an attempt, no money collected
cancelledYou cancelled it while it was still pending

GET /reference returns this list, always current, with no authentication.


curl https://merchant.olympuspay.co/api/v1/payment-links \
  -X POST \
  -H "Authorization: Bearer $OLYMPUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Order 1001",
    "description": "Two nights, deluxe room",
    "amount": 250.00,
    "currency": "BWP",
    "returnUrl": "https://shop.example.com/orders/1001",
    "idempotencyKey": "order-1001"
  }'

Omit amount to let the customer type one. Use expiresAt (ISO 8601) to make a link stop working at a time you choose. If the key has a redirect-domain allowlist, returnUrl must be on it. After payment the customer is sent to returnUrl with ?payment_id=...&status=success (or status=cancelled) appended.

The response is 201 with the link's id and the payUrl to give the customer.

Create a QR code#

For in-person payments, create a dynamic QR code and show it on a screen. Note that amount here is in minor units.

curl https://merchant.olympuspay.co/api/v1/qr-codes \
  -X POST \
  -H "Authorization: Bearer $OLYMPUS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "mode": "fixed_amount", "amount": 25000, "currency": "BWP", "singleUse": true }'

mode is fixed_amount (needs amount) or open_amount (the payer chooses). A singleUse code stops accepting payments once it has been paid.

Retrieve payments#

curl https://merchant.olympuspay.co/api/v1/payments/PAYMENT_ID \
  -H "Authorization: Bearer $OLYMPUS_API_KEY"
{
  "id": "6f0c1a52-3f3a-4b6e-9b0e-6d0a1c2f9a11",
  "method": "hosted_checkout",
  "amount": 25000,
  "currency": "BWP",
  "fee_amount": 750,
  "net_amount": 24250,
  "refunded_amount": 0,
  "status": "succeeded",
  "payment_link_id": "b3a4e1c8-7d52-4a53-8c0b-2f1a9d44e8aa",
  "created_at": "2026-09-26T10:15:00.000Z"
}

processor and the other provider fields are opaque strings: do not build logic on their values. Prefer webhooks to polling. To list payments see Pagination.

Cancel a payment#

POST /payments/{id}/cancel (scope payments:cancel) works only while the payment is pending. A payment already sent to the provider cannot be cancelled: refund it once it succeeds.

Amounts#

The API uses both units. Check each field.

WhereFieldUnit
Payment link, createamount, presetAmountMajor units (250.00)
QR code, createamountMinor units (25000)
Payment objectamount, fee_amount, net_amount, refunded_amountMinor units
Refund, requestamountMinor units
Payout, requestamountMajor units
Webhook dataamountsMinor units

Minor units are one hundredth of the currency unit for BWP, USD, GBP and ZAR.