Baton Developer API
Sell bills from your prepaid Baton wallet over a simple REST API. All amounts are in kobo (1 NGN = 100 kobo). Airtime, data bundles, electricity (prepaid and postpaid) and cable TV are live today.
1. How it works
- Create a business account and wait for Baton to approve it.
- Fund your wallet by transferring to your dedicated account number.
- Create an API key in your dashboard.
- Call the transactions endpoint. Each sale debits your wallet instantly.
- Receive a webhook when the sale settles, or poll the transaction.
2. Funding your wallet
Your dashboard shows an account number that belongs only to your business. Any transfer into it credits your wallet automatically, usually within seconds, and appears in your wallet history. A sale is declined with 402 when the balance is short.
3. Authentication
Pass your key id and secret as a bearer token, separated by a colon.
Authorization: Bearer pk_xxx:sk_yyyRequests are rate limited per key (120 per minute by default). On overflow you get 429 with Retry-After and X-RateLimit-* headers.
4. Base URL
https://batonbills.com/api/public/partners/v15. List products
curl https://batonbills.com/api/public/partners/v1/products \
-H "Authorization: Bearer pk_xxx:sk_yyy"{
"products": [
{ "slug": "mtn-airtime", "name": "MTN Airtime", "pricing_mode": "variable", "category": "airtime", "price_kobo": null, "discount_bps": 200, "your_price_kobo": null }
]
}Only categories enabled for API sales are returned. Today that is airtime, data bundles, electricity and cable TV. Data bundles are fixed-price: send the exact price_kobo as amount_kobo and your wallet is charged your_price_kobo.discount_bps is your reseller discount in basis points (200 = 2%). For variable-amount products your wallet is charged the amount you send less that discount, so a NGN 1,000 MTN top-up at 2% costs you NGN 980. Current airtime discounts: MTN 2%, Airtel 2%, Glo 4%, 9mobile 4%. Data bundles carry the same discount per network.
6. Check your wallet
curl https://batonbills.com/api/public/partners/v1/balance \
-H "Authorization: Bearer pk_xxx:sk_yyy"7. Sell airtime
Send an Idempotency-Key unique to your order. Replaying the same key with the same body returns the original sale; a different body returns 409.
curl -X POST https://batonbills.com/api/public/partners/v1/transactions \
-H "Authorization: Bearer pk_xxx:sk_yyy" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-12345" \
-d '{
"product_slug": "mtn-airtime",
"recipient": "08012345678",
"amount_kobo": 50000,
"reference": "order-12345"
}'{
"transaction": {
"reference": "BTN-...",
"partner_reference": "order-12345",
"status": "success",
"recipient": "08012345678",
"amount_kobo": 50000,
"amount_charged_kobo": 49000,
"discount_kobo": 1000
}
}amount_kobo is the airtime value delivered. amount_charged_kobo is what left your wallet after your discount.
7a. Sell data bundles
Each bundle is its own fixed-price product, for example data-mtn-200. Call /products and filter by category data for the full list across MTN, Airtel, Glo and 9mobile, with prices. Send the exact price_kobo as amount_kobo and the phone number as recipient. Your wallet is charged your_price_kobo (the price less your per-network discount, same as airtime).
curl -X POST https://batonbills.com/api/public/partners/v1/transactions \
-H "Authorization: Bearer pk_xxx:sk_yyy" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-456" \
-d '{
"product_slug": "data-mtn-200",
"recipient": "08012345678",
"amount_kobo": 10000,
"reference": "order-456"
}'{
"transaction": {
"reference": "BTN-...",
"status": "success",
"recipient": "08012345678",
"amount_kobo": 10000,
"amount_charged_kobo": 9800,
"discount_kobo": 200
}
}Sending an amount that does not match the bundle price returns 400.
7b. Sell electricity (prepaid and postpaid)
All major discos are available, prepaid and postpaid: Abuja, Eko, Ikeja, Ibadan, Enugu, Port Harcourt, Benin, Jos, Kaduna, Kano, Yola, Aba Power, Access Power, Bonny Utility and Brains & Hammers. Slugs follow the pattern ekedc-prepaid, ikeja-postpaid, phed-prepaid (Ikeja, Eko and Abuja prepaid are ikedc-prepaid, ekedc-prepaid, aedc-prepaid); call /products for the full list. Always verify the meter first so you can show your customer the name on the meter before taking payment. Lookups are free.
curl -X POST https://batonbills.com/api/public/partners/v1/lookup \
-H "Authorization: Bearer pk_xxx:sk_yyy" \
-H "Content-Type: application/json" \
-d '{ "product_slug": "ekedc-prepaid", "recipient": "62120126537" }'{
"valid": true,
"recipient": "62120126537",
"customer_name": "JOHN DOE",
"address": "1B Sample Close, Lagos",
"minimum_amount_kobo": 100000
}An unknown meter returns { "valid": false, "message": "..." }. Then sell with the same transactions endpoint. The amount is in whole naira (multiple of 100 kobo), minimum NGN 1,000. Required: pass the customer's 11-digit mobile number as metadata.phone (the token is delivered to it). The meter number goes in recipient. Missing or invalid phone returns 400 before your wallet is charged.
curl -X POST https://batonbills.com/api/public/partners/v1/transactions \
-H "Authorization: Bearer pk_xxx:sk_yyy" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-778" \
-d '{
"product_slug": "ekedc-prepaid",
"recipient": "62120126537",
"amount_kobo": 1000000,
"reference": "order-778",
"metadata": { "phone": "08012345678" }
}'{
"transaction": {
"reference": "BTN-...",
"status": "success",
"recipient": "62120126537",
"amount_kobo": 1000000,
"amount_charged_kobo": 1000000,
"token": "4095-6299-9589-6790-1502",
"token_units": "44.4"
}
}Give the token to your customer to load on the meter. If the disco is slow you get 202 with status pending; the token arrives in the transaction.success webhook, or poll the transaction. Failed sales are refunded to your wallet automatically.
7c. Sell cable TV (DStv, GOtv, StarTimes)
Each bouquet is its own fixed-price product, for example dstv-compe36 (DStv Compact), gotv-gotvmax (GOtv Max) or startimes-basic. Call /products for the full list with prices. Verify the smartcard first:
curl -X POST https://batonbills.com/api/public/partners/v1/lookup \
-H "Authorization: Bearer pk_xxx:sk_yyy" \
-H "Content-Type: application/json" \
-d '{ "product_slug": "dstv-compe36", "recipient": "8213124636" }'{
"valid": true,
"recipient": "8213124636",
"customer_name": "JOHN DOE",
"current_bouquet": "DStv Compact",
"due_date": "2026-10-04T00:00:00"
}Then sell with the transactions endpoint, sending the exact price_kobo as amount_kobo, and the smartcard or IUC number as recipient. The customer's 11-digit mobile number in metadata.phone is required.
curl -X POST https://batonbills.com/api/public/partners/v1/transactions \
-H "Authorization: Bearer pk_xxx:sk_yyy" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-901" \
-d '{
"product_slug": "dstv-compe36",
"recipient": "8213124636",
"amount_kobo": 1900000,
"reference": "order-901",
"metadata": { "phone": "08012345678" }
}'8. Fetch one transaction
curl https://batonbills.com/api/public/partners/v1/transactions/BTN-XXXX \
-H "Authorization: Bearer pk_xxx:sk_yyy"9. Webhooks
Register an https endpoint in your dashboard. Each delivery is signed with your webhook secret; verify the signature header before trusting the payload. Failed deliveries can be replayed from the dashboard.
10. Errors
400validation problem or unknown product401missing or invalid key402not enough wallet balance403key missing a scope, business not approved, or category not enabled409idempotency key reused with a different body429rate limited
Ready to start?
Create your business account, fund the wallet and generate a key.
Create a business account