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

@chiahq/sdk

v0.6.0

Published

A unified SDK for African payment providers

Readme

Chia SDK

A TypeScript SDK for integrating African mobile money payments. Unified, type-safe API for PayChangu, PawaPay, and OneKhusa.

npm version License: MIT

Standalone by design

The SDK talks directly to the provider APIs with your own credentials - a PayChangu secret key, a PawaPay API token, or OneKhusa API credentials. There is no Chia account, no proxy, and no platform dependency: your requests go straight to the providers, and nothing here phones home.

Reach for the SDK when you need:

  • Custom payment flows under your full control
  • Direct access to provider APIs (deposits, payouts, refunds, wallets)
  • Integration into an existing backend where you manage your own provider accounts
  • Batch disbursements or approval workflows (OneKhusa)
  • The unified payments surface: one call that routes across whichever providers you configure

The hosted platform (optional)

If what you actually want is recurring billing - plans, hosted checkout, automatic renewals and retries, failed-payment recovery, webhooks, and weekly payouts - the Chia platform runs all of that on top of this SDK. Sign up, create a plan, share a link; no provider accounts needed. The SDK remains the right tool for custom flows; the platform is the shortcut for subscriptions. Neither requires the other.

Features

  • Multi-Provider Support - PayChangu, PawaPay, and OneKhusa in one SDK
  • Full TypeScript Support - Comprehensive type definitions for all APIs
  • Sandbox & Production - Easy environment switching
  • Comprehensive Error Handling - Detailed error messages and types

Supported Providers

| Provider | Region | Capabilities | |----------|--------|--------------| | PayChangu | Malawi | Payments, Mobile Money, Bank Transfers | | PawaPay | Sub-Saharan Africa | Deposits, Payouts, Refunds, Wallets | | OneKhusa | Malawi & Southern Africa | Collections, Disbursements, Batch Payouts |

Installation

npm install @chiahq/sdk
# or
pnpm add @chiahq/sdk
# or
yarn add @chiahq/sdk

Quick Start

import { ChiaSDK } from "@chiahq/sdk";

const sdk = ChiaSDK.initialize({
  pawapay: {
    jwt: "your-pawapay-jwt"
  },
  paychangu: {
    secretKey: "your-paychangu-secret"
  },
  onekhusa: {
    apiKey: "your-onekhusa-api-key",
    apiSecret: "your-onekhusa-api-secret",
    organisationId: "your-organisation-id"
  }
});

ChiaSDK has a private constructor - use ChiaSDK.initialize(config) to create (or fetch) the singleton, or ChiaSDK.create(config) for an independent instance. Both accept the same SDKConfig shape.

You only need to configure the providers you plan to use.

Unified payments API

Instead of calling each provider directly, sdk.payments and sdk.payouts route a request to whichever configured provider can serve it:

const payment = await sdk.payments.initiate({
  reference: "order-123",
  amount: "50.00",
  currency: "ZMW",
  msisdn: "260971234567",
  country: "ZMB",
  description: "Payment for services",
});

payment.provider   // "pawapay"      - paychangu was skipped, it cannot serve ZMW in ZMB
payment.status     // "pending"
payment.nextAction // { type: "pin_prompt" }
payment.operator   // "AIRTEL_ZMB"   - inferred from the msisdn

Routing is by country and currency, preferring PayChangu, then PawaPay, then OneKhusa. Providers that cannot serve the route are skipped, not contacted. Pin a single provider with provider: "pawapay", or give an ordered shortlist with providers: ["pawapay", "paychangu"].

payment.attempts records every provider tried, skipped or refused, with the reason. payment.raw always carries the untouched response from whichever provider handled the request.

Coverage today

| Provider | Countries | |----------|-----------| | PawaPay | 19 countries across Sub-Saharan Africa | | PayChangu | Malawi only | | OneKhusa | Malawi only |

Outside Malawi, PawaPay is currently the only candidate.

