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

payaza-node-sdk

v0.1.1

Published

Official Node.js SDK for the Payaza API — collect payments and send transfers across Africa.

Readme

payaza-node-sdk

Official Node.js / TypeScript SDK for the Payaza API — collect payments (cards, virtual accounts, mobile money) and send transfers across Africa from your server.

  • Typed end-to-end: every request and response shape ships as a TypeScript type.
  • Works in both require() and import projects (CJS + ESM builds).
  • Handles Payaza's auth scheme for you — pass your raw API key, the SDK base64-encodes it and attaches the right headers per call.
  • Zero runtime dependencies — built on Node's native fetch.

Status: v0.1.0 covers the full Payaza API surface — Accounts (main account, sub-accounts, EUR accounts, virtual accounts, branches), Transfers, Mobile Money/XOF/ZAR Collections, Card Collections, Authorize/Capture/Void, Refunds & Chargebacks, Subscriptions, and Split Settlements. See API coverage below for the full resource list.

Requirements

  • Node.js 18 or later (for native fetch and Web Crypto).
  • A Payaza business account with API keys — see Getting your API keys.

Installation

npm install payaza-node-sdk
yarn add payaza-node-sdk
pnpm add payaza-node-sdk

Getting your API keys

  1. Sign up / log in at business.payaza.africa.
  2. Go to Settings → Developers.
  3. Click Generate Keys. Toggle Test Mode to get a sandbox key, or use live keys once your KYB verification is approved.

Keep your key on the server — never ship it in client-side / mobile code. If a key is ever exposed, regenerate it immediately from the same screen.

Quick start

import { Payaza } from "payaza-node-sdk";

const payaza = new Payaza({
  publicKey: process.env.PAYAZA_PUBLIC_KEY!,
  environment: "test", // "test" while integrating, "live" once you go live
});

const account = await payaza.account.view();
console.log(account.data);
// CommonJS also works out of the box
const { Payaza } = require("payaza-node-sdk");

const payaza = new Payaza({ publicKey: process.env.PAYAZA_PUBLIC_KEY, environment: "test" });

Client options

new Payaza({
  publicKey: "...",      // required — your raw Payaza public key (not pre-encoded)
  environment: "test",   // "test" | "live", defaults to "test". Sent as X-TenantID on endpoints that require it.
  productId: "app",      // sent as X-ProductID, only on the Mobile Money collection endpoints that require it.
  baseUrl: "https://api.payaza.africa/live", // override for testing against a mock server
  timeoutMs: 30_000,     // per-request timeout
});

Two things that trip people up on every Payaza integration, handled for you:

  • The /live path segment is fixed. It's part of the API host regardless of whether you're in test or live mode — your environment option (via X-TenantID) is what actually switches modes, not the URL.
  • The Authorization header needs your key base64-encoded, with a Payaza prefix instead of Bearer. Just pass the raw key from the dashboard as publicKey — the SDK encodes it on every request.

Usage

Account

// All currency sub-accounts under your business, with balances and account references
const { data: accounts } = await payaza.account.view();

// Look up a transaction by the reference you supplied
const status = await payaza.account.getTransactionStatus("TD93001234");

// Supported banks / mobile money providers for a currency (gives you bank_code values)
const { data: banks } = await payaza.account.getBankCodes("NGN");

// Resolve an account number + bank code to an account holder's name before transferring
const enquiry = await payaza.account.nameEnquiry({
  service_payload: {
    currency: "NGN",
    bank_code: "100004",
    account_number: "0190878999",
  },
});
console.log(enquiry.response_content.account_name);

Transfers

const transfer = await payaza.transfers.initiate({
  transaction_type: "nuban", // NGN. Use "mobile_money" for GHS/UGX/KES/etc — see field docs below
  service_payload: {
    payout_amount: 100,
    transaction_pin: 490736,          // 6-digit PIN set on the dashboard
    account_reference: "1010000009",  // from payaza.account.view()
    currency: "NGN",
    payout_beneficiaries: [
      {
        credit_amount: 100,
        account_number: "9207067319",
        account_name: "John Doe",
        bank_code: "000013",
        narration: "Invoice #482",           // <= 25 chars, no special characters
        transaction_reference: "TD93001234", // unique, >= 10 characters
        sender: {
          sender_name: "Jane Doe",
          sender_phone_number: "01234595",
          sender_address: "123, Ace Street",
        },
      },
    ],
  },
});

