npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

monnify-nodejs-lib

v3.0.0

Published

A Node.js wrapper for the Monnify API

Readme

Monnify Node.js Library

CI codecov npm version Node.js License: ISC

A Node.js wrapper for the Monnify API, giving you clean, validated access to every Monnify service — collections, disbursements, invoices, direct debit, bills payment, and more — without having to hand-craft HTTP requests yourself.


Table of Contents


Requirements

  • Node.js 18 or higher
  • A Monnify account — get your API key and secret from the Monnify dashboard

Installation

npm install monnify-nodejs-lib

Setup & Credentials

You need three things from your Monnify dashboard:

| Variable | Where to find it | |---|---| | MONNIFY_ENV | SANDBOX for testing, LIVE for production | | MONNIFY_APIKEY | Dashboard → Settings → API Keys | | MONNIFY_SECRET | Dashboard → Settings → API Keys | | CONTRACT | Dashboard → Settings → Contract Code |

The recommended approach is a .env file so credentials never appear in source code:

# .env
MONNIFY_ENV=SANDBOX
MONNIFY_APIKEY=MK_TEST_XXXXXXXXXX
MONNIFY_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
CONTRACT=1234567890
WALLETACCOUNTNUMBER=0123456789   # only needed for disbursement wallet balance

The library reads MONNIFY_ENV automatically — no need to pass it to any constructor. It will also detect if your API key prefix does not match your declared environment (e.g. a MK_PROD_ key with MONNIFY_ENV=SANDBOX) and throw a clear error.

Then load it at the top of your app:

import dotenv from 'dotenv';
dotenv.config();

⚠️ Add .env to your .gitignore. Never commit credentials to source control.


How Authentication Works

Every Monnify API call needs a bearer token. The library handles token fetching and caching automatically — you just call getToken() once and pass the result to each method.

import { Transaction } from 'monnify-nodejs-lib';

const api = new Transaction();

const [statusCode, token] = await api.getToken();
// token is the raw bearer string — pass it to every method call below

The token is cached in memory and reused until it expires, so calling getToken() multiple times is cheap.

The environment is read from MONNIFY_ENV in your environment variables. All instances in the same process must use the same environment.


Modules at a Glance

import {
  MonnifyAPI,           // single entry point — all modules in one object
  Transaction,          // individual import — useful for tree-shaking
  ReservedAccount,
  SubAccount,
  Invoice,
  Settlement,
  Disbursement,
  TransactionRefund,
  Wallet,
  LimitProfile,
  DirectDebit,
  Verification,
  BillsPayment
} from 'monnify-nodejs-lib';

Using the unified MonnifyAPI class:

import { MonnifyAPI } from 'monnify-nodejs-lib';

const monnify = new MonnifyAPI({
  MONNIFY_APIKEY: process.env.MONNIFY_APIKEY,
  MONNIFY_SECRET: process.env.MONNIFY_SECRET,
});

const [, token] = await monnify.getToken();

// Access every module through the same instance
await monnify.transaction.initTransaction(token, payload);
await monnify.reservedAccount.createReservedAccount(token, payload);
await monnify.disbursement.initiateSingleTransfer(token, payload);
// ...and so on

Reserved Accounts

A reserved account is a dedicated virtual bank account assigned to a specific customer. Any transfer made to it is automatically matched to that customer.

import { ReservedAccount } from 'monnify-nodejs-lib';

const api = new ReservedAccount();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | createReservedAccount(token, data) | Create a permanent virtual account for a customer | | createInvoiceReservedAccount(token, data) | Create a one-time virtual account tied to an invoice | | addLinkedAccounts(token, data) | Add preferred banks to an existing reserved account | | reservedAccountDetails(token, data) | Retrieve details of a reserved account | | reservedAccountTransactions(token, data) | List transactions received on a reserved account | | updateReservedAccountKycInfo(token, data) | Update BVN / NIN on a reserved account | | updateReservedAccountBvn(token, data) | Update just the BVN | | updatePaymentSources(token, data) | Restrict which payment sources are accepted | | updateIncomeSplitConfig(token, data) | Update how incoming funds are split across sub-accounts | | deallocateReservedAccount(token, data) | Permanently delete a reserved account |

Example

import crypto from 'crypto';

