⚡ Disco Electricity Vending

Purchase prepaid tokens or pay postpaid bills for any supported distribution company meter. Disco vending is its own API collection — no Venshack meter registration is required, and it is separate from Vending (Venshack).

💡 Two vending collections

Use /v1/vending/* for meters registered to your Venshack organization, and /v1/disco-vending/* for any supported DISCO meter. The two collections are independent; nothing in the existing Venshack vending API has changed.

Supported DISCOs

Code Distribution company
IKEJAIkeja Electric
EKOEko Electricity Distribution
ABUJAAEDC
KANOKano Electricity Distribution
PHPort Harcourt Electricity Distribution
JOSJos Electricity Distribution
KADUNAKaduna Electric
ENUGUEnugu Electricity Distribution
IBADANIbadan Electricity Distribution
BENINBenin Electricity Distribution
ABAAba Power
YOLAYola Electricity Distribution

Common utility aliases such as IKEDC, EKEDC, AEDC and PHEDC are accepted and normalized to their canonical codes.

Pricing

Operation Cost
Validate meter Free
Purchase token / pay bill ₦50 flat (under ₦10,000) · 0.5% above
Requery a pending transaction Free
List transactions Free
Query token details Free

How It Works

  1. Validate meter → Confirm the meter and get the customer name
  2. Confirm with user → Show the customer name before purchase
  3. Purchase → Charge your wallet and receive the token, or a pending reference
  4. Requery → If the transaction is pending, requery the reference until it resolves

Step 1: Validate Meter

Always validate first to confirm the meter and show the customer name.

POST /v1/disco-vending/validate
{
  "meterNumber": "1234567890123",
  "disco": "IKEJA",
  "meterCategory": "PREPAID"
}
Response
{
  "success": true,
  "data": {
    "success": true,
    "meterNumber": "1234567890123",
    "customerName": "John Doe",
    "meterType": "PREPAID",
    "disco": "IKEJA",
    "meterCategory": "PREPAID",
    "message": "Meter validated successfully"
  }
}

Step 2: Purchase Token / Pay Bill

Purchase electricity for the validated meter. Costs ₦50 for amounts under ₦10,000, 0.5% above.

POST /v1/disco-vending/purchase
{
  "meterNumber": "1234567890123",
  "amount": 50000,  // Amount in kobo (50000 = ₦500)
  "disco": "IKEJA",
  "meterCategory": "PREPAID",
  "phone": "08012345678",  // Optional but recommended
  "externalRef": "my-order-123"  // Optional - your reference
}
Response (delivered)
{
  "success": true,
  "data": {
    "success": true,
    "token": "1234-5678-9012-3456-7890",
    "units": 25.5,
    "meterNumber": "1234567890123",
    "amount": 50000,
    "reference": "202603231430abc123",
    "customerName": "John Doe",
    "disco": "IKEJA",
    "meterCategory": "PREPAID",
    "message": "Token purchased successfully"
  }
}
⚠️ Pending transactions

DISCO purchases are not always delivered immediately. When the provider is still processing, the response is HTTP 200 with success: false, errorCode: "PENDING" and a reference. Do not retry the purchase with a new reference — requery the existing one instead.

Response (pending)
{
  "success": true,
  "data": {
    "success": false,
    "meterNumber": "1234567890123",
    "amount": 50000,
    "reference": "202603231430abc123",
    "errorCode": "PENDING",
    "disco": "IKEJA",
    "meterCategory": "PREPAID",
    "message": "Transaction is being processed. Use the reference to requery for the final status."
  }
}

Step 3: Requery a Pending Transaction

Pass the reference from the original purchase. Requery is free and safe to call repeatedly.

POST /v1/disco-vending/requery
{
  "reference": "202603231430abc123"
}

The response uses the same shape as a purchase: a delivered transaction returns the token, while a still-processing one returns errorCode: "PENDING" again.

Postpaid Meters

Set meterCategory to POSTPAID to pay a postpaid bill. There is no token for postpaid payments; a successful response returns the payment reference and message: "Payment completed successfully".

Request Fields

Field Required Description
meterNumber Yes 11-13 digit meter number
disco Yes DISCO code (e.g. IKEJA) or a supported alias
meterCategory No PREPAID (default) or POSTPAID
amount Yes (purchase) Amount in kobo (100 kobo = ₦1). Range: 20000-50000000 (₦200-₦500,000)
phone No Customer phone number; recommended
externalRef No Your reference ID for tracking

Sandbox Test Cases

TEST API keys (vk_test_) return deterministic sandbox values and never call a live electricity provider.

Meter number Validate Purchase
00000000001 success: false (INVALID_METER) success: false (INVALID_METER)
00000000002 Valid customer errorCode: "PENDING"
Any other 11-13 digit number Valid customer Token generated

Amounts below 50000 kobo (₦500) fail with MIN_AMOUNT in sandbox. Requery resolves any sandbox PENDING reference successfully. Sandbox requests are free but still appear in your API call logs; webhooks are not sent for TEST calls.

Code Example

Node.js / JavaScript
const API_KEY = 'vk_prod_xxxxxxxxxxxxx';
const BASE_URL = 'https://api-developers.venshack.io/v1';

async function purchaseDiscoElectricity({
  meterNumber,
  amountInKobo,
  disco,          // e.g. 'IKEJA'
  meterCategory,  // 'PREPAID' | 'POSTPAID'
  phone
}) {
  // Step 1: Validate meter
  const validateRes = await fetch(`${BASE_URL}/disco-vending/validate`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ meterNumber, disco, meterCategory })
  });

  const meter = await validateRes.json();

  if (!meter.success) {
    throw new Error(meter.error.message);
  }

  console.log(`Customer: ${meter.data.customerName}`);

  // Step 2: Purchase
  const purchaseRes = await fetch(`${BASE_URL}/disco-vending/purchase`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      meterNumber,
      amount: amountInKobo,
      disco,
      meterCategory,
      ...(phone ? { phone } : {}),
      externalRef: `order-${Date.now()}`
    })
  });

  let result = await purchaseRes.json();

  // Step 3: Pending transactions are resolved by requery
  if (result.data?.errorCode === 'PENDING') {
    const reference = result.data.reference;

    for (let attempt = 0; attempt < 3; attempt++) {
      await new Promise((resolve) => setTimeout(resolve, 2000));

      const requeryRes = await fetch(`${BASE_URL}/disco-vending/requery`, {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${API_KEY}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ reference })
      });

      result = await requeryRes.json();
      if (result.data?.errorCode !== 'PENDING') break;
    }
  }

  if (result.data?.success) {
    console.log(`Token: ${result.data.token}`);
    console.log(`Units: ${result.data.units} kWh`);
    return result.data;
  }

  throw new Error(result.data?.message || result.error?.message);
}

// 50000 kobo = ₦500
purchaseDiscoElectricity({
  meterNumber: '1234567890123',
  amountInKobo: 50000,
  disco: 'IKEJA',
  meterCategory: 'PREPAID',
  phone: '08012345678'
});

Transaction History

List DISCO vending transactions for your organization. Transactions include disco, meterCategory and reference fields.

GET /v1/disco-vending/transactions
GET /v1/disco-vending/transactions?page=1&limit=20&meterNumber=1234567890123

Query Token

POST /v1/disco-vending/query-token
{
  "token": "12345678901234567890"
}

Webhooks

DISCO vending emits the same vending.completed and vending.failed events as Venshack vending, with meterType: "DISCO" plus disco and meterCategory in the payload. Pending transactions do not emit vending.failed; they emit vending.completed once requery confirms delivery. See the Webhooks Guide for how to receive and verify webhook events.

Error Handling

Error Code Description
PENDING Transaction is still processing — requery with the reference
INVALID_METER Meter number not found or invalid
INVALID_DISCO Unsupported or missing disco code
INVALID_AMOUNT Amount is not supported for this meter
INVALID_SERVICE The DISCO service is currently unavailable
PROVIDER_UNAVAILABLE Electricity provider is temporarily unavailable — try again later
DUPLICATE_REQUEST A transaction with this reference already exists
TRANSACTION_NOT_FOUND The reference could not be found
TRANSACTION_FAILED The provider rejected the transaction
TIMEOUT Provider did not respond in time — requery before retrying
NETWORK_ERROR Could not reach the electricity provider
PAYMENT_REQUIRED Insufficient wallet balance
💡 Retries

Never retry a PENDING or TIMEOUT purchase with a new reference — requery the original reference first to avoid double vending.