Skip to main content

Bill Payments

Coming Soon

Bill payments are currently available as API-only through OneEngineClient. A dedicated widget and React hooks are under development and will ship in a future release. The API is stable and production-ready.

The bill payments API lets your users pay utility bills, purchase airtime, settle subscriptions, and handle other recurring payments directly from their crypto wallets. The ONE SDK (@one_deploy/sdk v1.1.0) handles provider discovery, account validation, payment execution, and history tracking.

Bill Payment Flow

  1. Discover          2. Select           3. Validate          4. Pay
providers --> provider & --> account --> and confirm
by country / enter account number
category number

API Methods

getBillProviders

Discover bill payment providers filtered by country and/or category.

import { OneEngineClient } from '@one_deploy/sdk';

const engine = new OneEngineClient({
apiKey: 'YOUR_API_KEY',
projectId: 'YOUR_PROJECT_ID',
});

// All providers in Nigeria
const providers: BillProvider[] = await engine.getBillProviders('NG');

// Filter by category
const electricityProviders = await engine.getBillProviders('NG', 'electricity');
const airtimeProviders = await engine.getBillProviders('NG', 'airtime');

console.log(electricityProviders);
// [
// {
// providerId: 'bp_ng_ekedc',
// name: 'Eko Electricity (EKEDC)',
// country: 'NG',
// category: 'electricity',
// currency: 'NGN',
// minAmount: 1000,
// maxAmount: 500000,
// requiredFields: ['meterNumber', 'meterType'],
// logo: 'https://assets.one23.io/bills/ekedc.png',
// },
// {
// providerId: 'bp_ng_ikedc',
// name: 'Ikeja Electric (IKEDC)',
// country: 'NG',
// category: 'electricity',
// currency: 'NGN',
// minAmount: 1000,
// maxAmount: 500000,
// requiredFields: ['meterNumber', 'meterType'],
// logo: 'https://assets.one23.io/bills/ikedc.png',
// },
// ]
// Get all available categories (omit both parameters)
const allProviders = await engine.getBillProviders();
const categories = [...new Set(allProviders.map((p) => p.category))];
console.log(categories);
// ['electricity', 'airtime', 'data', 'water', 'cable_tv', 'internet', 'education']

validateBillAccount

Validate an account number with a provider before submitting payment. Returns the account holder name for user confirmation.

const validation = await engine.validateBillAccount(
'bp_ng_ekedc', // providerId
'45678901234' // accountNumber (meter number)
);

console.log(validation);
// {
// valid: true,
// accountName: 'ALICE ADEYEMI',
// accountNumber: '45678901234',
// providerId: 'bp_ng_ekedc',
// metadata: {
// meterType: 'prepaid',
// address: '12 Example Street, Lagos',
// },
// }
// Handle invalid accounts
const invalid = await engine.validateBillAccount('bp_ng_ekedc', '00000000000');

if (!invalid.valid) {
console.error('Invalid account number');
}

payBill

Execute a bill payment. Crypto is debited from the user's wallet and the bill is settled with the provider.

const payment: BillPayment = await engine.payBill({
providerId: 'bp_ng_ekedc',
accountNumber: '45678901234',
amount: 10000,
currency: 'NGN',
walletAddress: '0xAbc...',
chainId: 137,
payWithToken: 'USDT',
fields: {
meterNumber: '45678901234',
meterType: 'prepaid',
},
metadata: { userId: 'user_42' },
});

console.log(payment);
// {
// paymentId: 'bill_xyz789',
// status: 'completed',
// providerId: 'bp_ng_ekedc',
// providerName: 'Eko Electricity (EKEDC)',
// accountNumber: '45678901234',
// amount: 10000,
// currency: 'NGN',
// cryptoAmount: '6.25',
// cryptoCurrency: 'USDT',
// txHash: '0xdef...',
// receipt: {
// token: 'ELEC-8765-4321-0987',
// units: '45.2 kWh',
// },
// createdAt: '2026-02-02T12:00:00Z',
// }

getBillHistory

Retrieve past bill payments with optional filtering and pagination.

// Recent 20 payments
const history = await engine.getBillHistory();

// With filters
const filtered = await engine.getBillHistory({
walletAddress: '0xAbc...',
category: 'electricity',
status: 'completed',
limit: 50,
offset: 0,
fromDate: '2026-01-01T00:00:00Z',
toDate: '2026-02-02T23:59:59Z',
});

console.log(filtered);
// {
// payments: [ { paymentId: 'bill_xyz789', ... }, ... ],
// total: 12,
// limit: 50,
// offset: 0,
// }

Types

interface BillProvider {
/** Unique provider identifier */
providerId: string;
/** Human-readable provider name */
name: string;
/** ISO 3166-1 alpha-2 country code */
country: string;
/** Bill category */
category: BillCategory;
/** Currency accepted by the provider */
currency: string;
/** Minimum payment amount */
minAmount: number;
/** Maximum payment amount */
maxAmount: number;
/** Fields required for this provider (besides accountNumber) */
requiredFields: string[];
/** Provider logo URL */
logo?: string;
}

type BillCategory =
| 'electricity'
| 'airtime'
| 'data'
| 'water'
| 'cable_tv'
| 'internet'
| 'education'
| 'insurance'
| 'government'
| 'other';

