Node.js SDK
Official server-side SDK for integrating ZevPay Checkout in Node.js applications. Provides full REST API coverage with TypeScript support.
Installation
bash
npm install @zevpay/nodeRequires Node.js 18 or later.
Quick start
typescript
import ZevPay from '@zevpay/node';
const zevpay = new ZevPay('sk_test_your_secret_key');
// Initialize a checkout session
const session = await zevpay.checkout.initialize({
amount: 500000, // ₦5,000 in kobo
email: 'customer@example.com',
reference: 'ORDER-123',
callbackUrl: 'https://yoursite.com/callback',
});
console.log(session.checkoutUrl);
// → https://secure.zevpaycheckout.com/ses_abc123...Configuration
typescript
const zevpay = new ZevPay('sk_live_xxx', {
baseUrl: 'https://api.zevpaycheckout.com', // default
timeout: 30000, // 30s request timeout (default)
maxRetries: 2, // retries on 5xx errors (default)
});| Option | Type | Default | Description |
|---|---|---|---|
baseUrl | string | https://api.zevpaycheckout.com | API base URL |
timeout | number | 30000 | Request timeout in ms |
maxRetries | number | 2 | Max retries on server errors |
Secret keys only
The SDK only accepts secret keys (sk_live_* or sk_test_*). Public keys cannot be used server-side.
Checkout sessions
Initialize a session
typescript
const session = await zevpay.checkout.initialize({
amount: 500000,
email: 'customer@example.com',
currency: 'NGN',
reference: 'ORDER-123',
callbackUrl: 'https://yoursite.com/callback',
metadata: { orderId: '123' },
paymentMethods: ['bank_transfer', 'payid'],
});
// Redirect your customer to:
console.log(session.checkoutUrl);Verify a payment
typescript
const result = await zevpay.checkout.verify(session.sessionId);
if (result.status === 'completed') {
console.log('Payment confirmed at:', result.paidAt);
}Get session details
typescript
const details = await zevpay.checkout.get('ses_abc123');Transfers
Bank transfer
typescript
const transfer = await zevpay.transfers.create({
type: 'bank_transfer',
amount: 1000000, // ₦10,000
accountNumber: '0123456789',
bankCode: '044',
accountName: 'John Doe',
narration: 'Payout',
reference: 'TXN-123',
});PayID transfer
typescript
const transfer = await zevpay.transfers.create({
type: 'payid',
amount: 500000,
payId: 'johndoe',
narration: 'Payment',
});List transfers
typescript
const transfers = await zevpay.transfers.list({
page: 1,
pageSize: 20,
status: 'completed',
type: 'bank_transfer',
});Verify a transfer
typescript
const result = await zevpay.transfers.verify('TXN-123');List banks
typescript
const banks = await zevpay.transfers.listBanks();
// [{ code: '044', name: 'Access Bank', slug: 'access-bank' }, ...]Resolve bank account
typescript
const account = await zevpay.transfers.resolveAccount({
accountNumber: '0123456789',
bankCode: '044',
});
console.log(account.accountName); // 'JOHN DOE'Calculate fees
typescript
const charges = await zevpay.transfers.calculateCharges({
amount: 1000000,
bankCode: '044',
});
console.log(charges.fee); // Fee in kobo
console.log(charges.total); // Amount + all chargesGet wallet balance
typescript
const balance = await zevpay.transfers.getBalance();
console.log(balance.availableBalance); // Balance in koboInvoices
Create an invoice
typescript
const invoice = await zevpay.invoices.create({
customerName: 'Jane Doe',
customerEmail: 'jane@example.com',
dueDate: '2026-04-01',
lineItems: [
{ description: 'Web Design', quantity: 1, unitPrice: 5000000 },
{ description: 'Hosting (1yr)', quantity: 1, unitPrice: 1200000 },
],
taxRate: 7.5,
note: 'Thank you for your business',
});
// Send to customer:
console.log(invoice.paymentUrl);Send, list, cancel
typescript
// Send invoice (draft → sent)
await zevpay.invoices.send(invoice.publicId);
// List invoices
const invoices = await zevpay.invoices.list({ status: 'sent' });
// Cancel invoice
await zevpay.invoices.cancel(invoice.publicId);Static PayIDs
typescript
// Create
const payid = await zevpay.staticPayId.create({
payId: 'mystore',
suffix: '.spid',
name: 'My Store',
description: 'Accept payments to my store',
});
// List
const payids = await zevpay.staticPayId.list();
// Update
await zevpay.staticPayId.update(payid.id, { name: 'New Name' });
// Deactivate / Reactivate
await zevpay.staticPayId.deactivate(payid.id);
await zevpay.staticPayId.reactivate(payid.id);Dynamic PayIDs
typescript
// Create a time-limited payment link
const dpayid = await zevpay.dynamicPayId.create({
amount: 1000000,
name: 'Donation Drive',
expiresInMinutes: 60,
amountValidation: 'A0',
});
console.log(dpayid.fullPayId); // e.g. 'donation-drive-xyz.dpay'
// List active
const active = await zevpay.dynamicPayId.list({ status: 'active' });
// Deactivate
await zevpay.dynamicPayId.deactivate(dpayid.id);Virtual accounts
typescript
// Create
const va = await zevpay.virtualAccounts.create({
amount: 1000000,
validityMinutes: 60,
});
console.log(va.accountNumber); // Customer pays to this account
// List
const accounts = await zevpay.virtualAccounts.list({ status: 'pending' });Wallet
typescript
// Get wallet details
const wallet = await zevpay.wallet.get();
// List members
const members = await zevpay.wallet.listMembers();
// Add / remove members
await zevpay.wallet.addMember({ payId: 'johndoe' });
await zevpay.wallet.removeMember('johndoe');Webhook verification
Verify incoming webhook signatures using your webhook secret:
typescript
import ZevPay from '@zevpay/node';
app.post('/webhooks/zevpay', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-zevpay-signature'] as string;
try {
const event = ZevPay.webhooks.constructEvent(
req.body,
signature,
process.env.ZEVPAY_WEBHOOK_SECRET!,
);
switch (event.event) {
case 'charge.success':
// Handle successful checkout payment
break;
case 'transfer.success':
// Handle successful transfer
break;
case 'transfer.failed':
// Handle failed transfer
break;
case 'invoice.paid':
// Handle paid invoice
break;
}
res.sendStatus(200);
} catch (err) {
res.status(400).send('Invalid signature');
}
});typescript
const isValid = ZevPay.webhooks.verify(
rawBody,
signature,
webhookSecret,
);Always verify
Never process webhook events without verifying the signature. See Verifying Signatures for details.
Error handling
All API errors throw typed exceptions:
typescript
import ZevPay, {
ZevPayError,
ZevPayValidationError,
ZevPayAuthenticationError,
ZevPayNotFoundError,
ZevPayRateLimitError,
ZevPayConflictError,
} from '@zevpay/node';
try {
await zevpay.transfers.create({ /* ... */ });
} catch (err) {
if (err instanceof ZevPayValidationError) {
// 400 — invalid parameters
console.log(err.code); // e.g. 'VALIDATION_ERROR'
console.log(err.message); // Human-readable message
console.log(err.details); // Field-level errors
} else if (err instanceof ZevPayAuthenticationError) {
// 401 — invalid API key
} else if (err instanceof ZevPayNotFoundError) {
// 404 — resource not found
} else if (err instanceof ZevPayConflictError) {
// 409 — duplicate transaction
} else if (err instanceof ZevPayRateLimitError) {
// 429 — rate limit exceeded
console.log(err.retryAfter); // seconds to wait
}
}| Error class | Status | When |
|---|---|---|
ZevPayValidationError | 400 | Invalid request parameters |
ZevPayAuthenticationError | 401 | Invalid or missing API key |
ZevPayPermissionError | 403 | Insufficient permissions |
ZevPayNotFoundError | 404 | Resource not found |
ZevPayConflictError | 409 | Duplicate resource |
ZevPayRateLimitError | 429 | Too many requests |
ZevPayApiError | 500+ | Server error |
Full example — Express.js
typescript
import express from 'express';
import ZevPay from '@zevpay/node';
const app = express();
const zevpay = new ZevPay(process.env.ZEVPAY_SECRET_KEY!);
// Initialize payment
app.post('/api/pay', express.json(), async (req, res) => {
const session = await zevpay.checkout.initialize({
amount: req.body.amount,
email: req.body.email,
reference: `ORDER-${Date.now()}`,
callbackUrl: `${req.protocol}://${req.get('host')}/api/callback`,
});
res.json({ checkoutUrl: session.checkoutUrl });
});
// Verify after callback
app.get('/api/callback', async (req, res) => {
const sessionId = req.query.session_id as string;
const result = await zevpay.checkout.verify(sessionId);
if (result.status === 'completed') {
res.send('Payment successful!');
} else {
res.send('Payment not completed yet.');
}
});
// Receive webhooks
app.post('/webhooks/zevpay', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = ZevPay.webhooks.constructEvent(
req.body,
req.headers['x-zevpay-signature'] as string,
process.env.ZEVPAY_WEBHOOK_SECRET!,
);
console.log('Webhook received:', event.event, event.data);
res.sendStatus(200);
} catch {
res.status(400).send('Invalid signature');
}
});
app.listen(3000);Resources
- API Reference — Full endpoint documentation
- Webhook Events — All event types
- GitHub — Source code
- npm — Package registry