const [statusCode, response] = await api.createReservedAccount(token, {
  customerName:    'Ada Obi',
  customerEmail:   '[email protected]',
  accountName:     'Ada Obi',
  accountReference: crypto.randomBytes(16).toString('hex'), // your unique ref
  contractCode:    process.env.CONTRACT,
  bvn:             '22222222222',
  currencyCode:    'NGN',
  paymentMethods:  ['ACCOUNT_TRANSFER']
});

console.log(response.responseBody.accountNumber); // the virtual account number

Transactions

Manage the full payment lifecycle — from initialising a checkout to charging a card or generating a bank transfer.

import { Transaction } from 'monnify-nodejs-lib';

const api = new Transaction();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | initTransaction(token, data) | Start a new payment — returns a transactionReference | | getTransactionStatusv2(token, data) | Check status by transactionReference (recommended) | | getTransactionStatusv1(token, data) | Check status by paymentReference (your own reference) | | getAllTransactions(token, filters?) | Search / list transactions with optional filters | | payWithBankTransfer(token, data) | Generate a one-time bank account for an existing transaction | | payWithUssd(token, data) | Generate a USSD string for an existing transaction | | chargeCard(token, data) | Charge a card directly (requires transactionReference) | | authorizeOtp(token, data) | Submit the OTP for a card charge that requires one | | ThreeDsSecureAuthTransaction(token, data) | Complete a 3DS card authentication | | cardTokenization(token, data) | Charge a previously saved card token |

from / to date filters — pass Unix timestamps in milliseconds (not ISO strings).

const to   = Date.now();
const from = to - 7 * 24 * 60 * 60 * 1000; // 7 days ago
const [, resp] = await api.getAllTransactions(token, { from, to, page: 0, size: 20 });

Example — Basic Payment Flow

import crypto from 'crypto';

// 1. Initialise the transaction
const [, initResp] = await api.initTransaction(token, {
  customerName:       'Emeka Dike',
  customerEmail:      '[email protected]',
  amount:             5000,           // in Naira
  paymentDescription: 'Order #1042',
  paymentReference:   crypto.randomBytes(16).toString('hex'),
  contractCode:       process.env.CONTRACT,
  currencyCode:       'NGN',
  paymentMethods:     ['CARD', 'ACCOUNT_TRANSFER'],
  redirectUrl:        'https://yourapp.com/payment/callback'
});

const { transactionReference, paymentReference, checkoutUrl } = initResp.responseBody;
// Redirect your customer to checkoutUrl, or continue with one of the methods below

// 2a. Pay via bank transfer
const [, transferResp] = await api.payWithBankTransfer(token, {
  transactionReference,
  bankCode: '058' // optional — generates USSD string for this bank
});

// 2b. OR charge a card directly
const [, cardResp] = await api.chargeCard(token, {
  transactionReference,
  card: {
    number:      '4111111111111111',
    expiryMonth: '10',
    expiryYear:  '2025',
    pin:         '1234',
    cvv:         '123'
  },
  deviceInformation: {
    httpBrowserLanguage:          'en-US',
    httpBrowserJavaEnabled:       false,
    httpBrowserJavaScriptEnabled: true,
    httpBrowserColorDepth:        24,
    httpBrowserScreenHeight:      1203,
    httpBrowserScreenWidth:       2138,
    httpBrowserTimeDifference:    '',
    userAgentBrowserValue:        'Mozilla/5.0 ...'
  }
});

// 3. Check the outcome
const [, statusResp] = await api.getTransactionStatusv2(token, { transactionReference });
console.log(statusResp.responseBody.paymentStatus); // 'PAID', 'PENDING', etc.

Recurring Payments — Card Tokenisation

After a successful first charge, Monnify returns a cardToken in the transaction status response. Save it alongside the customer email and use it for all future charges — no card details needed again.

// After a successful chargeCard call, query the status:
const [, statusResp] = await api.getTransactionStatusv2(token, { transactionReference });
const cardToken    = statusResp.responseBody.cardToken;    // e.g. "MNFY_0CD0138B..."
const customerEmail = '[email protected]';                  // same email used in initTransaction

// Save cardToken + customerEmail in your database, then for future charges:
const [, recurringResp] = await api.cardTokenization(token, {
  cardToken,
  customerEmail,
  customerName:       'Emeka Dike',
  amount:             5000,
  paymentReference:   crypto.randomBytes(16).toString('hex'),
  paymentDescription: 'Monthly subscription',
  contractCode:       process.env.CONTRACT,
  currencyCode:       'NGN',
  apiKey:             process.env.MONNIFY_APIKEY
});

