Electricity
Generate prepaid meter tokens for Nigerian DisCos.
Endpoints
Fetch Providers
GET /api/services/electricity/plans
Verify Meter
POST /api/services/verify/meter
Generate Token
POST /api/services/electricity
All API requests must be made over HTTPS to: https://kda-turbo-web.vercel.app
Supported Discos
KDA supports electricity token purchases for all major Nigerian distribution companies (DisCos). Each Disco is accessible via two routes:
-v1-— Backed by the primary infrastructure. All discos available.-v2-— Backed by secondary infrastructure. All discos available.
Abuja Electricity
Slug: AEDC
Provider IDs: kds-elec-aedc-v1, kds-elec-aedc-v2
Benin Electricity
Slug: BEDC
Provider IDs: kds-elec-bedc-v2
Eko Electricity
Slug: EKEDC
Provider IDs: kds-elec-ekedc-v1, kds-elec-ekedc-v2
Enugu Electricity
Slug: EEDC
Provider IDs: kds-elec-eedc-v1, kds-elec-eedc-v2
Ibadan Electricity
Slug: IBEDC
Provider IDs: kds-elec-ibedc-v1, kds-elec-ibedc-v2
Ikeja Electricity
Slug: IKEDC
Provider IDs: kds-elec-ikedc-v1, kds-elec-ikedc-v2
Jos Electricity
Slug: JEDC
Provider IDs: kds-elec-jedc-v1, kds-elec-jedc-v2
Kaduna Electricity
Slug: KAEDCO
Provider IDs: kds-elec-kaedco-v1, kds-elec-kaedco-v2
Kano Electricity
Slug: KEDCO
Provider IDs: kds-elec-kedco-v1, kds-elec-kedco-v2
Port Harcourt Electricity
Slug: PHED
Provider IDs: kds-elec-phed-v1, kds-elec-phed-v2
Yola Electricity
Slug: YEDC
Provider IDs: kds-elec-yedc-v1, kds-elec-yedc-v2
Supported Meter Types
- PREPAID — Pay-as-you-go meters. Requires a meter number and amount.
- POSTPAID — Credit-based meters. Requires a meter number and amount to clear outstanding bills.
Fetch Providers
curl -X GET https://kda-turbo-web.vercel.app/api/services/electricity/plans \
-H "Authorization: Bearer kds_test_YOUR_API_KEY"{
"success": true,
"count": 22,
"data": [
{
"id": "kds-elec-aedc-v1",
"name": "Abuja Electricity",
"saleFee": "5",
"slug": "AEDC"
},
{
"id": "kds-elec-ikedc-v2",
"name": "Ikeja Electricity",
"saleFee": "15",
"slug": "IKEDC"
},
{
"id": "kds-elec-kedco-v1",
"name": "Kano Electricity",
"saleFee": "5",
"slug": "KEDCO"
}
]
}The saleFee indicates the service fee added to the face value. For example, "5" means a ₦5 fee is added to the purchase amount. Fees vary by route — v1 (primary infrastructure) generally has lower fees than v2 (secondary infrastructure), so check both options when fetching plans.
Fetching without any filter returns all plans. Pass ?id=<planId> to fetch a single plan.
Fetch a single Disco by its id:
curl -X GET "https://kda-turbo-web.vercel.app/api/services/electricity/plans?id=kds-elec-kedco-v1" \
-H "Authorization: Bearer kds_test_YOUR_API_KEY"Purchase Flow
Verify Meter
Before generating a token, you can validate a meter number against its DisCo to confirm it is active and retrieve the customer name.
Request Body
Prop
Type
Be sure to select the correct meterType (prepaid vs postpaid) based on the user's meter, as they are separate plan IDs.
Example
curl -X POST https://kda-turbo-web.vercel.app/api/services/verify/meter \
-H "Authorization: Bearer kds_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"discoSlug": "KEDCO",
"meterNumber": "04123456789",
"meterType": "prepaid"
}'const response = await fetch("https://kda-turbo-web.vercel.app/api/services/verify/meter", {
method: "POST",
headers: {
"Authorization": "Bearer kds_test_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
discoSlug: "PHED",
meterNumber: "04123456789",
meterType: "prepaid"
})
});
const data = await response.json();import requests
response = requests.post(
"https://kda-turbo-web.vercel.app/api/services/verify/meter",
headers={
"Authorization": "Bearer kds_test_YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"discoSlug": "IBEDC",
"meterNumber": "04123456789",
"meterType": "prepaid",
},
)
data = response.json()<?php
$ch = curl_init("https://kda-turbo-web.vercel.app/api/services/verify/meter");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer kds_test_YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"discoSlug" => "KEDCO",
"meterNumber" => "04123456789",
"meterType" => "prepaid",
]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data);Success Response
{
"success": true,
"data": {
"valid": true,
"name": "BAT",
"address": "State House, Aso Rock, Abuja"
}
}Returns a normalized valid: true/false and name regardless of the upstream provider. The address field is conditional — it is only included when the upstream provider returns it. Always check for its presence before displaying.
Error Response
{
"success": false,
"error": {
"code": "BAD_REQUEST",
"message": "INVALID METER NUMBER"
}
}Purchase Request
Request Body
Prop
Type
Example
curl -X POST https://kda-turbo-web.vercel.app/api/services/electricity \
-H "Authorization: Bearer kds_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"providerId": "kds-elec-kedco-v1",
"meterNumber": "04123456789",
"amount": 5000,
"meterType": "prepaid",
"idempotencyKey": "681227cc-2638-49fe-bbe3-d2500cf54767"
}'const response = await fetch("https://kda-turbo-web.vercel.app/api/services/electricity", {
method: "POST",
headers: {
"Authorization": "Bearer kds_test_YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
providerId: "kds-elec-kano-prepaid-v1",
meterNumber: "04123456789",
amount: 5000,
meterType: "prepaid",
idempotencyKey: crypto.randomUUID()
})
});
const data = await response.json();import requests
import uuid
response = requests.post(
"https://kda-turbo-web.vercel.app/api/services/electricity",
headers={
"Authorization": "Bearer kds_test_YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"providerId": "kds-elec-kedco-v1",
"meterNumber": "04123456789",
"amount": 5000,
"meterType": "prepaid",
"idempotencyKey": str(uuid.uuid4()),
},
)
data = response.json()<?php
$ch = curl_init("https://kda-turbo-web.vercel.app/api/services/electricity");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer kds_test_YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"providerId" => "kds-elec-kedco-v1",
"meterNumber" => "04123456789",
"amount" => 5000,
"meterType" => "prepaid",
"idempotencyKey" => bin2hex(random_bytes(16)),
]),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
print_r($data);Success Response
The response includes the electricityToken directly in the data object.
{
"success": true,
"message": "Electricity Bill purchase successful!",
"transactionId": "KDS-ELC-B5Q21TGY-SN",
"data": {
"amount": 5000,
"providerId": "kds-elec-kedco-v1",
"provider": "KEDCO",
"meterNumber": "04123456789",
"status": "SUCCESS",
"description": "Electricity Bill purchase successful!",
"transactionId": "KDS-ELC-B5Q21TGY-SN",
"createdAt": "2026-06-17T12:00:00.000Z",
"meterType": "PREPAID",
"fee": 5,
"electricityToken": "1111 2222 3333 4444 5555",
"electricityUnits": "55.6 KWH",
"type": "ELECTRICITY",
"idempotencyKey": "681227cc-2638-49fe-bbe3-d2500cf54767"
}
}electricityUnits is conditional — it is only included when the upstream provider returns it. Always check for its presence before displaying.
Best Practices & Next Steps
Prepaid Token Display: The 20-digit electricityToken is required for prepaid meter customers to manually recharge their meters. Ensure your UI presents this token prominently to the user alongside any available electricityUnits.
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.
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.