// Later — check how it landed
const status = await payaza.transfers.getStatus("TD93001234");

transaction_type selects the payout rail per currency: nuban for NGN, mobile_money (or a country-specific rail like ghipps, kepss, tiss, wave) for GHS/UGX/KES/TZS/XOF, and RTC for ZAR. The sum of every beneficiary's credit_amount must equal payout_amount, and every transaction_reference you send must be globally unique — reusing one is rejected by the API.

Sub-accounts

Segmented accounts under your main Payaza account, for merchants, vendors, or internal business units.

const created = await payaza.subAccounts.create({
  mainAccountPayazaReference: "100000000", // your main account's reference, from payaza.account.view()
  name: "Test Sub Account",
  currency: "NGN",
  country: "NGA", // ISO 3166-1 alpha-3
});

const subAccount = await payaza.subAccounts.get(created.data[0].payazaAccountReference);

EUR accounts

EUR-denominated sub-accounts for corporates or individuals — each request goes through document review before the account is provisioned.

// Check which ID / proof-of-address documents are accepted for the applicant's country first
const { data: acceptableIds } = await payaza.eurAccounts.acceptableIds();

// Individual applicant
const request = await payaza.eurAccounts.requestUser({
  country: "US",
  currency: "EUR",
  category: "SUB_ACCOUNT",
  purpose: "Freelance invoicing",
  consent: true,
  account_type: "user",
  main_account_payaza_reference: "10987654312",
  id_file: "https://your-cdn.example.com/uploads/passport.jpg",
  id_type: "passport",
  poa_file: "https://your-cdn.example.com/uploads/utility-bill.png",
  poa_type: "utilityBill",
  first_name: "Steve",
  last_name: "Stones",
});

// Company applicant — payaza.eurAccounts.requestCorporate({ ... company_name, certificate_of_incorporation, directors: [...] })

// Track review status
const status = await payaza.eurAccounts.getRequest(request.creationReference);

// All requests you've submitted, or a specific category
const requests = await payaza.eurAccounts.listRequests({ category: "SUB_ACCOUNT" });

// Approved/active EUR sub-accounts (paginated)
const subAccounts = await payaza.eurAccounts.list({ pageSize: 10, pageNumber: 1, currency: "EUR" });

Virtual accounts

Collect NGN bank transfers into a Dynamic (single-use, amount-locked, auto-expiring) or Static (reusable) virtual account.

const dynamic = await payaza.virtualAccounts.create({
  account_type: "Dynamic",
  account_name: "Test DVA",
  bank_code: "140", // Globus Bank
  account_reference: "accRef123", // unique per account/transaction
  customer_first_name: "John",
  customer_last_name: "Doe",
  customer_email: "[email protected]",
  transaction_amount: "1000",
  expires_in_minutes: "20",
});

console.log(dynamic.data.account_number);

// Static accounts require a validated BVN
const reserved = await payaza.virtualAccounts.create({
  account_type: "Static",
  account_name: "Test Reserved VA",
  bank_code: "140",
  bvn: "323212345",
  bvn_validated: true,
  account_reference: "accRef456",
  customer_first_name: "John",
  customer_last_name: "Doe",
  customer_email: "[email protected]",
});

const accountStatus = await payaza.virtualAccounts.getStatus(dynamic.data.account_number);
const txnStatus = await payaza.virtualAccounts.getTransactionStatus("accRef123");

// Test mode only — simulate an inbound transfer instead of moving real money
await payaza.virtualAccounts.fundTestAccount({
  account_name: dynamic.data.account_name,
  account_number: dynamic.data.account_number,
  initiation_transaction_reference: "accRef123", // required for Dynamic accounts, omit for Static
  transaction_amount: "1000",
  currency: "NGN",
  source_account_number: "0123456789",
  source_account_name: "Jill Stones",
  source_bank_name: "Test Bank",
});