Sub Accounts

Split incoming payments automatically across multiple bank accounts.

import { SubAccount } from 'monnify-nodejs-lib';

const api = new SubAccount();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | createSubAccount(token, data) | Create a new sub-account | | getSubAccounts(token) | List all sub-accounts | | updateSubAccount(token, data) | Update a sub-account | | deleteSubAccount(token, data) | Remove a sub-account |

Example

const [statusCode, response] = await api.createSubAccount(token, [{
  currencyCode:           'NGN',
  bankCode:               '058',
  accountNumber:          '2085086393',
  email:                  '[email protected]',
  defaultSplitPercentage: 20   // this account gets 20% of every payment
}]);

Invoices

Create payment invoices with an expiry date and track their status.

import { Invoice } from 'monnify-nodejs-lib';

const api = new Invoice();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | createInvoice(token, data) | Create a new invoice | | viewInvoiceDetails(token, data) | Get details of a specific invoice | | getAllInvoices(token, data?) | List all invoices with pagination | | cancelInvoice(token, data) | Cancel an unpaid invoice |

Example

import crypto from 'crypto';

const [statusCode, response] = await api.createInvoice(token, {
  amount:           10000,
  invoiceReference: crypto.randomBytes(16).toString('hex'),
  description:      'Consulting fee - May 2026',
  contractCode:     process.env.CONTRACT,
  customerName:     'Bola Tinubu Ltd',
  customerEmail:    '[email protected]',
  paymentMethods:   ['CARD', 'ACCOUNT_TRANSFER'],
  currencyCode:     'NGN'
});

console.log(response.responseBody.invoiceLink); // share this link with your customer

Settlements

Query how funds from transactions have been settled to your bank account.

import { Settlement } from 'monnify-nodejs-lib';

const api = new Settlement();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | getTransactionsBySettlementReference(token, data) | List all transactions in a settlement batch | | getSettlementInfo(token, data) | Get settlement details for a specific transaction |

Example

// Find all transactions in a settlement batch
const [, response] = await api.getTransactionsBySettlementReference(token, {
  reference: 'MSP_20260101_001'
});

// Or look up the settlement for one transaction
const [, info] = await api.getSettlementInfo(token, {
  transactionReference: 'MNFY|24|20260115120000|000001'
});

Disbursements

Send money out of your Monnify wallet — single transfers, bulk transfers, and everything in between.

import { Disbursement } from 'monnify-nodejs-lib';

const api = new Disbursement();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | initiateSingleTransfer(token, data) | Send money to one bank account | | initiateBulkTransfer(token, data) | Send money to many accounts in one request | | authorizeSingleTransfer(token, data) | Authorise a single transfer (OTP step) | | authorizeBulkTransfer(token, data) | Authorise a bulk transfer (OTP step) | | resendTransferOTP(token, data) | Resend the OTP for a single transfer | | resendBulkTransferOTP(token, data) | Resend the OTP for a bulk transfer | | getSingleTransferStatus(token, data) | Check the status of a single transfer | | getBulkTransferStatus(token, data) | Check the summary of a bulk batch | | getBulkBatchSummary(token, data) | Alias for getBulkTransferStatus | | getBulkTransferTransactions(token, data) | List individual transactions within a bulk batch | | getAllSingleTransfers(token, data?) | Paginated list of all single transfers | | getAllBulkTransfers(token, data?) | Paginated list of all bulk transfers | | searchDisbursementTransactions(token, data) | Search disbursement transactions with filters |

Example

import crypto from 'crypto';

const [statusCode, response] = await api.initiateSingleTransfer(token, {
  sourceAccountNumber:      process.env.WALLETACCOUNTNUMBER,
  destinationBankCode:      '058',
  destinationAccountNumber: '2085086393',
  destinationAccountName:   'John Doe',
  amount:                   5000,
  currencyCode:             'NGN',
  narration:                'Freelancer payment - May 2026',
  reference:                crypto.randomBytes(16).toString('hex')
});

Refunds

Reverse a payment back to the customer's original payment method.

import { TransactionRefund } from 'monnify-nodejs-lib';

const api = new TransactionRefund();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | initiateRefund(token, data) | Start a refund for a completed transaction | | getAllRefunds(token, data?) | List all refunds | | getRefundStatus(token, data) | Check the status of a specific refund |

