Skip to content
HitchPay API Docs

BILLS PAYMENT

Buy Airtime

Top up a phone number with airtime on any supported network.

POST /v1/bills/airtime

Use this endpoint to

  • Purchase airtime for any phone number on a supported network
  • Charge the business NGN wallet for amounts between NGN 50 and NGN 20,000
  • Safely retry a purchase without double-charging, using reference

Request

Body parameters

Field Type Required Description
network string Yes Biller slug from Get Billers (e.g. MTN)
phone string Yes Recipient phone number
amount number Yes NGN 50–20,000
reference string Yes Your unique idempotency key for this purchase

Code Samples

const response = await fetch("https://sandbox.hitchpay.ng/v1/bills/airtime", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    network: "MTN",
    phone: "08012345678",
    amount: 500,
    reference: "order-airtime-001"
  })
});

const data = await response.json();
console.log(data);
<?php

$ch = curl_init();

curl_setopt_array($ch, [
  CURLOPT_URL => "https://sandbox.hitchpay.ng/v1/bills/airtime",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => json_encode([
    "network" => "MTN",
    "phone" => "08012345678",
    "amount" => 500,
    "reference" => "order-airtime-001"
  ]),
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer YOUR_ACCESS_TOKEN",
    "Content-Type: application/json"
  ]
]);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
import requests

url = "https://sandbox.hitchpay.ng/v1/bills/airtime"
headers = {
    "Authorization": "Bearer YOUR_ACCESS_TOKEN",
    "Content-Type": "application/json"
}
payload = {
    "network": "MTN",
    "phone": "08012345678",
    "amount": 500,
    "reference": "order-airtime-001"
}

response = requests.post(url, json=payload, headers=headers)
print(response.json())

Response

Success

{
  "status": "success",
  "message": "Bill payment successful.",
  "data": {
    "reference": "HTCHB…",
    "merchant_reference": "order-airtime-001",
    "product": "airtime",
    "provider": "MTN",
    "amount": 500,
    "fee": 0,
    "amount_charged": 500,
    "recipient": "08012345678",
    "currency": "NGN",
    "balance": 12450.75,
    "paid_at": "2026-07-02T10:15:00.000Z"
  }
}

Pending

{
  "status": "success",
  "message": "Bill payment is processing",
  "data": {
    "reference": "HTCHB…",
    "merchant_reference": "order-airtime-001",
    "product": "airtime",
    "provider": "MTN",
    "amount": 500,
    "recipient": "08012345678",
    "currency": "NGN"
  }
}

If you get a pending response, poll Get Transaction Status or listen for the bill.success / bill.failed webhook to get the final state.

Fields

Field Type Description
reference string Our transaction id — use this for status polling
merchant_reference string Echoes the reference you sent
product string airtime
provider string Network the airtime was sent to
amount number Amount requested
fee number Fee charged, if any
amount_charged number Total debited from your wallet (amount + fee)
recipient string Phone number credited
currency string NGN
balance number Your wallet balance after this transaction
paid_at string ISO 8601 timestamp

Errors

Code Meaning
INVALID_REQUEST Missing/invalid fields, or amount outside NGN 50–20,000
UNAUTHORIZED Business not found or inactive
PRODUCT_UNAVAILABLE No matching network configured
INSUFFICIENT_BALANCE Wallet balance too low
BILL_FAILED Provider declined the purchase — wallet is auto-refunded
PROVIDER_ERROR Provider call failed

Idempotent by design: retrying this request with the same reference will never double-charge — you'll get the original transaction back instead.

Questions? Email [email protected]. Also on GitBook.