Skip to Content
Bill paymentsOverview

Bill payments overview

Pay electricity, cable TV, and betting wallet funding using the same API as Airtime and Airtime Async. Authentication headers are unchanged. Response field rules: Field conventions.

ProductGuideUse msisdn as
ELECTRICITYElectricityMeter number (prepaid or postpaid)
CABLECable TVSmartcard / IUC number
BETTINGBettingCustomer ID on the betting platform
POST https://api.subthingy.io/v1/transactions

Sync on the external API — the create response includes the final outcome in one response for electricity, cable, and betting. Airtime and data on the same route are async — see Airtime Async.

Contact your account manager to enable bill products and betting on your merchant profile.

Plan catalogs

Names and amounts (no plan IDs): Catalog — electricity, cable, betting.

Each bill product is identified by a numeric plan_code (catalog plan id). Provider routing fields are resolved server-side — you never send raw service_id or variation_id.

GET /v1/plans/bills/{product}

{product} is electricity, cable, or betting. Optional filter: ?network=Ikeja Electric (electricity) or ?network=DSTV (cable).

curl "https://api.subthingy.io/v1/plans/bills/electricity?network=Ikeja Electric" \ -H "X-Merchant-Key: mk_your_key_id" \ -H "X-Merchant-Secret: your_issued_secret"

HTTP 200:

{ "status": "2000", "description": "Operation Successful-BILLS-ELECTRICITY", "data": [ { "id": 1001, "name": "Ikeja Electric Prepaid", "network": "Ikeja Electric", "product": "ELECTRICITY", "amount_type": "variable" }, { "id": 1002, "name": "Ikeja Electric Postpaid", "network": "Ikeja Electric", "product": "ELECTRICITY", "amount_type": "variable" } ] }
FieldDescription
idPass as plan_code on verify and purchase
amount_typevariable (you set amount) or fixed (amount is set from catalog)
pricePresent on fixed cable bouquets

Pass the returned plan id as plan_code. Product-specific network lists: Electricity, Cable TV, Betting.

Betting is opt-in per merchant. Contact support if your profile is not enabled.

Verify customer (optional)

Customer verification also runs automatically before purchase. To validate a meter or smartcard without creating a transaction, use the same merchant credentials as purchase:

POST /v1/transactions/verify
curl -X POST "https://api.subthingy.io/v1/transactions/verify" \ -H "Content-Type: application/json" \ -H "X-Merchant-Key: mk_your_key_id" \ -H "X-Merchant-Secret: your_issued_secret" \ -d '{ "merchant": "YOUR_MERCHANT", "msisdn": "10000000001", "network": "Ikeja Electric", "product": "ELECTRICITY", "plan_code": "1001" }'
FieldRequiredDescription
merchant or merchant_codeYesYour merchant profile
msisdn or customer_msisdnYesMeter, smartcard, or betting ID
networkYesBiller name (e.g. Ikeja Electric)
productYesELECTRICITY, CABLE, or BETTING
plan_codeYes*Catalog id from Plan catalogs
service_idYes*Legacy service code — omit when using plan_code

* Send plan_code (recommended) or service_id, not both.

HTTP 200 (Subthingy envelope):

{ "state": "ok", "code": "00", "message": "customer verified", "result": { "product": "ELECTRICITY", "network": "Ikeja Electric", "msisdn": "10000000001", "customer_name": "Test Customer", "customer_address": "Ikeja Electric - Test Address", "min_amount": "1000", "max_amount": "50000" } }

Electricity verify may also include disco details when the biller returns them: meter_number, arrears, account_type, meter_type, district, business_unit, district_reference, and tariff. Empty values are omitted. min_amount / max_amount are purchase limits (catalog floor when the meter reports 0), not arrears.

No request_ref on verify. You may skip verify and proceed directly to purchase.

HTTP 400 — the meter, smartcard, or betting ID was rejected, or the request was invalid. This is not an outage. Do not retry as if the API is down. message is the biller’s reason when available:

{ "status": "error", "code": 400, "message": "This meter is not correct or is not a valid Ibadan Electric prepaid meter. Please check and try again" }

Verify errors use status, code, and message (not the success state / result envelope).

HTTP 502 — verify could not be completed. Retry with backoff. message is generic.

Product-specific guides: Electricity, Cable TV, Betting.

Check status (optional)

Bill purchases return the final outcome on create. To re-fetch a transaction later, use the same status endpoint as airtime and data:

GET /v1/transactions/status?request_ref={request_ref}
curl "https://api.subthingy.io/v1/transactions/status?request_ref=subthingy-bill-ikeja-001" \ -H "X-Merchant-Key: mk_your_key_id" \ -H "X-Merchant-Secret: your_issued_secret"

Status poll uses state, code, message, payload (different from create). Full shape: Airtime Async — Check status.

List transactions

Bill payments appear in the standard transaction list:

GET /v1/transactions?page=1&limit=20

Filter by product in your integration layer using the product field on each row (ELECTRICITY, CABLE, BETTING).

Last updated on