OuiPay
API ReferenceServices

Services

Bill payments, airtime, data, and utility purchases through one order API.

A service is a purchasable digital product or bill: mobile top-up, data bundle, utility payment, subscription, or voucher. Every purchase produces a service order linked to a transaction entry: the transaction is the ledger truth, the order tracks fulfilment of the purchased item.

You never integrate with a fulfilment vendor directly. OuiPay routes each order to the fulfilment rail configured for the service and country, and exposes the same contract regardless of which rail executes it.

Service catalogue

service_code identifies the product family. Availability is per country: the catalogue for a country only returns the services that country offers.

CodeCategorySellsRecipient
airtimemobileMobile airtime top-upPhone number
datamobileMobile data bundlesPhone number
electricityutilitiesPrepaid token / postpaid billMeter number
waterutilitiesWater utility billsMeter/account no.
internetutilitiesISP and broadband subscriptionsCustomer ID
tventertainmentCable and satellite subscriptionsSmartcard / IUC
bettingentertainmentBetting wallet fundingAccount ID / phone
gift_cardsentertainmentDigital gift cardsRecipient email
educationeducationExam PINs and result-checker productsCandidate/profile
insurancefinanceInsurance premiums and cover packagesPolicy holder

Two pricing models exist. Fixed-price services (data, tv, internet, education, insurance, gift_cards) sell a plan selected from /plans. Open-amount services (airtime, electricity, water, betting) take a customer-entered provider_cost_minor.

The operators behind each service (mobile networks, DisCos, TV providers, exam bodies) resolve per country: see Supported networks for per-market coverage.

The purchase flow

GET  /services?country=            catalogue for the service country
GET  /services/{code}              form schema + rules + country_context
GET  /services/{code}/operators    networks, DisCos, providers for the service
GET  /services/{code}/plans        bundles/bouquets for an operator
GET  /services/{code}/variants     variants (e.g. prepaid / postpaid meter)
POST /services/{code}/validate     verify the recipient before quoting
POST /services/quote               locked price, fee, and FX
POST /services/orders              create the order and collect payment
GET  /services/orders/{id}/status  poll, or wait for the webhook

Not every step applies to every service. The steps array on the service definition tells the client which inputs to collect, and requires_validation tells it whether to call /validate before quoting.

The service order object

{
  "id": "01M2S18...",
  "transaction_id": "01M2S18...",
  "payment_transaction_id": "01M2S18...",
  "country_code": "NG",
  "service_code": "electricity",
  "status": "fulfilling",
  "customer_amount_minor": 510000,
  "fee_minor": 10000,
  "provider_cost_minor": 500000,
  "currency": "NGN",
  "operator_code": "ikeja-electric",
  "meter_type": "prepaid",
  "account_ref": "04591234567",
  "provider_reference": "IKEDC-99218...",
  "quote_id": "01M2S17...",
  "created_at": "2026-09-18T02:00:00Z",
  "updated_at": "2026-09-18T02:00:41Z"
}
FieldTypeNotes
transaction_idstringThe type=service transaction entry: source of truth
payment_transaction_idstringThe collection transaction once payment is initiated
country_codestringService country the order executes in (ISO 3166-1 alpha-2)
customer_amount_minorintWhat the customer pays, in currency
provider_cost_minorintDestination service value, in the destination currency
fee_minorintOuiPay fee included in customer_amount_minor
meter_typestringSelected variant when the service has one (e.g. prepaid)
provider_referencestringFulfilment reference once the order is dispatched
quote_idstringThe locked quote this order was priced from
fulfillment_snapshotobjectFulfilment detail: tokens, pins, and receipts land here

Same-currency orders always satisfy customer_amount_minor = provider_cost_minor + fee_minor. Cross-currency orders carry the locked FX terms in pricing_snapshot.

Order status

pending -> awaiting_payment -> fulfilling -> completed
                                   |-> failed | retry_required | refund_pending -> refunded
                                   |-> unknown (reconciled to completed or failed)
pending|awaiting_payment -> cancelled
StatusMeaning
pendingCreated; payment not yet initiated
awaiting_paymentWaiting on the collection to settle
fulfillingPaid; purchase dispatched to the fulfilment rail
completedDelivered: fulfillment_snapshot carries tokens/pins
failedDefinite failure; customer funds released or refunded
unknownTimed out with no definite outcome: reconciled, never re-purchased
retry_requiredQueued for a controlled fulfilment retry
provider_funding_failurePaid, but the rail could not fund the purchase; refund path opens
manual_fulfilmentHeld for an authorized operator to complete
refund_pendingRefund in progress on the payment
refundedCustomer money returned; terminal
cancelledCancelled before fulfilment; terminal

unknown is not failed: a timed-out purchase may have reached the rail. Treat it as in-flight and wait for the terminal webhook or a later status poll.

Webhooks

Fulfilment is asynchronous. Subscribe to service_order.completed and service_order.failed rather than polling /status in a tight loop. See Webhook Events.

Country scoping

Every services call takes a service country: the country the purchase executes in, which decides the catalogue, operators, plans, currency, and limits. It is independent of the customer's account country. See Countries for the home vs service country model and the country_context selector contract.

Endpoints

MethodPathDescription
GET/v1/servicesCatalogue for a country
GET/v1/services/{code}Definition, steps, limits
GET/v1/services/{code}/availabilityEffective country selector for this customer
GET/v1/services/{code}/payment-methodsPayable methods for this service and country
GET/v1/services/{code}/operatorsNetworks / billers
GET/v1/services/{code}/plansBundles and fixed-price plans
GET/v1/services/{code}/variantsVariants (meter type, etc.)
POST/v1/services/{code}/validateVerify a recipient
POST/v1/services/quoteLocked price quote
POST/v1/services/ordersCreate an order
GET/v1/services/orders/{id}Order detail
GET/v1/services/orders/{id}/statusCompact status poll