Developer API

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.

Base URL: https://api.hasrinpay.com/api/merchant/v1REST APIJSON

Authentication

All API requests must include a Bearer token in the Authorization header. You have two key types: sandbox and live.

Sandbox Key
hpk_test_xxxxxxxxxxxxxxxxxxxxxxxx

Transactions are simulated. No real money moves.

Live Key
hpk_live_xxxxxxxxxxxxxxxxxxxxxxxx

Real transactions. Requires approved live access.

bash
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
// 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
<?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.

GET/data/networksList supported networks
GET/data/plansList all data plans (filter by ?network=mtn)
POST/data/purchasePurchase a data plan
GET/airtime/networksList networks that support airtime
POST/airtime/purchaseTop up airtime

Purchase Data — Request

ParameterTypeRequiredDescription
networkstringYesNetwork code: mtn, airtel, glo, 9mobile
phonestringYesRecipient phone number (11 digits)
plan_idstringYesPlan ID from GET /data/plans
referencestringNoYour unique transaction reference (auto-generated if omitted)
json
// 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

ParameterTypeRequiredDescription
networkstringYesNetwork code: mtn, airtel, glo, 9mobile
phonestringYesRecipient phone number
amountintegerYesAmount in Naira (min: 50, max: 50000)
referencestringNoYour unique transaction reference

Bill Payments

Pay electricity bills, cable TV subscriptions, and exam registration fees.

GET/bills/electricity/providersList electricity distribution companies
POST/bills/electricity/verifyVerify meter number before payment
POST/bills/electricity/payPay electricity bill (prepaid/postpaid)
GET/bills/cable/providersList cable TV providers (DSTV, GOtv, Startimes)
GET/bills/cable/plansList bouquets (filter by ?provider=dstv)
POST/bills/cable/verifyVerify smartcard/IUC number
POST/bills/cable/paySubscribe cable TV
GET/bills/education/providersList exam bodies (WAEC, NECO, JAMB)
POST/bills/education/payPurchase exam scratch card / pin
json
// 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.

GET/esim/packagesList eSIM packages (filter by ?country=NG or ?region=africa)
POST/esim/purchasePurchase eSIM package for a customer
GET/esim/ordersList your eSIM orders
GET/esim/orders/:idGet eSIM order details + QR code / installation code
json
// 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.

GET/virtual-cardsList cards created under your platform
POST/virtual-cards/createCreate a new virtual card for a customer
GET/virtual-cards/:idGet card details + balance
POST/virtual-cards/:id/fundFund a card (deducted from API wallet)
POST/virtual-cards/:id/freezeFreeze card (block transactions)
POST/virtual-cards/:id/unfreezeUnfreeze card
POST/virtual-cards/:id/terminatePermanently terminate card
json
// 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.

GET/walletGet wallet balance and funding account details
GET/wallet/transactionsWallet transaction history (paginated)
json
// 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.

json
// 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

EventTrigger
transaction.successA purchase completed successfully
transaction.failedA purchase failed
wallet.fundedWallet credited via bank transfer
card.status_changedVirtual card frozen, unfrozen, or terminated
esim.activatedeSIM 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

CodeMeaning
200Success
201Created (new resource)
400Bad request — validation error or missing field
401Unauthorized — invalid or missing API key
403Forbidden — service not approved for your key
404Resource not found
422Unprocessable — e.g. insufficient wallet balance
429Rate limit exceeded
500Internal server error — contact support
json
// 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.