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

@landelatech/mpesa-node

v1.1.2

Published

Production-ready Node.js SDK for Safaricom M-Pesa Daraja APIs — fluent API, automatic OAuth, zero boilerplate.

Downloads

387

Readme

@landelatech/mpesa-node

Build Production-ready Node.js (TypeScript) SDK for Safaricom M-Pesa Daraja APIs. Fluent API, automatic OAuth, zero boilerplate.

  • Fluent API — Method-based, not endpoint-based
  • Automatic auth — OAuth token generation and in-memory caching with refresh
  • Environment support — Sandbox and production
  • Typed — Full TypeScript with strict mode
  • Zero hardcoded secrets — Config via constructor or environment variables (env used when not specified)
  • Typed errorsMpesaAuthError, MpesaRequestError, MpesaValidationError

Requirements

  • Node.js 20+
  • Yarn (classic v1)

Installation

yarn add @landelatech/mpesa-node

Quick start

Credentials can be set in the environment or passed explicitly in config. The SDK reads from env when a value is not provided.

import { Mpesa } from "@landelatech/mpesa-node";

// Option 1: Rely on environment (e.g. MPESA_CONSUMER_KEY, MPESA_CONSUMER_SECRET, MPESA_ENVIRONMENT, etc.)
const mpesa = new Mpesa({});

// Option 2: Pass config explicitly (overrides env for those fields)
const mpesa = new Mpesa({
  consumerKey: "...",
  consumerSecret: "...",
  environment: "sandbox",
  shortCode: "174379",
  passKey: "...",
});

// STK Push (Lipa Na M-Pesa Online)
const res = await mpesa.stkPush({
  phoneNumber: "254708374149",
  amount: 10,
  callbackUrl: "https://your-domain.com/callback",
  accountReference: "order-123",
  transactionDesc: "Payment for order",
});
console.log(res.CheckoutRequestID); // use with stkQuery()

Configuration

Config fields are optional. Any value not passed is read from the environment. Explicit config always overrides env.

| Option | Env fallback | Description | |--------|--------------|-------------| | consumerKey | MPESA_CONSUMER_KEY | Daraja app consumer key (required with consumerSecret) | | consumerSecret | MPESA_CONSUMER_SECRET | Daraja app consumer secret (required with consumerKey) | | environment | MPESA_ENVIRONMENT | "sandbox" or "production" (default: sandbox) | | shortCode | MPESA_SHORT_CODE | Paybill or Till number (for STK/C2B/B2C/balance/status) | | passKey | MPESA_PASS_KEY | Lipa Na M-Pesa passkey (for STK Push/Query) | | initiatorName | MPESA_INITIATOR_NAME | API operator username (for B2C/balance/status) | | securityCredential | MPESA_SECURITY_CREDENTIAL | Encrypted initiator password (for B2C/balance/status) |

Required for auth: consumerKey and consumerSecret must be set (in config or env). All other fields are only needed for the APIs that use them. Never commit secrets.

API overview

STK Push (Lipa Na M-Pesa Online)

Initiate a payment prompt on the customer’s phone; then query status.

const res = await mpesa.stkPush({
  phoneNumber: "254708374149",
  amount: 100,
  callbackUrl: "https://example.com/stk-callback",
  accountReference: "invoice-001",
  transactionDesc: "Payment",
});
// res.CheckoutRequestID

const status = await mpesa.stkQuery({ checkoutRequestId: res.CheckoutRequestID });

C2B (Customer to Business)

Register confirmation/validation URLs and (sandbox) simulate payments.

await mpesa.c2b.registerUrls({
  confirmationUrl: "https://example.com/c2b/confirm",
  validationUrl: "https://example.com/c2b/validate",
  responseType: "Completed",
});

// Sandbox only: simulate a payment
await mpesa.c2b.simulate({
  amount: 100,
  msisdn: "254712345678",
  billRefNumber: "ref-001",
});

B2C (Business to Customer)

Send money to customers. Result and timeout callbacks go to your URLs.

await mpesa.b2c.send({
  recipientPhone: "254712345678",
  amount: 500,
  resultUrl: "https://example.com/b2c/result",
  queueTimeOutUrl: "https://example.com/b2c/timeout",
  remarks: "Salary",
  occasion: "January 2024",
  commandId: "SalaryPayment",
});

Account balance

Request balance; Daraja sends the result to your callback URL.

await mpesa.account.balance({
  resultUrl: "https://example.com/balance/result",
  queueTimeOutUrl: "https://example.com/balance/timeout",
});

Transaction status

Query status of a transaction (e.g. when callback was missed).

await mpesa.transaction.status({
  transactionId: "ABC123...",
  resultUrl: "https://example.com/status/result",
  queueTimeOutUrl: "https://example.com/status/timeout",
  remarks: "Status check",
});

