Bill Payments
The bill payment API allows merchants to purchase various bills (airtime, data, TV subscriptions, utility, insurance, education) using their wallet balance. All amounts are specified in kobo (e.g., ₦100 = 10000 kobo).
Overview
iNPAY's bill payment service enables you to offer value-added services to your customers, including:
- Airtime: Mobile phone top-ups
- Data: Internet data bundles
- TV Subscriptions: Cable TV services (DSTV, GOTV, etc.)
- Utility: Electricity bill payments
- Insurance: Insurance premium payments
- Education: WAEC, JAMB, and other educational services
Authentication
Bill payment endpoints use the same authentication as other API endpoints:
- Header:
Authorization: Bearer sk_live_your_secret_key_here - Wallet: Must specify
fromWallet(wallet PayID ending with.wallet)
Commission Structure
Commission is calculated as a discount (deducted from bill amount before debiting merchant):
| Bill Type | Commission |
|---|---|
| Airtime | 1.5% |
| Data | 1.5% |
| Electricity | 0.5% |
| Cable TV | 0.5% |
| Education | ₦100 flat |
Note: Convenience fees (if any) are added to the total charge, but commission percentage is not applied to convenience fees.
Service ID Reference
Below is a comprehensive list of serviceIDs for each category. Important: Always use the exact serviceID as shown below.
Airtime Services
| ServiceID | Provider Name |
|---|---|
mtn | MTN |
glo | GLO |
airtel | Airtel |
etisalat | 9mobile (formerly Etisalat) |
Data Services
| ServiceID | Provider Name |
|---|---|
mtn-data | MTN Data |
glo-data | GLO Data |
airtel-data | Airtel Data |
etisalat-data | 9mobile Data (Note: Use etisalat-data, not 9mobile-data) |
glo-sme-data | GLO Data (SME) |
smile-direct | Smile Payment |
spectranet | Spectranet Internet Data |
TV Subscription Services
Common serviceIDs include:
dstv- DSTVgotv- GOTVstartimes- StarTimes
Note: Use the /services endpoint with categoryIdentifier=tv-subscription to get the complete list.
Electricity/Utility Services
Common serviceIDs include:
ikeja-electric- Ikeja Electric (IKEDC)eko-electric- Eko Electric (EKEDC)kano-electric- Kano Electricportharcourt-electric- Port Harcourt Electricjos-electric- Jos Electricibadan-electric- Ibadan Electrickaduna-electric- Kaduna Electric
Note:
- Use the
/servicesendpoint withcategoryIdentifier=electricity-billto get the complete list - For utility verification, the
typeparameter is required and must be either"prepaid"or"postpaid"
Education Services
waec-result- WAEC Result Checkerwaec-registration- WAEC Registrationjamb- JAMB
Note: Use the /services endpoint with categoryIdentifier=education to get the complete list.
Insurance Services
Note: Use the /services endpoint with categoryIdentifier=insurance to get available insurance services.
Important Notes
-
9mobile/Etisalat:
- For airtime: Use
etisalat - For data: Use
etisalat-data(NOT9mobile-data)
- For airtime: Use
-
Variation Amount: When purchasing data or other fixed-price services, the
variation_amountfield from the variations response represents the actual cost of the service in kobo.- VTpass returns
variation_amountin naira, but our API converts it to kobo for consistency - Use this amount directly in your calculations when purchasing fixed-price services (like data plans)
- Example: If VTpass returns
variation_amount: 100(₦100), our API returnsvariation_amount: 10000(10000 kobo = ₦100)
- VTpass returns
-
Dynamic Service Lists: While this reference provides common serviceIDs, always use the
/servicesendpoint to get the most up-to-date list of available services for each category, as VTpass may add or remove services.
Base URL
https://api.inpaycheckout.com/api/v1/developer
Endpoints
Get Bill Categories
Retrieve all available bill payment categories.
GET /api/v1/developer/bills/categories
Headers:
Authorization: Bearer sk_live_your_secret_key_here
Response:
{
"success": true,
"message": "Bill categories retrieved successfully",
"data": {
"categories": [
{
"category": "airtime",
"name": "Airtime VTU",
"identifier": "airtime"
},
{
"category": "data",
"name": "Data Subscription",
"identifier": "data"
}
]
}
}
Get Services for Category
Get all services available for a specific category.
GET /api/v1/developer/bills/services?categoryIdentifier=airtime
Headers:
Authorization: Bearer sk_live_your_secret_key_here
Response:
{
"success": true,
"message": "Bill services retrieved successfully",
"data": {
"services": [
{
"serviceID": "mtn",
"name": "MTN",
"variation": "mtn",
"category": "airtime"
},
{
"serviceID": "glo",
"name": "GLO",
"variation": "glo",
"category": "airtime"
}
]
}
}
Get Variations for Service
Get available variations (plans/bundles) for a specific service.
GET /api/v1/developer/bills/variations?serviceID=mtn-data
Important: For 9mobile data, use serviceID=etisalat-data (NOT 9mobile-data)
Headers:
Authorization: Bearer sk_live_your_secret_key_here
Response:
{
"success": true,
"message": "Bill variations retrieved successfully",
"data": {
"serviceName": "MTN Data",
"serviceID": "mtn-data",
"convenienceFee": 0,
"variations": [
{
"variation_code": "mtn-500mb-100",
"name": "MTN 500MB - ₦100",
"variation_amount": 10000,
"fixedPrice": "Yes"
}
]
}
}
Note: The variation_amount field represents the actual cost of the service/variation in kobo.
- VTpass returns
variation_amountin naira, but our API converts it to kobo for consistency - Use this amount directly in your calculations when purchasing fixed-price services (like data plans)
- Example: If VTpass returns
variation_amount: 100(₦100), our API returnsvariation_amount: 10000(10000 kobo = ₦100)
Verify Bill Account
Verify bill account details before purchase (required for TV subscriptions, utility, and JAMB).
POST /api/v1/developer/bills/verify
Headers:
Authorization: Bearer sk_live_your_secret_key_here
Content-Type: application/json
Request Body (TV Subscription):
{
"serviceID": "dstv",
"billersCode": "1234567890",
"phone": "08012345678"
}
Note: For TV subscriptions, the type field is optional and not required.
Request Body (Utility/Electricity - Prepaid):
{
"serviceID": "ikeja-electric",
"billersCode": "12345678901",
"phone": "08012345678",
"type": "prepaid"
}
Request Body (Utility/Electricity - Postpaid):
{
"serviceID": "ikeja-electric",
"billersCode": "12345678901",
"phone": "08012345678",
"type": "postpaid"
}
Request Body (JAMB):
{
"serviceID": "jamb",
"billersCode": "12345678901",
"phone": "08012345678",
"type": "jamb-pin-variation-code"
}
Important Notes about the type field:
-
For Utility/Electricity Services:
- The
typefield is required and must be either"prepaid"or"postpaid" - This tells the system whether you're verifying a prepaid meter or a postpaid meter account
- Example:
"type": "prepaid"for prepaid electricity meters
- The
-
For JAMB Services:
- The
typefield is required and should be the variation code obtained from callinggetVariationCodes("jamb") - First, call the variations endpoint for JAMB to get the available variation codes
- Then use one of those variation codes as the
typevalue - Example: If
getVariationCodes("jamb")returns"jamb-pin-2024", use"type": "jamb-pin-2024"
- The
-
For TV Subscriptions:
- The
typefield is optional and not required - You can omit it entirely for TV subscription verification
- The
Response (TV):
{
"success": true,
"message": "Bill account verified successfully",
"data": {
"customerName": "John Doe",
"renewalAmount": 2500,
"currentBouquet": "Compact",
"expiryDate": "2024-12-31"
}
}
Response (Utility):
{
"success": true,
"message": "Bill account verified successfully",
"data": {
"customerName": "John Doe",
"customerAddress": "123 Main St",
"meterType": "prepaid"
}
}
Purchase Bill Payment
Purchase a bill payment using your wallet balance.
POST /api/v1/developer/bills/purchase
Headers:
Authorization: Bearer sk_live_your_secret_key_here
Content-Type: application/json
Request Body (Airtime):
{
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "mtn",
"amount": 10000,
"phone": "08012345678",
"narration": "MTN Airtime purchase",
"reference": "unique-ref-123"
}
Request Body (Data):
{
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "mtn-data",
"variation_code": "mtn-500mb-100",
"phone": "08012345678",
"narration": "MTN Data purchase",
"reference": "unique-ref-124"
}
Request Body (TV Subscription - Renewal):
{
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "dstv",
"billersCode": "1234567890",
"phone": "08012345678",
"subscription_type": "renewal",
"amount": 2500,
"quantity": 1,
"narration": "DSTV renewal",
"reference": "unique-ref-125"
}
Request Body (TV Subscription - Change Bouquet):
{
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "dstv",
"billersCode": "1234567890",
"phone": "08012345678",
"subscription_type": "change",
"variation_code": "dstv-compact",
"quantity": 1,
"narration": "DSTV bouquet change",
"reference": "unique-ref-126"
}
Request Body (Utility - Prepaid):
{
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "ikeja-electric",
"billersCode": "12345678901",
"phone": "08012345678",
"variation_code": "prepaid",
"amount": 5000,
"narration": "IKEDC prepaid payment",
"reference": "unique-ref-127"
}
Request Body (Education - WAEC Result Checker):
{
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "waec-result",
"phone": "08012345678",
"variation_code": "waec-result-checker",
"quantity": 1,
"narration": "WAEC result checker",
"reference": "unique-ref-128"
}
Response (Success - Airtime):
{
"success": true,
"message": "Bill payment completed successfully",
"data": {
"transactionId": "iNPAY-abc123def4",
"reference": "unique-ref-123",
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "mtn",
"billType": "airtime",
"amount": 10000,
"phone": "08012345678",
"commission": {
"rate": "1.5%",
"amount": 150,
"merchantDebitAmount": 9850
},
"convenienceFee": 0,
"totalCharge": 10000,
"status": "completed",
"vtpassReference": "vtpass-ref-123"
}
}
Response (Success - Utility/Electricity):
{
"success": true,
"message": "Bill payment completed successfully",
"data": {
"transactionId": "iNPAY-abc123def4",
"reference": "unique-ref-123",
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "ikeja-electric",
"billType": "electricity",
"amount": 5000,
"phone": "08012345678",
"commission": {
"rate": "0.5%",
"amount": 25,
"merchantDebitAmount": 4975
},
"convenienceFee": 0,
"totalCharge": 5000,
"status": "completed",
"vtpassReference": "vtpass-ref-123",
"token": "1234-5678-9012-3456"
}
}
Response (Success - Education/WAEC):
{
"success": true,
"message": "Bill payment completed successfully",
"data": {
"transactionId": "iNPAY-abc123def4",
"reference": "unique-ref-123",
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "waec-result",
"billType": "education",
"amount": 2000,
"phone": "08012345678",
"commission": {
"rate": "₦100 flat",
"amount": 10000,
"merchantDebitAmount": 1900
},
"convenienceFee": 0,
"totalCharge": 2000,
"status": "completed",
"vtpassReference": "vtpass-ref-123",
"cards": "1234567890"
}
}
Response (Failed):
{
"success": false,
"message": "Bill payment failed. Transaction has been recorded for manual review.",
"code": "BILL_PAYMENT_FAILED",
"transactionId": "iNPAY-abc123def4",
"reference": "unique-ref-123",
"amount": 10000,
"status": "failed",
"requiresManualReview": true,
"error": "INSUFFICIENT_BALANCE",
"vtpassCode": "INSUFFICIENT_BALANCE"
}
Note: Bill-type-specific fields are only included when relevant:
- Utility payments:
token(meter token) - Insurance:
certUrl(certificate URL) - Education/WAEC Registration:
tokens(registration tokens) - Education/WAEC Result Checker:
cards(result checker cards) - Education/JAMB:
pin(JAMB PIN)
Webhooks
Bill Purchase Completed Event
You'll receive a webhook notification when a bill payment is completed.
Airtime/Data Example:
{
"event": "bill.purchase.completed",
"timestamp": "2024-01-01T10:35:00.000Z",
"data": {
"transactionId": "iNPAY-abc123def4",
"reference": "unique-ref-123",
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "mtn",
"billType": "airtime",
"amount": 10000,
"phone": "08012345678",
"commission": {
"rate": "1.5%",
"amount": 150,
"merchantDebitAmount": 9850
},
"convenienceFee": 0,
"totalCharge": 10000,
"status": "completed",
"vtpassReference": "vtpass-ref-123",
"completedAt": "2024-01-01T10:35:00.000Z"
}
}
Utility/Electricity Example (with token):
{
"event": "bill.purchase.completed",
"timestamp": "2024-01-01T10:35:00.000Z",
"data": {
"transactionId": "iNPAY-abc123def4",
"reference": "unique-ref-123",
"fromWallet": "merchant.wallet.1234567890",
"serviceID": "ikeja-electric",
"billType": "electricity",
"amount": 5000,
"phone": "08012345678",
"commission": {
"rate": "0.5%",
"amount": 25,
"merchantDebitAmount": 4975
},
"convenienceFee": 0,
"totalCharge": 5000,
"status": "completed",
"vtpassReference": "vtpass-ref-123",
"token": "1234-5678-9012-3456",
"completedAt": "2024-01-01T10:35:00.000Z"
}
}
Note: Bill-type-specific fields are only included when relevant:
- Utility payments:
token(meter token) - Insurance:
certUrl(certificate URL) - Education/WAEC Registration:
tokens(registration tokens) - Education/WAEC Result Checker:
cards(result checker cards) - Education/JAMB:
pin(JAMB PIN)
Error Handling
Common Error Codes
| Code | Description | Details |
|---|---|---|
WALLET_PAYID_REQUIRED | Bill payments require wallet PayID | PayID must end with .wallet |
AMOUNT_TOO_LOW | Minimum bill payment amount not met | Below minimum (₦50 for airtime/data, ₦1,000 for others) |
AMOUNT_TOO_HIGH | Amount exceeds maximum limit | Above ₦100,000 limit |
INSUFFICIENT_WALLET_BALANCE | Insufficient wallet balance | Wallet balance too low |
BILL_PAYMENT_FAILED | Bill payment failed | VTpass payment failed (transaction recorded for review) |
FETCH_CATEGORIES_FAILED | Failed to fetch bill categories | VTpass API error |
FETCH_SERVICES_FAILED | Failed to fetch services | VTpass API error |
FETCH_VARIATIONS_FAILED | Failed to fetch variations | VTpass API error |
VERIFY_ACCOUNT_FAILED | Failed to verify account | Smartcard/meter/Profile ID verification failed |
Error Response Format
{
"success": false,
"message": "Insufficient wallet balance",
"code": "INSUFFICIENT_WALLET_BALANCE"
}
Code Examples
Node.js with Axios
const axios = require('axios');
class InpayBillPaymentAPI {
constructor(secretKey, baseUrl = 'https://api.inpaycheckout.com') {
this.secretKey = secretKey;
this.baseUrl = baseUrl;
}
async getBillCategories() {
try {
const response = await axios.get(
`${this.baseUrl}/api/v1/developer/bills/categories`,
{
headers: {
'Authorization': `Bearer ${this.secretKey}`
}
}
);
return response.data;
} catch (error) {
console.error('Error getting bill categories:', error.response?.data || error.message);
throw error;
}
}
async getBillServices(categoryIdentifier) {
try {
const response = await axios.get(
`${this.baseUrl}/api/v1/developer/bills/services`,
{
params: {
categoryIdentifier
},
headers: {
'Authorization': `Bearer ${this.secretKey}`
}
}
);
return response.data;
} catch (error) {
console.error('Error getting bill services:', error.response?.data || error.message);
throw error;
}
}
async getBillVariations(serviceID) {
try {
const response = await axios.get(
`${this.baseUrl}/api/v1/developer/bills/variations`,
{
params: {
serviceID
},
headers: {
'Authorization': `Bearer ${this.secretKey}`
}
}
);
return response.data;
} catch (error) {
console.error('Error getting bill variations:', error.response?.data || error.message);
throw error;
}
}
async verifyBillAccount(serviceID, billersCode, phone, type = null) {
try {
const requestBody = {
serviceID,
billersCode,
phone
};
// Add type field if provided (required for utility and JAMB services)
if (type) {
requestBody.type = type;
}
const response = await axios.post(
`${this.baseUrl}/api/v1/developer/bills/verify`,
requestBody,
{
headers: {
'Authorization': `Bearer ${this.secretKey}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
} catch (error) {
console.error('Error verifying bill account:', error.response?.data || error.message);
throw error;
}
}
async purchaseBillPayment(fromWallet, serviceID, options = {}) {
try {
const response = await axios.post(
`${this.baseUrl}/api/v1/developer/bills/purchase`,
{
fromWallet,
serviceID,
amount: options.amount,
variation_code: options.variation_code,
billersCode: options.billersCode,
phone: options.phone,
subscription_type: options.subscription_type,
quantity: options.quantity,
narration: options.narration,
reference: options.reference
},
{
headers: {
'Authorization': `Bearer ${this.secretKey}`,
'Content-Type': 'application/json'
}
}
);
return response.data;
} catch (error) {
console.error('Error purchasing bill payment:', error.response?.data || error.message);
throw error;
}
}
}
// Usage
const api = new InpayBillPaymentAPI('sk_live_your_secret_key_here');
// Get bill categories
const categories = await api.getBillCategories();
// Get services for a category
const services = await api.getBillServices('airtime');
// Get variations for a service
const variations = await api.getBillVariations('mtn-data');
// Verify bill account examples:
// TV Subscription (type is optional, can be omitted)
const tvVerification = await api.verifyBillAccount('dstv', '1234567890', '08012345678');
// Utility/Electricity - Prepaid (type is required)
const prepaidVerification = await api.verifyBillAccount('ikeja-electric', '12345678901', '08012345678', 'prepaid');
// Utility/Electricity - Postpaid (type is required)
const postpaidVerification = await api.verifyBillAccount('ikeja-electric', '12345678901', '08012345678', 'postpaid');
// JAMB (type is required - use variation code from getVariationCodes)
// First, get JAMB variations to find the correct type
const jambVariations = await api.getBillVariations('jamb');
// Then use the variation code as the type
const jambVerification = await api.verifyBillAccount('jamb', '12345678901', '08012345678', 'jamb-pin-2024');
// Purchase airtime (10000 kobo = ₦100.00)
const airtimePurchase = await api.purchaseBillPayment(
'merchant.wallet.1234567890',
'mtn',
{
amount: 10000,
phone: '08012345678',
narration: 'MTN Airtime purchase',
reference: 'unique-ref-123'
}
);
// Purchase data bundle
const dataPurchase = await api.purchaseBillPayment(
'merchant.wallet.1234567890',
'mtn-data',
{
variation_code: 'mtn-500mb-100',
phone: '08012345678',
narration: 'MTN Data purchase',
reference: 'unique-ref-124'
}
);
// Purchase TV subscription renewal
const tvRenewal = await api.purchaseBillPayment(
'merchant.wallet.1234567890',
'dstv',
{
billersCode: '1234567890',
phone: '08012345678',
subscription_type: 'renewal',
amount: 2500,
quantity: 1,
narration: 'DSTV renewal',
reference: 'unique-ref-125'
}
);
Python with Requests
import requests
class InpayBillPaymentAPI:
def __init__(self, secret_key, base_url='https://api.inpaycheckout.com'):
self.secret_key = secret_key
self.base_url = base_url
self.headers = {
'Authorization': f'Bearer {secret_key}',
'Content-Type': 'application/json'
}
def get_bill_categories(self):
"""Get all bill categories"""
url = f"{self.base_url}/api/v1/developer/bills/categories"
response = requests.get(url, headers=self.headers)
response.raise_for_status()
return response.json()
def get_bill_services(self, category_identifier):
"""Get services for a category"""
url = f"{self.base_url}/api/v1/developer/bills/services"
params = {'categoryIdentifier': category_identifier}
response = requests.get(url, headers=self.headers, params=params)
response.raise_for_status()
return response.json()
def get_bill_variations(self, service_id):
"""Get variations for a service"""
url = f"{self.base_url}/api/v1/developer/bills/variations"
params = {'serviceID': service_id}
response = requests.get(url, headers=self.headers, params=params)
response.raise_for_status()
return response.json()
def verify_bill_account(self, service_id, billers_code, phone, type=None):
"""Verify bill account"""
url = f"{self.base_url}/api/v1/developer/bills/verify"
data = {
'serviceID': service_id,
'billersCode': billers_code,
'phone': phone
}
# Add type field if provided (required for utility and JAMB services)
if type:
data['type'] = type
response = requests.post(url, headers=self.headers, json=data)
response.raise_for_status()
return response.json()
def purchase_bill_payment(self, from_wallet, service_id, **options):
"""Purchase bill payment"""
url = f"{self.base_url}/api/v1/developer/bills/purchase"
data = {
'fromWallet': from_wallet,
'serviceID': service_id,
'amount': options.get('amount'),
'variation_code': options.get('variation_code'),
'billersCode': options.get('billersCode'),
'phone': options.get('phone'),
'subscription_type': options.get('subscription_type'),
'quantity': options.get('quantity'),
'narration': options.get('narration'),
'reference': options.get('reference')
}
response = requests.post(url, headers=self.headers, json=data)
response.raise_for_status()
return response.json()
# Usage
api = InpayBillPaymentAPI('sk_live_your_secret_key_here')
# Get bill categories
categories = api.get_bill_categories()
# Get services for a category
services = api.get_bill_services('airtime')
# Get variations for a service
variations = api.get_bill_variations('mtn-data')
# Verify bill account examples:
# TV Subscription (type is optional, can be omitted)
tv_verification = api.verify_bill_account('dstv', '1234567890', '08012345678')
# Utility/Electricity - Prepaid (type is required)
prepaid_verification = api.verify_bill_account('ikeja-electric', '12345678901', '08012345678', 'prepaid')
# Utility/Electricity - Postpaid (type is required)
postpaid_verification = api.verify_bill_account('ikeja-electric', '12345678901', '08012345678', 'postpaid')
# JAMB (type is required - use variation code from getVariationCodes)
# First, get JAMB variations to find the correct type
jamb_variations = api.get_bill_variations('jamb')
# Then use the variation code as the type
jamb_verification = api.verify_bill_account('jamb', '12345678901', '08012345678', 'jamb-pin-2024')
# Purchase airtime (10000 kobo = ₦100.00)
airtime_purchase = api.purchase_bill_payment(
'merchant.wallet.1234567890',
'mtn',
amount=10000,
phone='08012345678',
narration='MTN Airtime purchase',
reference='unique-ref-123'
)
PHP with cURL
<?php
class InpayBillPaymentAPI {
private $secretKey;
private $baseUrl;
public function __construct($secretKey, $baseUrl = 'https://api.inpaycheckout.com') {
$this->secretKey = $secretKey;
$this->baseUrl = $baseUrl;
}
private function makeRequest($method, $endpoint, $data = null) {
$url = $this->baseUrl . $endpoint;
$headers = [
'Authorization: Bearer ' . $this->secretKey,
'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
if ($data && in_array($method, ['POST', 'PUT', 'PATCH'])) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 400) {
throw new Exception('API Error: ' . $response);
}
return json_decode($response, true);
}
public function getBillCategories() {
return $this->makeRequest('GET', '/api/v1/developer/bills/categories');
}
public function getBillServices($categoryIdentifier) {
$params = http_build_query([
'categoryIdentifier' => $categoryIdentifier
]);
return $this->makeRequest('GET', '/api/v1/developer/bills/services?' . $params);
}
public function getBillVariations($serviceID) {
$params = http_build_query([
'serviceID' => $serviceID
]);
return $this->makeRequest('GET', '/api/v1/developer/bills/variations?' . $params);
}
public function verifyBillAccount($serviceID, $billersCode, $phone, $type = null) {
$data = [
'serviceID' => $serviceID,
'billersCode' => $billersCode,
'phone' => $phone
];
// Add type field if provided (required for utility and JAMB services)
if ($type !== null) {
$data['type'] = $type;
}
return $this->makeRequest('POST', '/api/v1/developer/bills/verify', $data);
}
public function purchaseBillPayment($fromWallet, $serviceID, $options = []) {
$data = [
'fromWallet' => $fromWallet,
'serviceID' => $serviceID,
'amount' => $options['amount'] ?? null,
'variation_code' => $options['variation_code'] ?? null,
'billersCode' => $options['billersCode'] ?? null,
'phone' => $options['phone'] ?? null,
'subscription_type' => $options['subscription_type'] ?? null,
'quantity' => $options['quantity'] ?? null,
'narration' => $options['narration'] ?? null,
'reference' => $options['reference'] ?? null
];
return $this->makeRequest('POST', '/api/v1/developer/bills/purchase', $data);
}
}
// Usage
$api = new InpayBillPaymentAPI('sk_live_your_secret_key_here');
// Get bill categories
$categories = $api->getBillCategories();
// Get services for a category
$services = $api->getBillServices('airtime');
// Get variations for a service
$variations = $api->getBillVariations('mtn-data');
// Verify bill account examples:
// TV Subscription (type is optional, can be omitted)
$tvVerification = $api->verifyBillAccount('dstv', '1234567890', '08012345678');
// Utility/Electricity - Prepaid (type is required)
$prepaidVerification = $api->verifyBillAccount('ikeja-electric', '12345678901', '08012345678', 'prepaid');
// Utility/Electricity - Postpaid (type is required)
$postpaidVerification = $api->verifyBillAccount('ikeja-electric', '12345678901', '08012345678', 'postpaid');
// JAMB (type is required - use variation code from getVariationCodes)
// First, get JAMB variations to find the correct type
$jambVariations = $api->getBillVariations('jamb');
// Then use the variation code as the type
$jambVerification = $api->verifyBillAccount('jamb', '12345678901', '08012345678', 'jamb-pin-2024');
// Purchase airtime (10000 kobo = ₦100.00)
$airtimePurchase = $api->purchaseBillPayment(
'merchant.wallet.1234567890',
'mtn',
[
'amount' => 10000,
'phone' => '08012345678',
'narration' => 'MTN Airtime purchase',
'reference' => 'unique-ref-123'
]
);
?>
Best Practices
- Always verify accounts before purchasing TV subscriptions, utility bills, or JAMB services
- Include the
typefield when verifying utility/electricity accounts ("prepaid"or"postpaid") and JAMB services (use variation code fromgetVariationCodes) - Check wallet balance before initiating bill payments
- Handle errors gracefully - failed transactions are recorded for manual review
- Use unique references for each transaction to track payments
- Store transaction IDs for reconciliation and support purposes
- Monitor webhooks to track bill payment status in real-time
- Validate amounts - ensure amounts meet minimum requirements (₦50 for airtime/data, ₦1,000 for others)
- Respect rate limits - API has rate limits to ensure service stability