---
title: Electricity
description: Pay electricity bills for all major distribution companies
---

Pay prepaid and postpaid electricity bills for all major Nigerian distribution companies.

## Supported Distributors

| Code    | Name                   | Region        |
| ------- | ---------------------- | ------------- |
| `IKEDC` | Ikeja Electric         | Lagos (Ikeja) |
| `EKEDC` | Eko Electric           | Lagos (Eko)   |
| `AEDC`  | Abuja Electric         | Abuja         |
| `KEDC`  | Kaduna Electric        | Kaduna        |
| `JEDC`  | Jos Electric           | Jos           |
| `IBEDC` | Ibadan Electric        | Ibadan        |
| `KAEDC` | Kano Electric          | Kano          |
| `EEDC`  | Enugu Electric         | Enugu         |
| `PhED`  | Port Harcourt Electric | Port Harcourt |
| `BEDC`  | Benin Electric         | Benin         |
| `ABA`   | Aba Power              | Aba           |
| `YEDC`  | Yola Electric          | Yola          |

## Purchase Flow

Electricity purchases require a **two-step process**:

1. **Verify** - Validate the meter number and get customer details
2. **Purchase** - Make the payment

This prevents payments to invalid meters.

## Step 1: List Products

```bash
curl -X GET \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  "https://my.rizpay.app/api/partners/v1/products/electricity?distributor=IKEDC"
```

Response:

```json
{
  "status": { "code": 200, "message": "Success" },
  "data": [
    {
      "id": "prd_8152",
      "type": "electricity",
      "attributes": {
        "display_name": "Ikeja Electric Payment - IKEDC",
        "distributor": "Ikeja Electric Payment - IKEDC",
        "meter_type": null,
        "min_amount": "100.0",
        "max_amount": "100000.0",
        "price": {
          "currency": "NGN",
          "basis": "face_value",
          "min_amount": "100.00",
          "max_amount": "100000.00"
        }
      }
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total_pages": 1,
    "total_count": 12
  }
}
```

Product ids are numeric with a `prd_` prefix (e.g. `prd_8152`). There is
one product per distribution company. `meter_type` on the product is
`null`: you supply the meter type (`prepaid` or `postpaid`) on the
purchase request, and verify returns the meter type it detected.

### The `price` block

Electricity is variable: the partner chooses the amount. RizPay returns
the supported range as a `face_value` tuple. You'll be billed exactly the
amount you submit on the purchase request.

## Step 2: Verify Meter

**Required before purchase.** Validates the meter and returns customer details.

```bash
curl -X POST \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "prd_8152",
    "meter_number": "12345678901",
    "meter_type": "prepaid"
  }' \
  https://my.rizpay.app/api/partners/v1/purchases/verify
```

Response:

```json
{
  "status": { "code": 200, "message": "Verification successful" },
  "data": {
    "verified": true,
    "product_id": "prd_8152",
    "product_type": "electricity",
    "price": {
      "currency": "NGN",
      "basis": "face_value",
      "min_amount": "100.00",
      "max_amount": "100000.00"
    },
    "customer": {
      "meter_number": "12345678901",
      "meter_type": "prepaid",
      "customer_name": "JOHN DOE",
      "address": "123 Main Street, Ikeja, Lagos",
      "distributor": "Ikeja Electric Payment - IKEDC"
    }
  }
}
```

The `price` block on verify gives you the supported amount range for the
verified meter so you can prompt your end-user before submitting the
purchase.

### Verification Errors

If the meter number cannot be validated, verify returns a `400` with
`error.code` set to `VALIDATION_ERROR` and a message describing the
problem. If the distributor itself is unavailable, purchases for that
product return `PRODUCT_UNAVAILABLE`.

| Error                 | Meaning                            |
| --------------------- | ---------------------------------- |
| `VALIDATION_ERROR`    | Meter number could not be verified |
| `PRODUCT_UNAVAILABLE` | Distributor service is down        |

## Step 3: Make Purchase

After verification, make the purchase. Include the `meter_type`
(`prepaid` or `postpaid`) you verified:

```bash
curl -X POST \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "prd_8152",
    "meter_number": "12345678901",
    "meter_type": "prepaid",
    "amount": "5000.00",
    "phone_number": "08012345678",
    "external_reference": "1736234400D4E5F6"
  }' \
  https://my.rizpay.app/api/partners/v1/purchases
```