Example

import crypto from 'crypto';

const [statusCode, response] = await api.initiateRefund(token, {
  transactionReference:      'MNFY|24|20260115120000|000001',
  refundReference:           crypto.randomBytes(16).toString('hex'),
  refundReason:              'Customer requested cancellation',
  refundAmount:              5000,
  customerNote:              'Your refund is on the way',
  destinationAccountNumber:  '2085086393',
  destinationAccountBankCode: '058'
});

Wallet

Check the available balance in your Monnify disbursement wallet.

import { Wallet } from 'monnify-nodejs-lib';

const api = new Wallet();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | getWalletBalance(token, data) | Get available and ledger balance for a wallet account |

Example

const [statusCode, response] = await api.getWalletBalance(token, {
  accountNumber: process.env.WALLETACCOUNTNUMBER
});

const { availableBalance, ledgerBalance } = response.responseBody;
console.log(`Available: ₦${availableBalance}`);

Limit Profiles

Create and manage transaction limit profiles, then attach them to reserved accounts for spending controls.

import { LimitProfile } from 'monnify-nodejs-lib';

const api = new LimitProfile();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | createLimitProfile(token, data) | Create a new limit profile | | getLimitProfiles(token) | List all limit profiles on your account | | updateLimitProfile(token, data) | Update an existing limit profile | | reserveAccountWithLimit(token, data) | Create a reserved account with a limit profile attached | | updateReserveAccountLimit(token, data) | Change the limit profile on an existing reserved account |

Example

// Create a profile that caps daily spending at ₦500,000
const [, profileResp] = await api.createLimitProfile(token, {
  limitProfileName:       'Retail Customer Limit',
  singleTransactionValue: 100000,   // max per transaction: ₦100,000
  dailyTransactionVolume: 10,       // max 10 transactions per day
  dailyTransactionValue:  500000    // max ₦500,000 per day
});

const limitProfileCode = profileResp.responseBody.limitProfileCode;

Direct Debit

Set up recurring debit mandates — charge a customer's bank account on a schedule without them needing to be present for each payment.

import { DirectDebit } from 'monnify-nodejs-lib';

const api = new DirectDebit();
const [, token] = await api.getToken();

Note: Direct Debit requires regulatory approval from Monnify. Contact your account manager to get it enabled.

Methods

| Method | Description | |---|---| | createMandate(token, data) | Create a new debit mandate | | getMandateStatus(token, data) | Check the status of a mandate | | debitMandate(token, data) | Trigger a debit against an active mandate | | getDebitStatus(token, data) | Check the outcome of a debit attempt | | cancelMandate(token, data) | Cancel an active mandate |

Example

import crypto from 'crypto';

// 1. Create the mandate
const [, mandateResp] = await api.createMandate(token, {
  contractCode:            process.env.CONTRACT,
  mandateReference:        crypto.randomBytes(12).toString('hex'),
  mandateDescription:      'Monthly gym subscription',
  mandateStartDate:        '2026-01-01T00:00:00',
  mandateEndDate:          '2026-12-31T23:59:59',
  customerName:            'Ngozi Eze',
  customerEmailAddress:    '[email protected]',
  customerPhoneNumber:     '08011223344',
  customerAddress:         '12 Adeola Odeku, Victoria Island, Lagos',
  customerAccountNumber:   '2085086393',
  customerAccountBankCode: '058',
  mandateAmount:           120000,    // total lifetime cap
  autoRenew:               false,
  customerCancellation:    true,
  redirectUrl:             'https://yourapp.com/direct-debit/callback'
});

// 2. Once approved, debit the mandate
const [, debitResp] = await api.debitMandate(token, {
  mandateCode:      mandateResp.responseBody.mandateCode,
  debitAmount:      10000,
  paymentReference: crypto.randomBytes(12).toString('hex'),
  narration:        'May 2026 subscription',
  customerEmail:    '[email protected]'
});

Bills Payment

Pay utility bills, buy airtime, subscribe to cable TV, and more. The flow always goes in the same order:

getBillerCategories()            → pick a category (e.g. "CABLE_TV")
  └─ listBillers({ categoryCode }) → pick a biller (e.g. "DSTV")
       └─ getBillerProducts({ billerCode }) → pick a product / plan
            └─ validateCustomer({ productCode, customerId }) → validate the customer
                 └─ vendBill({ productCode, customerId, amount, reference })
                      └─ requeryBillPayment({ reference }) → confirm outcome if needed
