{"openapi":"3.0.3","info":{"title":"Olympus Pay Merchant API","version":"1.0.0","description":"The public API for merchants to accept payments, manage split recipients, request payouts, and receive webhooks from their own backend. Authenticate every request with `Authorization: Bearer <api-key>`. See GET /api/v1/reference for status values and webhook event types."},"servers":[{"url":"https://merchant.olympuspay.co/api/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An olp_live_... or olp_test_... API key."}},"schemas":{"Error":{"type":"object","properties":{"error":{}}}}},"paths":{"/payments":{"get":{"summary":"List payments","x-scope":"payments:read","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"status","in":"query","schema":{"type":"string"}},{"name":"starting_after","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/payments/{id}":{"get":{"summary":"Get a payment","x-scope":"payments:read","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"},"404":{"description":"Not found"}}}},"/payments/{id}/cancel":{"post":{"summary":"Cancel a pending payment","x-scope":"payments:cancel","description":"Only works while the payment is still pending — cannot void a charge already submitted to the processor.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Cancelled"},"400":{"description":"Not pending"}}}},"/payments/{id}/refund":{"post":{"summary":"Refund a payment (full or partial)","x-scope":"refunds:create_full (no amount) or refunds:create_partial (with amount)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","description":"Major units. Omit for a full refund."}}}}}},"responses":{"200":{"description":"Refunded"},"202":{"description":"Above the approval threshold — pending a second reviewer (live keys only)."}}}},"/payment-links":{"post":{"summary":"Create a payment link","x-scope":"payment_links:write (+ splits:assign if splitRecipientId is set)","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["title","currency"],"properties":{"title":{"type":"string","maxLength":140},"description":{"type":"string","maxLength":500},"amount":{"type":"number"},"currency":{"type":"string","minLength":3,"maxLength":3},"expiresAt":{"type":"string","format":"date-time"},"imageUrl":{"type":"string","format":"uri"},"presetAmount":{"type":"number"},"idempotencyKey":{"type":"string","maxLength":255},"returnUrl":{"type":"string","format":"uri"},"splitRecipientId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Created (or the existing link, if idempotencyKey was reused)"}}}},"/qr-codes":{"post":{"summary":"Create a dynamic QR code","x-scope":"qr_codes:write (+ splits:assign if splitRecipientId is set)","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["mode","currency"],"properties":{"mode":{"type":"string","enum":["fixed_amount","open_amount"]},"amount":{"type":"integer","description":"Minor units. Required for fixed_amount."},"currency":{"type":"string","minLength":3,"maxLength":3},"description":{"type":"string","maxLength":140},"singleUse":{"type":"boolean"},"returnUrl":{"type":"string","format":"uri"},"splitRecipientId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Created"}}}},"/split-recipients":{"get":{"summary":"List split recipients","x-scope":"recipients:read","responses":{"200":{"description":"OK"}}},"post":{"summary":"Register a split recipient (Flutterwave Subaccount)","x-scope":"recipients:write","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["externalReference","name","accountBank","accountNumber","splitValue"],"properties":{"externalReference":{"type":"string","maxLength":200,"description":"Idempotency key — retrying the same value returns the existing recipient."},"name":{"type":"string","maxLength":200},"accountBank":{"type":"string","description":"Flutterwave bank code — see GET /v3/banks/{country} on Flutterwave's own API."},"accountNumber":{"type":"string"},"recipientMobile":{"type":"string","maxLength":30,"description":"Recipient's own mobile number. Optional — falls back to the merchant's own contact phone if omitted."},"splitValue":{"type":"number","minimum":1,"maximum":100,"description":"Percentage of each charge routed to this recipient."}}}}}},"responses":{"200":{"description":"Created (or existing, if externalReference was reused)"}}}},"/split-recipients/{id}":{"patch":{"summary":"Verify or disable a split recipient","x-scope":"recipients:verify (for verified) / recipients:disable (for disabled)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"verified":{"type":"boolean"},"disabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated"}}}},"/payouts":{"get":{"summary":"List payouts","x-scope":"payouts:read","responses":{"200":{"description":"OK"}}},"post":{"summary":"Request a payout","x-scope":"payouts:create","description":"Live keys only — rejected outright on sandbox keys since payouts move real settlement funds.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["amount","currency","destinationType"],"properties":{"amount":{"type":"number","description":"Major units."},"currency":{"type":"string","minLength":3,"maxLength":3},"destinationType":{"type":"string","enum":["olympus_account","flutterwave_bank"]},"bankDetails":{"type":"object","description":"Required when destinationType is flutterwave_bank.","properties":{"accountNumber":{"type":"string"},"bankCode":{"type":"string"},"beneficiaryName":{"type":"string"}}}}}}}},"responses":{"200":{"description":"Processing or completed"},"202":{"description":"Above the approval threshold — pending a second reviewer"},"400":{"description":"Sandbox key, insufficient balance, or invalid destination"}}}},"/payouts/{id}/cancel":{"post":{"summary":"Cancel a pending payout","x-scope":"payouts:cancel","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Cancelled"},"400":{"description":"Already submitted to the processor"}}}},"/settlements":{"get":{"summary":"View settlements","x-scope":"settlements:read (+ reports:export for CSV)","parameters":[{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}},{"name":"splitRecipientId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"]}}],"responses":{"200":{"description":"OK — JSON or text/csv depending on format"}}}},"/account":{"get":{"summary":"View business profile and verification status","x-scope":"account:read or kyc:read","responses":{"200":{"description":"OK"}}}},"/webhooks":{"get":{"summary":"List webhook endpoints","x-scope":"webhooks:read_logs or webhooks:manage","responses":{"200":{"description":"OK"}}},"post":{"summary":"Register a webhook endpoint","x-scope":"webhooks:manage","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","maxLength":500}}}}}},"responses":{"200":{"description":"Created — response includes the signing secret exactly once"}}}},"/webhooks/{id}":{"delete":{"summary":"Remove a webhook endpoint","x-scope":"webhooks:manage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Removed"}}}},"/webhooks/{id}/deliveries":{"get":{"summary":"View delivery logs for a webhook endpoint","x-scope":"webhooks:read_logs","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK"}}}},"/webhooks/deliveries/{id}/retry":{"post":{"summary":"Retry a failed webhook delivery","x-scope":"webhooks:retry","description":"Resends the exact original payload with a fresh signature timestamp.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retried"}}}},"/reference":{"get":{"summary":"Status values and webhook event type reference","security":[],"responses":{"200":{"description":"OK — no authentication required"}}}}}}