Skip to main content
POST
Validate a customer

Why the enquiry exists

A bill is paid to a person, not just to a biller. The enquiry confirms the meter or account exists, returns the name and address the biller holds for it, and prices the payment — charge, commission, and totalDebit. Show that name to the payer before taking money: it is the only check that the reference was typed correctly.

Naming the product

Sakawave identifiers only. A slug will not resolve here, and neither will an upstream provider’s id — the route to a provider, and whatever that provider needs in its own payload, is resolved on our side. The same body therefore works whichever provider serves the biller, and keeps working when we change one. Any other field — groupId, groupSlug, billerSlug, packageSlug, productName — is rejected.

Amounts are decimals here

Bill payments use decimal strings — "5000.00" — not the minor units the rest of the API uses. Everything in this service, request and response alike, is in naira and kobo written out.
An enquiry expires after ten minutes, and paying with an expired one fails with 409 bill_enquiry_expired. Enquire immediately before paying, not when the user opens the form.

Error codes

Authorizations

Authorization
string
header
required

A secret API key, sent as Authorization: Bearer sk_test_… in sandbox or Bearer sk_live_… in live.

Body

application/json

Sakawave identifiers only. Slugs and provider references are rejected, so the same body works whichever provider serves the biller.

customerId
string
required

What the biller identifies the customer by: a meter number, an account number, or a phone number for airtime and data.

Required string length: 1 - 200
billerId
string
required

The biller’s Sakawave id, from the catalog.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

packageId
string

The package’s Sakawave id. Required when the biller has packages, rejected when it has none.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

amount
string

A decimal display amount returned by transfer APIs. Preserve it as a string.

Pattern: ^-?\d+(?:\.\d+)?$
Example:

"25000.00"

Response

Successful response.

id
string
required

Send this as enquiryId when creating the payment.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

billerId
string
required

A 26-character ULID.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

billerSlug
string
required
packageId
string | null
required

Null when the biller sells no packages.

Required string length: 26
Pattern: ^[0-7][0-9A-HJKMNP-TV-Z]{25}$
Example:

"01K2Z3AB4C5D6E7F8G9HJKMNPQ"

packageSlug
string | null
required
customer
object
required

What the biller returned about the customer, filtered to a safe subset: names, customer type, address, district, whether they can be vended, minimum vend, total due, due date, and available products. Shape varies by biller.

totalDue
string | null
required

A decimal display amount returned by transfer APIs. Preserve it as a string.

Pattern: ^-?\d+(?:\.\d+)?$
Example:

"25000.00"

minimumAmount
string | null
required

A decimal display amount returned by transfer APIs. Preserve it as a string.

Pattern: ^-?\d+(?:\.\d+)?$
Example:

"25000.00"

charge
string | null
required

A decimal display amount returned by transfer APIs. Preserve it as a string.

Pattern: ^-?\d+(?:\.\d+)?$
Example:

"25000.00"

commission
string | null
required

A decimal display amount returned by transfer APIs. Preserve it as a string.

Pattern: ^-?\d+(?:\.\d+)?$
Example:

"25000.00"

totalDebit
string | null
required

A decimal display amount returned by transfer APIs. Preserve it as a string.

Pattern: ^-?\d+(?:\.\d+)?$
Example:

"25000.00"

expiresAt
string<date-time>
required
Example:

"2026-08-14T09:00:00.000Z"