Error handling

The SDK throws typed errors you can catch by name or instanceof:

import {
  Mpesa,
  MpesaAuthError,
  MpesaRequestError,
  MpesaValidationError,
} from "@landelatech/mpesa-node";

try {
  await mpesa.stkPush({ ... });
} catch (err) {
  if (err instanceof MpesaAuthError) {
    // OAuth / token failure
  } else if (err instanceof MpesaRequestError) {
    // API 4xx/5xx or Daraja error; err.statusCode, err.responseBody
  } else if (err instanceof MpesaValidationError) {
    // Invalid input (phone, URL, etc.)
  }
}

Receiving callbacks

Daraja sends POST requests to your URLs (STK callback, C2B confirmation/validation, B2C result, etc.). The SDK gives you:

  • Typed payloadsStkPushCallbackPayload, C2BConfirmationPayload, DarajaResultPayload, etc.
  • Parsers — validate raw req.body and get typed data: parseStkPushCallback(body), parseC2BConfirmation(body), parseDarajaResult(body).
  • Rich helpersgetStkMetadata(payload) for amount, receipt number, phone; getResultParametersMap(payload) for B2C/balance/status result parameters.
  • Optional receivercreateCallbackHandler({ routes }) returns an HTTP handler you can pass to http.createServer() or mount in Express/Fastify.

Option 1: Use parsers in your own routes

In any POST handler, parse the body and use the typed payload:

import {
  parseStkPushCallback,
  getStkMetadata,
  parseC2BConfirmation,
  C2B_VALIDATION_ACCEPT,
  C2B_VALIDATION_REJECT,
} from "@landelatech/mpesa-node";

// STK callback
app.post("/mpesa/stk", (req, res) => {
  const payload = parseStkPushCallback(req.body);
  if (payload.ResultCode === 0) {
    const meta = getStkMetadata(payload);
    if (meta) console.log(meta.mpesaReceiptNumber, meta.amount, meta.phoneNumber);
  }
  res.json({ ResultCode: 0, ResultDesc: "Success" });
});

// C2B confirmation (payments to your paybill/till)
app.post("/mpesa/c2b/confirm", (req, res) => {
  const p = parseC2BConfirmation(req.body);
  console.log(p.TransID, p.TransAmount, p.MSISDN, p.BillRefNumber);
  res.sendStatus(200);
});

// C2B validation (accept or reject before completion)
app.post("/mpesa/c2b/validate", (req, res) => {
  const p = parseC2BValidation(req.body);
  const accept = yourValidationLogic(p); // e.g. check BillRefNumber
  res.json(accept ? C2B_VALIDATION_ACCEPT : C2B_VALIDATION_REJECT);
});

Option 2: Standalone callback server

Use createCallbackHandler with predefined routes and pass it to Node’s http.createServer (no Express needed):

import { createServer } from "node:http";
import {
  createCallbackHandler,
  stkPushRoute,
  c2BConfirmationRoute,
  getStkMetadata,
} from "@landelatech/mpesa-node";

const handler = createCallbackHandler({
  routes: {
    "/mpesa/stk": stkPushRoute(async (payload) => {
      if (payload.ResultCode === 0) {
        const meta = getStkMetadata(payload);
        if (meta) await savePayment(meta.mpesaReceiptNumber, meta.amount);
      }
    }),
    "/mpesa/c2b/confirm": c2BConfirmationRoute((p) => {
      console.log(p.TransID, p.TransAmount, p.BillRefNumber);
    }),
  },
});

createServer(handler).listen(3000);

Handlers can return a response override (e.g. for C2B validation): return { statusCode: 200, body: C2B_VALIDATION_ACCEPT };.

C2B registered URLs

When you call mpesa.c2b.registerUrls(), set ConfirmationURL and ValidationURL to the paths that handle confirmation and validation (e.g. https://your-domain.com/mpesa/c2b/confirm and .../mpesa/c2b/validate). Use the parsers or the callback handler above so you get typed payloads and can respond correctly (e.g. validation must return C2B_VALIDATION_ACCEPT or C2B_VALIDATION_REJECT).

Examples

After building (yarn build), copy examples/env.example to .env in the project root and fill in your Daraja credentials. Then run:

  • node examples/stk-push.mjs — STK Push and query
  • node examples/c2b.mjs — Register URLs and simulate
  • node examples/callbacks-server.mjs — Receive callbacks with typed payloads (standalone HTTP server)

Examples use dotenv (dev dependency) to load .env. Never commit .env or real secrets.

Development

yarn install
yarn build
yarn test
yarn lint
yarn format:check

License

MIT. See LICENSE.

Contributing

See CONTRIBUTING.md.