Failover is deliberately conservative

This is not retry-on-failure. When a shortlist is given, the SDK advances to the next provider only on outcomes that provably moved no money: the provider isn't configured, it can't serve the route, validation was rejected, or it explicitly refused the request. On a timeout or a 5xx after the request was sent, it aborts rather than trying another provider - a client-side timeout is indistinguishable from a successful charge, and retrying elsewhere would risk charging the customer twice.

Fetching a payment later

sdk.payments.get(id, { provider }) requires an explicit provider: an opaque id carries no routing information on its own. Pass back the provider field from the ChiaPayment that initiate() returned.

Provider-specific features

Anything the providers do not share stays on its own namespace: sdk.pawapay.refunds, sdk.pawapay.remittances, sdk.paychangu hosted checkout, sdk.onekhusa.disbursements, and so on.

OneKhusa payouts need approval

sdk.payouts.send() on OneKhusa returns status: "pending_approval" and requiresApproval: true, because its API opens a maker-checker flow rather than sending. Advance it with sdk.onekhusa.disbursements.approveSingle(id). Check sdk.capabilities("onekhusa").payouts.requiresApproval before calling.

PawaPay

Mobile money payments across Sub-Saharan Africa.

Request a Deposit via the Hosted Payment Page

const deposit = await sdk.pawapay.payments.initiatePayment({
  depositId: "order-123",
  returnUrl: "https://your-app.com/callback",
  msisdn: "260971234567",
  amount: "50.00",
  country: "ZMB",
  reason: "Service payment",
  language: "EN"
});

// Redirect the customer to deposit.redirectUrl to complete the payment

Send a Payout

const payout = await sdk.pawapay.payouts.sendPayout({
  payoutId: "payout-123",
  amount: "50.00",
  currency: "ZMW",
  recipient: {
    type: "MMO",
    accountDetails: {
      phoneNumber: "260701234567",
      provider: "AIRTEL_ZMB"
    }
  }
});

Check Wallet Balance

const balances = await sdk.pawapay.wallets.getAllBalances();

PayChangu

Payment services in Malawi.

Initiate Payment

const txRef = "order-456";

const payment = await sdk.paychangu.initiatePayment({
  amount: "1000",
  currency: "MWK",
  tx_ref: txRef,
  email: "[email protected]",
  first_name: "John",
  last_name: "Doe",
  callback_url: "https://your-app.com/webhook",
  return_url: "https://your-app.com/success"
});

// Redirect customer to checkout
console.log("Checkout URL:", payment.data.checkout_url);

Verify Transaction

const verification = await sdk.paychangu.verifyTransaction(txRef);

Mobile Money Payout

initializeMobileMoneyPayout takes positional arguments, not an options object:

const payout = await sdk.paychangu.initializeMobileMoneyPayout(
  "265991234567", // recipient mobile number
  "operator-ref-id", // from sdk.paychangu.getMobileMoneyOperators()
  2000, // amount
  "payout-123" // charge_id
);

OneKhusa

Enterprise payment platform with collections and disbursements.

Request-to-Pay Collection

initiateRequestToPay returns CollectionResponse | ServiceError - narrow with isServiceError before reading the success fields:

import { isServiceError } from "@chiahq/sdk";

const collection = await sdk.onekhusa.collections.initiateRequestToPay({
  amount: 5000,
  currency: "MWK",
  phone: "265991234567",
  paymentMethod: "MOBILE_MONEY",
  reference: "order-789",
  description: "Payment for goods"
});

if (isServiceError(collection)) {
  throw new Error(collection.errorMessage);
}

console.log("TAN:", collection.tan);

Single Disbursement

const disbursement = await sdk.onekhusa.disbursements.addSingle({
  amount: 10000,
  currency: "MWK",
  paymentMethod: "MOBILE_MONEY",
  recipient: {
    name: "John Doe",
    phone: "265991234567"
  },
  reference: "payout-001",
  description: "Salary payment"
});