Branches

const { data: branches } = await payaza.branches.list();

Webhooks

Payaza signs every webhook with HMAC-SHA512 over the raw request body, sent in the x-payaza-signature header. Verify it before trusting the payload:

import { verifyWebhookSignature } from "payaza-node-sdk";
import express from "express";

const app = express();

app.post(
  "/webhooks/payaza",
  express.raw({ type: "application/json" }), // keep the body raw/unparsed for verification
  (req, res) => {
    const signature = req.header("x-payaza-signature") ?? "";
    const isValid = verifyWebhookSignature(req.body, signature, process.env.PAYAZA_WEBHOOK_SECRET!);

    if (!isValid) {
      return res.status(401).send("Invalid signature");
    }

    const event = JSON.parse(req.body.toString("utf-8"));
    // Use event.transaction_reference (or equivalent) as an idempotency key —
    // Payaza may redeliver the same event.
    res.sendStatus(200);
  },
);

Configure your webhook URLs (separate ones for test and live) under Settings → Developers → Webhooks on the dashboard.

Error handling

Every failure — a non-2xx API response, a network error, or a timeout — raises PayazaError:

import { Payaza, PayazaError } from "payaza-node-sdk";

try {
  await payaza.transfers.initiate({ /* ... */ });
} catch (error) {
  if (error instanceof PayazaError) {
    console.error(error.message);   // human-readable message from the API (or the SDK, for network/timeout errors)
    console.error(error.status);    // HTTP status code, when the failure came from the API
    console.error(error.response);  // full parsed response body, for logging/debugging
  }
  throw error;
}

Common causes are listed in the Payaza errors reference — e.g. mismatched test/live keys, reused transaction_references, or an incorrect transaction PIN.

API coverage

The SDK is being built out incrementally against Payaza's full API surface. Everything below will follow the same payaza.<resource>.<method>() shape shown above.

| Resource | Status | Notes | |---|---|---| | payaza.account | ✅ Available | View details, transaction status, bank codes, name enquiry | | payaza.transfers | ✅ Available | Initiate transfer, check status | | payaza.subAccounts | ✅ Available | Create / view sub-accounts | | payaza.eurAccounts | ✅ Available | EUR sub-account requests, acceptable IDs, approved sub-accounts | | payaza.virtualAccounts | ✅ Available | Static/dynamic virtual accounts, status, test funding | | payaza.branches | ✅ Available | List merchant branches | | payaza.mobileMoneyCollections | ✅ Available | Mobile money / XOF / ZAR collections, OTP flow, transaction status, test funding | | payaza.cards | ✅ Available | Card charge, transaction/refund status | | payaza.authCaptureVoid | ✅ Available | Authorize, capture, void card transactions; list/get authorizations | | payaza.refunds | ✅ Available | Initiate refund, refund history | | payaza.chargebacks | ✅ Available | List, accept/reject, transaction history | | payaza.subscriptionPlans / payaza.subscriptions | ✅ Available | Plans, lifecycle (pause/resume/cancel/change plan), on-demand charging, invoices | | payaza.splitSettlements | ✅ Available | Split-account CRUD | | verifyWebhookSignature | ✅ Available | Standalone helper, no client instance needed |

payaza.mobileMoneyCollections also covers what was previously listed separately as subsidiaryCollections — Payaza exposes MoMo, XOF, and ZAR collections through the same API section.

Full endpoint-level reference: docs.payaza.africa/api-reference.

TypeScript

Types are generated as part of the build (dist/index.d.ts / dist/index.d.cts) and published with the package — no @types/ package needed. Every resource method's request and response shape is exported from the package root:

import type { InitiateTransferRequest, PayazaMainAccount } from "payaza-node-sdk";

Development

git clone https://github.com/78-Financials/payaza-node-sdk.git
cd payaza-node-sdk
npm install

npm run typecheck  # tsc --noEmit
npm run lint        # eslint
npm run test         # vitest
npm run build         # tsup — emits dist/ (ESM + CJS + .d.ts)

Support

License

MIT