API Reference
Build apps on top of your VTU platform. The HasrinPay Merchant API gives you programmatic access to data, airtime, bills, eSIM, virtual cards, and more.
Authentication
All API requests must include a Bearer token in the Authorization header. You have two key types: sandbox and live.
hpk_test_xxxxxxxxxxxxxxxxxxxxxxxxTransactions are simulated. No real money moves.
hpk_live_xxxxxxxxxxxxxxxxxxxxxxxxReal transactions. Requires approved live access.
curl -X POST https://api.hasrinpay.com/api/merchant/v1/data/purchase \
-H "Authorization: Bearer hpk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"network": "mtn", "phone": "08012345678", "plan_id": "mtn-1gb-30days"}'// JavaScript / Node.js
const response = await fetch("https://api.hasrinpay.com/api/merchant/v1/data/purchase", {
method: "POST",
headers: {
"Authorization": "Bearer hpk_live_xxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
network: "mtn",
phone: "08012345678",
plan_id: "mtn-1gb-30days",
}),
})
const data = await response.json()
console.log(data)<?php
$ch = curl_init("https://api.hasrinpay.com/api/merchant/v1/data/purchase");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer hpk_live_xxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"network" => "mtn",
"phone" => "08012345678",
"plan_id" => "mtn-1gb-30days",
]),
]);
$response = json_decode(curl_exec($ch), true);Data & Airtime
Purchase data plans and airtime for MTN, Airtel, Glo, and 9mobile numbers.
/data/networksList supported networks/data/plansList all data plans (filter by ?network=mtn)/data/purchasePurchase a data plan/airtime/networksList networks that support airtime/airtime/purchaseTop up airtimePurchase Data — Request
| Parameter | Type | Required | Description |
|---|---|---|---|
network | string | Yes | Network code: mtn, airtel, glo, 9mobile |
phone | string | Yes | Recipient phone number (11 digits) |
plan_id | string | Yes | Plan ID from GET /data/plans |
reference | string | No | Your unique transaction reference (auto-generated if omitted) |
// POST /data/purchase — Response
{
"status": "success",
"message": "Data purchase successful",
"data": {
"reference": "TXN-20260829-ABC123",
"network": "mtn",
"phone": "08012345678",
"plan": "1GB — 30 Days",
"amount": 300,
"wallet_balance_after": 4700
}
}Purchase Airtime — Request
| Parameter | Type | Required | Description |
|---|---|---|---|
network | string | Yes | Network code: mtn, airtel, glo, 9mobile |
phone | string | Yes | Recipient phone number |
amount | integer | Yes | Amount in Naira (min: 50, max: 50000) |
reference | string | No | Your unique transaction reference |
Bill Payments
Pay electricity bills, cable TV subscriptions, and exam registration fees.
/bills/electricity/providersList electricity distribution companies/bills/electricity/verifyVerify meter number before payment/bills/electricity/payPay electricity bill (prepaid/postpaid)/bills/cable/providersList cable TV providers (DSTV, GOtv, Startimes)/bills/cable/plansList bouquets (filter by ?provider=dstv)/bills/cable/verifyVerify smartcard/IUC number/bills/cable/paySubscribe cable TV/bills/education/providersList exam bodies (WAEC, NECO, JAMB)/bills/education/payPurchase exam scratch card / pin// POST /bills/electricity/pay — Request body
{
"provider": "EKEDC",
"meter_number": "12345678901",
"meter_type": "prepaid",
"amount": 5000,
"phone": "08012345678"
}
// Response
{
"status": "success",
"data": {
"reference": "TXN-20260829-DEF456",
"token": "1234-5678-9012-3456-7890",
"units": "28.75 kWh",
"amount": 5000
}
}eSIM
Sell international eSIM data packages. Powered by Airalo — coverage in 190+ countries.
/esim/packagesList eSIM packages (filter by ?country=NG or ?region=africa)/esim/purchasePurchase eSIM package for a customer/esim/ordersList your eSIM orders/esim/orders/:idGet eSIM order details + QR code / installation code// GET /esim/packages?country=NG — Response (excerpt)
{
"status": "success",
"data": [
{
"id": "airalo-ng-1gb-7d",
"name": "Nigeria 1GB — 7 Days",
"country": "Nigeria",
"data_amount": "1 GB",
"validity": "7 days",
"price": 1500
}
]
}
// POST /esim/purchase — Request
{
"package_id": "airalo-ng-1gb-7d",
"customer_email": "[email protected]"
}
// Response
{
"status": "success",
"data": {
"order_id": "ESIM-001",
"iccid": "8923100012341234561",
"qr_code_url": "https://...",
"activation_code": "LPA:1$...",
"status": "active"
}
}Virtual Cards
Issue USD virtual cards for your customers. Powered by Sudo Africa. Requires Virtual Cards service approval.
/virtual-cardsList cards created under your platform/virtual-cards/createCreate a new virtual card for a customer/virtual-cards/:idGet card details + balance/virtual-cards/:id/fundFund a card (deducted from API wallet)/virtual-cards/:id/freezeFreeze card (block transactions)/virtual-cards/:id/unfreezeUnfreeze card/virtual-cards/:id/terminatePermanently terminate card// POST /virtual-cards/create — Request
{
"customer_name": "John Doe",
"customer_email": "[email protected]",
"currency": "USD",
"amount": 10
}
// Response
{
"status": "success",
"data": {
"card_id": "VC-12345",
"card_number": "4111 **** **** 1234",
"expiry": "12/28",
"cvv": "***",
"balance": 10.00,
"status": "active"
}
}Merchant Wallet
All API transactions are charged from your merchant wallet. Fund it via bank transfer.
/walletGet wallet balance and funding account details/wallet/transactionsWallet transaction history (paginated)// GET /wallet — Response
{
"status": "success",
"data": {
"balance": 45200.00,
"currency": "NGN",
"funding_account": {
"bank_name": "Moniepoint",
"account_number": "1234567890",
"account_name": "HasrinPay / YourPlatform"
}
}
}Funding
Transfer to the funding account shown above. Your wallet is credited automatically within 1–5 minutes after the bank confirms the transfer. Minimum funding: ₦1,000.
Webhooks
Receive real-time notifications when transactions complete, wallets are funded, or cards change status.
Configure your webhook URL from the Developer API section of your admin panel. We sign all payloads with HMAC-SHA256 using your webhook secret.
// Webhook payload — transaction.success
{
"event": "transaction.success",
"timestamp": "2026-08-29T10:30:00Z",
"data": {
"reference": "TXN-20260829-ABC123",
"type": "data",
"amount": 300,
"status": "success",
"phone": "08012345678",
"network": "mtn",
"plan": "1GB — 30 Days"
}
}
// Webhook payload — wallet.funded
{
"event": "wallet.funded",
"timestamp": "2026-08-29T10:35:00Z",
"data": {
"amount": 10000,
"balance_after": 55200,
"reference": "FUND-20260829-XYZ789"
}
}Webhook Events
| Event | Trigger |
|---|---|
transaction.success | A purchase completed successfully |
transaction.failed | A purchase failed |
wallet.funded | Wallet credited via bank transfer |
card.status_changed | Virtual card frozen, unfrozen, or terminated |
esim.activated | eSIM order activated by the customer |
Errors & Rate Limits
All errors return a JSON body with status, message, and optionally errors for validation failures.
HTTP Status Codes
| Code | Meaning |
|---|---|
200 | Success |
201 | Created (new resource) |
400 | Bad request — validation error or missing field |
401 | Unauthorized — invalid or missing API key |
403 | Forbidden — service not approved for your key |
404 | Resource not found |
422 | Unprocessable — e.g. insufficient wallet balance |
429 | Rate limit exceeded |
500 | Internal server error — contact support |
// Error response example
{
"status": "error",
"message": "Insufficient wallet balance",
"errors": null
}
// Validation error
{
"status": "error",
"message": "Validation failed",
"errors": {
"phone": ["The phone field is required"],
"amount": ["The amount must be at least 50"]
}
}Rate Limits
Sandbox
120 requests / minute
Per API key
Live
300 requests / minute
Per API key
Need help with the API?
Our developer support team is available Monday–Saturday, 8am–10pm WAT. Include your API key prefix and a request/response sample in your message.