API Overview¶
Base URL: https://api.instapaybill.com
Prefix: /api/v1
Every request and response is application/json (UTF-8). Request bodies are
capped at 10 MB.
Endpoint map¶
Purchases¶
| Method | Path | Service | Auth |
|---|---|---|---|
POST |
/airtime/buy |
Airtime | API key |
POST |
/data/buy |
Data bundle | API key |
POST |
/electricity/validate |
Meter validation | API key |
POST |
/electricity/buy |
Prepaid electricity | API key |
POST |
/cables/validate |
Smart card validation | API key |
POST |
/cables/buy |
Cable TV | API key |
POST |
/education/buy |
Result-checker PINs | API key |
Catalogue¶
| Method | Path | Returns | Auth |
|---|---|---|---|
GET |
/data/agent-data |
Full agent catalogue (data plans + cable plans) | API key |
GET |
/data/networks |
Networks with active data plans | API key |
GET |
/data/networks/{network}/plans |
Plans for one network | API key |
GET |
/data/ |
Data plans | API key |
GET |
/cables/types |
Cable types | API key |
GET |
/cables/ |
Cable plans | Public |
GET |
/electricity/ |
Electricity discos | API key |
GET |
/education/ |
Education exam plans | API key |
GET |
/network/ |
Supported networks | API key |
GET |
/startime/ |
Startimes plans | Public |
GET |
/category/ |
Product categories | Public |
GET |
/network/validate-number/{phoneNumber} |
Carrier lookup for a number | Public |
Transactions and money¶
| Method | Path | Auth |
|---|---|---|
GET |
/transactions/ |
API key |
GET |
/transactions/resolve |
API key |
GET |
/transactions/success-rates |
API key |
GET |
/wallet/manage-wallet-balance |
API key |
GET |
/wallet/generate-wallet-reference |
API key |
GET |
/user/ |
API key |
GET |
/notification/ |
API key |
Sandbox¶
All under /api/v1/sandbox — see Sandbox.
| Method | Path |
|---|---|
POST |
/sandbox/airtime |
POST |
/sandbox/data |
POST |
/sandbox/electricity/validate |
POST |
/sandbox/electricity |
POST |
/sandbox/cables/validate |
POST |
/sandbox/cables |
POST |
/sandbox/education |
POST |
/sandbox/startimes |
Common request fields¶
Fields that apply to most purchase endpoints:
| Field | Type | Notes |
|---|---|---|
apiRefId |
string | Your reference for the order. Stored only for API-channel requests. Look it up with GET /api/v1/transactions/resolve?apiRefID=…. |
pin |
string | Wallet PIN. Ignored for API-key requests — only enforced on app/web channels. |
promoCode / coupon |
string | Discount codes. Not applied to API-channel requests. |
type |
string | Service-specific variant — vtu / share&sell / awuf4u for airtime, prepaid / postpaid for electricity. |
apiRefId is the field most integrations get wrong. If you set it, you can
always find the transaction later without scraping the transaction list.
Common response envelope¶
Every purchase endpoint returns the same shape:
{
"msg": "MTN Airtime Purchase of ₦500 for 08012345678 was successful",
"data": {
"code": 200,
"reference": "IP|TN|A|123|20260918120000_ASDFG",
"description": "MTN Airtime Purchase",
"message": "Top-up of ₦500 to 08012345678 delivered successfully.",
"type": "airtime"
},
"code": 200
}
| Field | Type | Notes |
|---|---|---|
msg |
string | Human-readable summary of the outcome. |
data.code |
number | 200 / 300 / 400. Mirrors the HTTP status. |
data.reference |
string | Your reference for the transaction. Save it. |
data.description |
string | What was bought, e.g. "MTN Airtime Purchase". |
data.message |
string | The outcome text. Safe to show a customer. |
data.type |
string | Service discriminator: airtime, data, electricity, cables, education. |
code |
number | Top-level business code. Same value as data.code. |
Field availability by service¶
Not every service returns every field. Check before you depend on one.
| Field | Airtime | Data | Electricity | Cables | Education |
|---|---|---|---|---|---|
data.code |
✅ | ✅ | ✅ | ✅ | ✅ |
data.reference |
✅ | ✅ | ✅ | ✅ | ✅ |
data.description |
✅ | ✅ | ✅ | ✅ | ✅ |
data.message |
✅ | ✅ | ✅ | ✅ | ✅ |
data.msg |
✅ | ✅ | ✅ | ❌ | ✅ |
data.type |
✅ | ✅ | ✅ | ✅ | ✅ |
data.token |
❌ | ❌ | ✅ | ❌ | ❌ |
data.unit |
❌ | ❌ | ✅ | ❌ | ❌ |
data.data_pin |
❌ | ❌ | ❌ | ❌ | ✅ |
data.reference is your reference, not the provider's
The provider's own reference is overwritten with the platform's internal
item_id before the response is sent. If you need the provider reference
for reconciliation, read it from the transaction record via
resolve.
The data shape differs by channel¶
When you authenticate with an API key, data is the compact envelope above.
When you authenticate with a session JWT, data is the full transaction
document — every internal field, including wallet balances before and after
and the profit margin.
Always code against the API-key shape. If you need a field that only appears in the session shape, it is not part of the supported API contract.
Reference values¶
Networks¶
MTN, AIRTEL, GLO, T2MOBILE
Case-insensitive on input; the platform uppercases before use. 9MOBILE is
accepted as a legacy alias for T2MOBILE in some catalogue responses but
T2MOBILE is the canonical value.
{ "error": [{ "msg": "Invalid network", "path": "network", "suggesstions": ["MTN", "AIRTEL", "GLO", "T2MOBILE"] }] }
(The misspelled suggesstions key is the real field name.)
Electricity meter type¶
PREPAID, POSTPAID — case-insensitive.
Cable type¶
DSTV, GOTV, STARTIMES, SHOWMAX — uppercased before use.
Data plan identifiers¶
A data purchase needs the planId and the network:
planId alone is not enough — the plan lookup is
{ planId, network: network.toUpperCase() }. Omitting network produces
"Plan Id not found", which reads like a bad plan id but is a missing field.
Retrieve valid identifiers from
GET /api/v1/data/agent-data.
Product identifiers¶
The item_id returned as data.reference follows a fixed pattern:
| Segment | Meaning |
|---|---|
IP |
InstaPayBill |
TN |
Transaction |
A |
Airtime (also D data, E electricity, C cables, ED education) |
123 |
Sequential counter |
20260918120000 |
Timestamp, 14 digits, 100 µs resolution |
ASDFG |
Random suffix |
You do not need to construct or parse these. Treat them as opaque strings.
Health and status endpoints¶
| Method | Path | Auth | Returns |
|---|---|---|---|
GET |
/mcp/health |
None | { status, service, version, totalTools } |
GET |
/mcp/tools |
None | Array of { name, description } |
GET |
/api/v1/settings/ |
None | Public settings (commission rates, limits) |
GET |
/api/v1/usecase/ |
None | Feature flags and channel status |
GET |
/api/v1/voice-assistant/health |
None | Voice service health |
GET /api/v1/usecase/ is the fastest way to see which features are currently
enabled for a channel — including the kill switches that can make a purchase
fail with 300 "Service is currently unavailable".
Making requests from a browser¶
CORS is restricted to an allowlist of known origins. The current allowlist
includes https://instapaybill.com, https://www.instapaybill.com,
https://admin.instapaybill.com, https://crm.instapaybill.com and
https://developer.instapaybill.com.
Requests with no Origin header are always allowed. That covers server-to-
server calls, CLI tools, and curl — you do not need to do anything special.
Browser calls from an origin outside the allowlist are blocked, and the CORS headers are omitted from the response. For browser-based integrations, proxy through your own backend rather than calling the API directly from the client — otherwise your live key would be exposed.
Related pages¶
- Authentication — credentials and which endpoints accept them
- Errors & Status Codes — the error contract
- Rate Limits — budgets and the duplicate guard
- Webhooks — async settlement notifications