Skip to main content

AIRTIME API

This section outlines the structure and requirements for purchasing airtime via the API. The API enables seamless top-ups to one or more mobile numbers in a single request. All transactions are asynchronous, with per-recipient status updates delivered via callbacks or status queries.

Endpoints

MethodEndpointDescription
POST/v1/gw/airtime/sendSubmit airtime request
POST/v1/authGet access token
GET/v1/gw/airtime/{reference}/statusQuery status of all recipients

Authentication

All requests require an access token obtained via the authentication endpoint.

Endpoint

POST /v1/auth

Request

{
"consumer_key": "<your_consumer_key>",
"consumer_secret": "<your_consumer_secret>"
}

Example

curl -X POST https://sandbox.api.gateway.lipad.io/v1/auth \
-H "Content-Type: application/json" \
-d '{"consumer_key": "your_key", "consumer_secret": "your_secret"}'

Success Response

{
"access_token": "xyz789abc123",
"expiresIn": 3600
}

Token expires in 1 hour. Re-authenticate when needed.

Airtime Request

Send airtime to one or more phone numbers in a single request.

Endpoint

POST /v1/gw/airtime/send

Request Payload

{
"reference": "467777774564563453",
"recipients": [
{
"phone_number": "254XXXXXXXXXXX",
"amount": "10"
}
]
}

Fields

FieldTypeRequiredDescription
referenceStringYesUnique request ID (e.g., UUID). Must be unique per request.
recipientsArrayYesList of recipients (1–1000).
phone_numberStringYesE.164 format (e.g., 2547...)
amountStringYesAmount in local currency (e.g., "10" for KES 10)

Use string for amount to avoid precision issues.

Example Request

curl -X POST https://sandbox.api.gateway.lipad.io/v1/gw/airtime/send \
-H "Content-Type: application/json" \
-H "x-access-token: xyz789abc123" \
-d '{
"reference": "da091c64-07d6-4a7c-9a9f-e0134869166c",
"recipients": [
{ "phone_number": "254711000000", "amount": "10" },
{ "phone_number": "254722000000", "amount": "50" }
]
}'

Airtime Response

Success (Accepted)

{
"reference": "da091c64-07d6-4a7c-9a9f-e0134869166c",
"response_code": 720,
"response_description": "Airtime request has been accepted for processing"
}

Common Errors

CodeDescription
721Validation Failed

Callback Handling

The API sends one POST callback per recipient to your configured callback_url (set in the merchant portal).

Callback Payload (per recipient)

{
"phone_number": "2547XXXXXXXXXXXX",
"amount": 10,
"service_status": 602,
"external_reference": "da091c64-07d6-4a7c-9a9f-e0134869166c",
"provider_reference": "2611175",
"correlation_id": "GHCRODJAPX6I",
"message": "Airtime request processed successfully"
}

Fields

FieldTypeDescription
phone_numberStringRecipient number
amountNumberAmount sent
service_statusNumberSee codes below
external_referenceStringYour original reference
provider_referenceStringNetwork transaction ID
correlation_idStringInternal ID
messageStringResult description

Service Status Codes

CodeNameDescription
600UNPROCESSEDNot started
601PROCESSINGIn progress
602SUCCESSFULAirtime delivered
603FAILEDFailed (check message)
604JAMMEDStuck at provider
605REVERSEDReversed
606REFUNDEDFunds returned
607SUBMITTED_FOR_REPROCESSINGWill retry

Always respond with 200 OK to acknowledge callback and prevent retries.

Idempotency Key: external_reference + phone_number

Status Query

Check the status of all recipients in a request.

Endpoint

GET /v1/gw/airtime/{reference}/status

Example

curl -X GET https://sandbox.api.gateway.lipad.io/v1/gw/airtime/da091c64-07d6-4a7c-9a9f-e0134869166c/status \
-H "x-access-token: xyz789abc123"

Response (Array)

[
{
"phone_number": "254718192689",
"amount": 10,
"service_status": 602,
"external_reference": "da091c64-07d6-4a7c-9a9f-e0134869166c",
"provider_reference": "2611175",
"correlation_id": "GHCRODJAPX6I",
"message": "Airtime request processed successfully"
},
{
"phone_number": "254722000000",
"amount": 50,
"service_status": 603,
"external_reference": "da091c64-07d6-4a7c-9a9f-e0134869166c",
"provider_reference": null,
"correlation_id": "ABC123XYZ",
"message": "Invalid phone number"
}
]

Returns same structure as callbacks. Poll until all statuses are final.

Quick Integration Checklist

StepAction
1Get consumer_key & consumer_secret from Merchant Portal > My Business > API Keys
2Call /v1/auth → get access_token
3Generate unique reference (UUID)
4POST to /v1/gw/airtime/send
5Save reference
6Set up public callback_url in portal
7Handle callbacks → return 200 OK
8(Optional) Poll status endpoint

Best Practices

  • Phone Format: Always use E.164 (254..., not 07...)
  • Idempotency: Deduplicate using reference
  • Bulk Limit: Max 1000 recipients per request
  • Retry Logic: Re-query if status is 601 or 604
  • Sandbox Testing: Use any valid phone number`

Example: Full Flow (Node.js)

const axios = require("axios");
const API = "https://sandbox.api.gateway.lipad.io";
let token = "";

async function auth() {
const res = await axios.post(`${API}/v1/auth`, {
consumer_key: "your_key",
consumer_secret: "your_secret",
});
token = res.data.access_token;
}

async function sendAirtime() {
await auth();
const res = await axios.post(
`${API}/v1/gw/airtime/send`,
{
reference: "da091c64-07d6-4a7c-9a9f-e0134869166c",
recipients: [{ phone_number: "2547XXXXXXXXX", amount: "10" }],
},
{
headers: { "x-access-token": token },
}
);
console.log("Submitted:", res.data);
}

async function checkStatus(ref) {
await auth();
const res = await axios.get(`${API}/v1/gw/airtime/${ref}/status`, {
headers: { "x-access-token": token },
});
console.log("Status:", res.data);
}

You're ready to disburse airtime at scale.