interface BillValidation {
/** Whether the account number is valid */
valid: boolean;
/** Account holder name (for user confirmation) */
accountName?: string;
/** Echoed account number */
accountNumber: string;
/** Provider ID */
providerId: string;
/** Additional metadata from the provider */
metadata?: Record<string, string>;
/** Error message if invalid */
error?: string;
}

interface BillPaymentParams {
/** Provider to pay */
providerId: string;
/** Account / meter / subscriber number */
accountNumber: string;
/** Amount in provider's fiat currency */
amount: number;
/** Fiat currency code */
currency: string;
/** Wallet address to debit */
walletAddress: string;
/** Chain ID of the wallet */
chainId: number;
/** Token to pay with (debited from wallet and converted) */
payWithToken: string;
/** Provider-specific fields (meterType, packageCode, etc.) */
fields?: Record<string, string>;
/** Arbitrary metadata */
metadata?: Record<string, string>;
}

interface BillPayment {
/** Unique payment identifier */
paymentId: string;
/** Payment status */
status: PaymentStatus;
/** Provider ID */
providerId: string;
/** Provider display name */
providerName: string;
/** Bill category */
category: BillCategory;
/** Account number paid */
accountNumber: string;
/** Fiat amount paid */
amount: number;
/** Fiat currency */
currency: string;
/** Crypto amount debited from wallet */
cryptoAmount: string;
/** Crypto token used */
cryptoCurrency: string;
/** On-chain transaction hash */
txHash?: string;
/** Provider receipt (token, units, etc.) */
receipt?: Record<string, string>;
/** ISO 8601 creation timestamp */
createdAt: string;
}

interface BillHistoryOptions {
/** Filter by wallet address */
walletAddress?: string;
/** Filter by bill category */
category?: BillCategory;
/** Filter by payment status */
status?: PaymentStatus;
/** Max results to return */
limit?: number;
/** Offset for pagination */
offset?: number;
/** Start date (ISO 8601) */
fromDate?: string;
/** End date (ISO 8601) */
toDate?: string;
}

interface BillHistoryResult {
/** List of bill payments */
payments: BillPayment[];
/** Total matching payments */
total: number;
/** Current limit */
limit: number;
/** Current offset */
offset: number;
}

type PaymentStatus =
| 'pending'
| 'processing'
| 'completed'
| 'failed'
| 'expired'
| 'refunded';

Full Example: Pay Electricity Bill

import { OneEngineClient } from '@one_deploy/sdk';

const engine = new OneEngineClient({
apiKey: process.env.ONE_API_KEY!,
projectId: process.env.ONE_PROJECT_ID!,
});

async function payElectricityBill(
wallet: string,
meterNumber: string,
amountNGN: number
) {
// 1. Find electricity providers in Nigeria
const providers = await engine.getBillProviders('NG', 'electricity');
console.log(`Found ${providers.length} electricity providers`);

// Use the first provider
const provider = providers[0];
console.log(`Using: ${provider.name}`);

// 2. Validate the meter number
const validation = await engine.validateBillAccount(
provider.providerId,
meterNumber
);

if (!validation.valid) {
throw new Error(`Invalid meter number: ${validation.error}`);
}

console.log(`Account holder: ${validation.accountName}`);
console.log(`Meter type: ${validation.metadata?.meterType}`);

// 3. Pay the bill
const payment = await engine.payBill({
providerId: provider.providerId,
accountNumber: meterNumber,
amount: amountNGN,
currency: 'NGN',
walletAddress: wallet,
chainId: 137,
payWithToken: 'USDT',
fields: {
meterNumber,
meterType: validation.metadata?.meterType ?? 'prepaid',
},
});

if (payment.status === 'completed') {
console.log('Payment successful!');
console.log(`Debited: ${payment.cryptoAmount} USDT`);
console.log(`Token: ${payment.receipt?.token}`);
console.log(`Units: ${payment.receipt?.units}`);
} else {
console.log(`Payment status: ${payment.status}`);
}

return payment;
}

// Pay 10,000 NGN electricity bill
await payElectricityBill('0xAbc...', '45678901234', 10000);

Full Example: Buy Airtime

async function buyAirtime(
wallet: string,
phoneNumber: string,
amountNGN: number
) {
// 1. Find airtime providers
const providers = await engine.getBillProviders('NG', 'airtime');
const mtn = providers.find((p) => p.name.includes('MTN'));
if (!mtn) throw new Error('MTN provider not found');

// 2. Validate (for airtime, this checks the phone number)
const validation = await engine.validateBillAccount(
mtn.providerId,
phoneNumber
);

if (!validation.valid) {
throw new Error(`Invalid phone number: ${validation.error}`);
}

// 3. Pay
const payment = await engine.payBill({
providerId: mtn.providerId,
accountNumber: phoneNumber,
amount: amountNGN,
currency: 'NGN',
walletAddress: wallet,
chainId: 137,
payWithToken: 'USDT',
});

console.log(`Airtime top-up: ${payment.status}`);
console.log(`Debited: ${payment.cryptoAmount} USDT`);
return payment;
}

See Also