Response:

```json
{
  "status": { "code": 201, "message": "Purchase created successfully" },
  "data": {
    "id": "txn_abc123",
    "type": "transaction",
    "attributes": {
      "amount": "5000.0",
      "currency": "NGN",
      "status": "pending",
      "category": "purchase",
      "description": "Purchase of IKEDC Electricity",
      "reference": "elec0order0001abcd",
      "external_reference": "1736234400D4E5F6",
      "product_type": "electricity",
      "phone_number": "08012345678",
      "meter_number": "12345678901",
      "price": {
        "product_amount": "5000.00",
        "fee_amount": "0.00",
        "total_debit": "5000.00",
        "currency": "NGN",
        "basis": "face_value"
      },
      "created_at": "2026-05-18T10:30:00+01:00",
      "updated_at": "2026-05-18T10:30:00+01:00"
    }
  }
}
```

### The `price` breakdown

Same shape as airtime. `basis` is `face_value` because the partner picked
the amount.

## Successful Purchase

Poll the transaction (or use webhooks) until `status` reaches
`successful`. The completed purchase uses the same nested shape as the
create response. For a prepaid meter the recharge `token` appears inside
`data.attributes.token`:

```json
{
  "status": { "code": 200, "message": "Purchase details retrieved" },
  "data": {
    "id": "txn_abc123",
    "type": "transaction",
    "attributes": {
      "amount": "5000.0",
      "currency": "NGN",
      "status": "successful",
      "category": "purchase",
      "description": "Purchase of IKEDC Electricity",
      "reference": "elec0order0001abcd",
      "external_reference": "1736234400D4E5F6",
      "product_type": "electricity",
      "phone_number": "08012345678",
      "meter_number": "12345678901",
      "token": "1234-5678-9012-3456-7890",
      "price": {
        "product_amount": "5000.00",
        "fee_amount": "0.00",
        "total_debit": "5000.00",
        "currency": "NGN",
        "basis": "face_value"
      },
      "created_at": "2026-05-18T10:30:00+01:00",
      "updated_at": "2026-05-18T10:30:05+01:00"
    }
  }
}
```

**Important:** For prepaid meters, provide the `token` to the customer.
They'll enter it into their meter to load the units. The `token` field is
present only once the purchase is successful and only for prepaid meters.
There is no separate completion timestamp: use `updated_at`.

## Complete Example

```javascript
// Generate external reference: 10-digit timestamp + 6 alphanumeric
function generateReference() {
  const timestamp = Math.floor(Date.now() / 1000);
  const chars =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  let suffix = "";
  for (let i = 0; i < 6; i++) {
    suffix += chars.charAt(Math.floor(Math.random() * chars.length));
  }
  return `${timestamp}${suffix}`;
}

async function payElectricity(meterNumber, meterType, amount, phoneNumber) {
  const API_KEY = "sk_live_your_secret_key";
  const BASE_URL = "https://my.rizpay.app/api/partners/v1";

  // Step 1: Find the product (one per distributor)
  const productsRes = await fetch(
    `${BASE_URL}/products/electricity?distributor=IKEDC`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  const products = await productsRes.json();
  const product = products.data[0];

  // Step 2: Verify meter
  const verifyRes = await fetch(`${BASE_URL}/purchases/verify`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      product_id: product.id,
      meter_number: meterNumber,
      meter_type: meterType,
    }),
  });

  const verification = await verifyRes.json();
  if (!verification.data.verified) {
    throw new Error("Invalid meter number");
  }

  // Step 3: Make purchase
  const purchaseRes = await fetch(`${BASE_URL}/purchases`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      product_id: product.id,
      meter_number: meterNumber,
      meter_type: meterType,
      amount: amount,
      phone_number: phoneNumber,
      external_reference: generateReference(),
    }),
  });

  return await purchaseRes.json();
}
```

## Meter Types

| Type       | Description    | Token                        |
| ---------- | -------------- | ---------------------------- |
| `prepaid`  | Pay before use | Yes - customer enters token  |
| `postpaid` | Pay after use  | No - payment credits account |

## Required Scope

Requires the `purchase_electricity` scope on your API key.

## Next Steps

- [Cable TV](/docs/products/cable-tv) - Subscribe to cable TV
- [Webhooks](/docs/webhooks/overview) - Get notified when payment completes