KDA API Logo
API Docs
Services

Electricity

Generate prepaid meter tokens for Nigerian DisCos.

Endpoints

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.
AEDC

Abuja Electricity

Slug: AEDC
Provider IDs: kds-elec-aedc-v1, kds-elec-aedc-v2

BEDC

Benin Electricity

Slug: BEDC
Provider IDs: kds-elec-bedc-v2

EKEDC

Eko Electricity

Slug: EKEDC
Provider IDs: kds-elec-ekedc-v1, kds-elec-ekedc-v2

EEDC

Enugu Electricity

Slug: EEDC
Provider IDs: kds-elec-eedc-v1, kds-elec-eedc-v2

IBEDC

Ibadan Electricity

Slug: IBEDC
Provider IDs: kds-elec-ibedc-v1, kds-elec-ibedc-v2

IKEDC

Ikeja Electricity

Slug: IKEDC
Provider IDs: kds-elec-ikedc-v1, kds-elec-ikedc-v2

JEDC

Jos Electricity

Slug: JEDC
Provider IDs: kds-elec-jedc-v1, kds-elec-jedc-v2

KAEDCO

Kaduna Electricity

Slug: KAEDCO
Provider IDs: kds-elec-kaedco-v1, kds-elec-kaedco-v2

KEDCO

Kano Electricity

Slug: KEDCO
Provider IDs: kds-elec-kedco-v1, kds-elec-kedco-v2

PHED

Port Harcourt Electricity

Slug: PHED
Provider IDs: kds-elec-phed-v1, kds-elec-phed-v2

YEDC

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.