import { BillsPayment } from 'monnify-nodejs-lib';

const api = new BillsPayment();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | getBillerCategories(token, data?) | List all biller categories (Airtime, Cable TV, Electricity, etc.) | | listBillers(token, data?) | List billers, optionally filtered by categoryCode | | getBillerProducts(token, data) | List products / plans for a specific biller | | validateCustomer(token, data) | Validate a customer's identifier before paying | | vendBill(token, data) | Actually pay the bill | | requeryBillPayment(token, data) | Re-check the outcome of a bill payment |

Example — End-to-End Bill Payment

import crypto from 'crypto';

// 1. Find categories
const [, categoriesResp] = await api.getBillerCategories(token);
// e.g. categories: [{ categoryCode: 'CABLE_TV', categoryName: 'Cable TV' }, ...]

// 2. Find billers in a category
const [, billersResp] = await api.listBillers(token, { categoryCode: 'CABLE_TV' });
const { billerCode } = billersResp.responseBody.content[0];

// 3. Find products for the biller
const [, productsResp] = await api.getBillerProducts(token, { billerCode });
const { productCode, amount } = productsResp.responseBody.content[0];

// 4. Validate the customer's smart card number
const [, validateResp] = await api.validateCustomer(token, {
  productCode,
  customerId: '1234567890'  // e.g. DSTV smart card number
});

const validationReference = validateResp.responseBody?.vendInstruction?.requireValidationRef
  ? validateResp.responseBody.vendInstruction.validationReference
  : undefined;

// 5. Pay the bill
const reference = crypto.randomBytes(16).toString('hex');

const [statusCode, vendResp] = await api.vendBill(token, {
  productCode,
  customerId:  '1234567890',
  amount,
  reference,
  validationReference,  // include only if step 4 said it was required
  emailAddress: '[email protected]'
});

// 6. If the outcome was unclear, requery
if (statusCode !== 200) {
  const [, requery] = await api.requeryBillPayment(token, { reference });
  console.log(requery.responseBody);
}

Verification (Value-Added Services)

Validate bank accounts and verify customer identity documents.

import { Verification } from 'monnify-nodejs-lib';

const api = new Verification();
const [, token] = await api.getToken();

Methods

| Method | Description | |---|---| | validateBankAccount(token, data) | Confirm that an account number belongs to the expected name | | verifyBvnInformation(token, data) | Retrieve BVN holder details | | matchBvnAndAccountName(token, data) | Check that a BVN and bank account belong to the same person | | verifyNin(token, data) | Retrieve NIN holder details |

Example

// Verify a bank account before sending money
const [statusCode, response] = await api.validateBankAccount(token, {
  accountNumber: '2085086393',
  bankCode:      '058'
});

console.log(response.responseBody.accountName); // the registered account name

// Verify NIN
const [, ninResp] = await api.verifyNin(token, { nin: '12345678901' });

Error Handling

Every method returns a two-element array: [httpStatusCode, responseBody]. Check the status code before reading the body.

const [statusCode, response] = await api.initiateSingleTransfer(token, payload);

if (statusCode === 200) {
  console.log('Transfer successful:', response.responseBody);
} else {
  console.error(`Transfer failed (${statusCode}):`, response);
}

If you pass an invalid or incomplete payload, the library throws a validation error before making any network request:

try {
  await api.createMandate(token, { mandateReference: 'REF001' }); // missing required fields
} catch (err) {
  console.error(err.message); // "mandateDescription" is required ...
}

Running the Tests

Clone the repo and install dependencies:

git clone https://github.com/Monnify/Monnify-Nodejs-lib.git
cd Monnify-Nodejs-lib
npm install

Export your sandbox credentials, then run the full test suite:

export MONNIFY_APIKEY=MK_TEST_XXXXXXXXXX
export MONNIFY_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
export CONTRACT=1234567890
export WALLETACCOUNTNUMBER=0123456789

npm test

The suite runs 71 tests across all 11 modules. All tests target the Monnify sandbox — no real money moves.


Contributing

Contributions are welcome. Please open a pull request with a clear description of your changes. All PRs must:

  • Pass npm test with no failures
  • Follow the existing pattern: class extends BaseRequestAPI, Joi validators in /validators/, tests in /tests/
  • Target the dev branch, not main