Skip to content

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/node

Requires 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)
});
OptionTypeDefaultDescription
baseUrlstringhttps://api.zevpaycheckout.comAPI base URL
timeoutnumber30000Request timeout in ms
maxRetriesnumber2Max 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 charges

Get wallet balance

typescript
const balance = await zevpay.transfers.getBalance();
console.log(balance.availableBalance); // Balance in kobo

Invoices

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 classStatusWhen
ZevPayValidationError400Invalid request parameters
ZevPayAuthenticationError401Invalid or missing API key
ZevPayPermissionError403Insufficient permissions
ZevPayNotFoundError404Resource not found
ZevPayConflictError409Duplicate resource
ZevPayRateLimitError429Too many requests
ZevPayApiError500+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

ZevPay Checkout Developer Documentation