if (isServiceError(disbursement)) {
  throw new Error(disbursement.errorMessage);
}

// Approve the disbursement
await sdk.onekhusa.disbursements.approveSingle(disbursement.id);

Batch Disbursement

Batch items each carry their own amount, currency, paymentMethod and recipient - there is no top-level currency/paymentMethod/recipients on the batch request:

const batch = await sdk.onekhusa.disbursements.addBatch({
  name: "January Salaries",
  items: [
    {
      amount: 50000,
      currency: "MWK",
      paymentMethod: "MOBILE_MONEY",
      recipient: { name: "John Doe", phone: "265991234567" }
    },
    {
      amount: 45000,
      currency: "MWK",
      paymentMethod: "MOBILE_MONEY",
      recipient: { name: "Jane Smith", phone: "265999876543" }
    }
  ]
});

if (isServiceError(batch)) {
  throw new Error(batch.errorMessage);
}

// Approve and transfer funds
await sdk.onekhusa.disbursements.approveBatch(batch.id);
await sdk.onekhusa.disbursements.transferBatchFunds(batch.id);

Configuration

Use environment variables for secure credential management. There is no top-level environment option - each provider takes its own environment field ("DEVELOPMENT" or "PRODUCTION", defaulting to "DEVELOPMENT"):

import { ChiaSDK, ENVIRONMENTS } from "@chiahq/sdk";

const sdk = ChiaSDK.initialize({
  pawapay: {
    jwt: process.env.PAWAPAY_TOKEN,
    environment: ENVIRONMENTS.PRODUCTION // or ENVIRONMENTS.DEVELOPMENT
  },
  paychangu: {
    secretKey: process.env.PAYCHANGU_SECRET,
    environment: ENVIRONMENTS.PRODUCTION
  },
  onekhusa: {
    apiKey: process.env.ONEKHUSA_API_KEY,
    apiSecret: process.env.ONEKHUSA_API_SECRET,
    organisationId: process.env.ONEKHUSA_ORGANISATION_ID,
    environment: ENVIRONMENTS.PRODUCTION
  }
});

Custom API URLs

Override default provider endpoints for testing or regional deployments:

const sdk = ChiaSDK.initialize({
  pawapay: {
    jwt: "your-jwt",
    environment: "DEVELOPMENT",
    sandboxUrl: "https://custom-sandbox.pawapay.io/v1",
    productionUrl: "https://custom-prod.pawapay.io/v1"
  },
  paychangu: {
    secretKey: "your-secret",
    sandboxUrl: "https://custom.paychangu.com"
  },
  onekhusa: {
    apiKey: "your-key",
    apiSecret: "your-secret",
    organisationId: "your-org-id",
    sandboxUrl: "https://custom-sandbox.onekhusa.com/v1"
  }
});

Both sandboxUrl and productionUrl are optional. The URL used depends on the environment setting.

Type Definitions

All types are exported from the main package:

import type {
  PayChanguTypes,
  PawaPayTypes,
  OneKhusaTypes
} from "@chiahq/sdk";

Requirements

  • Node.js 18.0.0 or higher
  • TypeScript 5.0+ (optional, but recommended)

Getting API Credentials

These credentials are needed when using the SDK directly. If you're using the Chia platform, you don't need provider API keys - Chia handles payment collection for you.

PawaPay

  1. Visit PawaPay and create a developer account
  2. Complete onboarding and verification
  3. Get your API token from the dashboard

PayChangu

  1. Sign up at PayChangu
  2. Complete business verification
  3. Get your secret key from the merchant dashboard

OneKhusa

  1. Contact OneKhusa to create a business account
  2. Complete KYC verification
  3. Get your API Key, API Secret, and Organisation ID

Documentation

For full documentation, visit docs.usechia.com or see the docs.

MCP Server

For AI-powered payment operations with Claude, check out @chiahq/mcp.

License

MIT