Airtime
Purchase airtime for any Nigerian network.
Endpoints
All API requests must be made over HTTPS to: https://app.kdadatasub.name.ng
Supported Providers
KDA currently supports instant airtime vending across all major Nigerian networks via VTU and Share & Sell channels.
MTN
Provider ID: kds-airtime-mtn
Airtel
Provider ID: kds-airtime-airtel
GLO
Provider ID: kds-airtime-glo
T2
Provider ID: kds-airtime-t2mobile
VITEL
Provider ID: kds-airtime-vitel
(v1 only — VTU)
Supported Channels
- VTU → Virtual Top-Up: standard airtime vending at a discount.
- Share & Sell → Transfer airtime credit from one line to another.
Fetch Plans
curl -X GET https://app.kdadatasub.name.ng/api/services/airtime/plans \
-H "Authorization: Bearer kds_test_YOUR_API_KEY"{
"success": true,
"count": 12,
"data": [
{
"id": "kds-airtime-mtn-vtu-v2",
"name": "MTN",
"airtimeType": "VTU",
"salePercentage": "3"
},
{
"id": "kds-airtime-glo-vtu-v1",
"name": "GLO",
"airtimeType": "VTU",
"salePercentage": "4"
}
]
}Fetching without any filter returns all plans. Pass ?id=<planId> to fetch a single plan.
Fetch a single provider by its id:
curl -X GET "https://app.kdadatasub.name.ng/api/services/airtime/plans?id=kds-airtime-mtn-vtu-v2" \
-H "Authorization: Bearer kds_test_YOUR_API_KEY"The salePercentage indicates the discount applied to the face value. For example, "3" means purchasing ₦100 airtime will actually only deduct ₦97 from your wallet.
Top-up limits depend on the plan version. Each route enforces its own minimum and maximum top-up amount:
- v1 (
kds-airtime-*-v1, BILAL): minimum ₦50, maximum ₦500 - v2 (
kds-airtime-*-v2, ALRAHUZ): minimum ₦100, maximum ₦10,000
Sending an amount below the route minimum is rejected by the provider — the transaction is refunded automatically and the response includes a clear error message. See Plan Versions for the full breakdown.
Anatomy of an Airtime Plan
Each plan object represents a provider channel combination:
{
"id": "kds-airtime-mtn-vtu-v2",
"name": "MTN",
"airtimeType": "VTU",
"salePercentage": "1.5"
}Prop
Type
Purchase Flow
Validate Phone Number
Before purchasing, validate the phone number client-side to confirm which network it belongs to. This helps prevent sending airtime to the wrong provider.
See Network Prefixes for the full list of prefixes and a client-side validation snippet.
Purchase Request
Request Body
Prop
Type
Example
curl -X POST https://app.kdadatasub.name.ng/api/services/airtime \
-H "Authorization: Bearer kds_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"planId": "kds-airtime-mtn-vtu-v2",
"number": "08012345678",
"amount": 100,
"idempotencyKey": "681227cc-2638-49fe-bbe3-d2500cf54767",
"isPorted": false
}'const response = await fetch("https://app.kdadatasub.name.ng/api/services/airtime", {
method: "POST",
headers: {
"Authorization": "Bearer kds_test_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
planId: "kds-airtime-mtn-vtu-v2",
number: "08012345678",
amount: 100,
idempotencyKey: crypto.randomUUID(),
isPorted: false
})
});
const data = await response.json();import requests
import uuid
response = requests.post(
"https://app.kdadatasub.name.ng/api/services/airtime",
headers={
"Authorization": "Bearer kds_test_YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"planId": "kds-airtime-mtn-vtu-v2",
"number": "08012345678",
"amount": 100,
"idempotencyKey": str(uuid.uuid4()),
"isPorted": False,
},
)
data = response.json()<?php
$ch = curl_init("https://app.kdadatasub.name.ng/api/services/airtime");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer kds_test_YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"planId" => "kds-airtime-mtn-vtu-v2",
"number" => "08012345678",
"amount" => 100,
"idempotencyKey" => bin2hex(random_bytes(16)),
"isPorted" => false,
]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data);Success Response
{
"success": true,
"message": "Airtime Purchase purchase successful!",
"transactionId": "KDS-AIR-HCKXV8TF-SN",
"data": {
"amount": 98.5,
"faceAmount": 100,
"planId": "kds-airtime-mtn-vtu-v1",
"provider": "MTN",
"number": "08101886979",
"status": "SUCCESS",
"description": "Airtime Purchase purchase successful!",
"transactionId": "KDS-AIR-HCKXV8TF-SN",
"createdAt": "2026-06-17T10:54:51.202Z",
"discountRate": "1.50",
"type": "AIRTIME",
"idempotencyKey": "fbb3ae62-72c9-4383-afd3-85b9fa136119"
}
}Best Practices & Next Steps
Safe Retries with Idempotency: Always attach a unique idempotencyKey (UUID v4) to your request body. If your connection drops or times out, you can safely resubmit the exact same request without risk of debiting your wallet twice.
Discounted billing: amount is what was actually debited from the wallet (face value minus the provider discountRate), while faceAmount is the airtime value delivered to the phone. The provider always delivers the full face value.
Handling Pending Statuses: While most purchases complete in under 3 seconds, vendor delays can occasionally leave a transaction in a PENDING state. Do not retry with a new idempotency key. Instead, listen for real-time status updates via Webhooks.
Related Resources
Webhooks Integration
Set up real-time notifications via the Purchase webhook category (PURCHASE_SUCCESS / PURCHASE_FAILED payloads).
Error Handling & Codes
Review full error code definitions, HTTP status codes, and recovery procedures.
Idempotency Guide
Learn how KDA Turbo prevents duplicate transactions on network timeouts.