Mpesa Payments

Made Simple

The modern SDK for integrating M-Pesa payments. Type-safe, fully documented.

Get started
Without the SDK
Raw Daraja HTTP calls with fetch/httpx
89 lines
import crypto from "node:crypto";

const API = process.env.MPESA_ENV === "prod"
  ? "https://api.safaricom.co.ke"
  : "https://sandbox.safaricom.co.ke";
const AUTH_PATH = "/oauth/v1/generate";
const STK_PATH = "/mpesa/stkpush/v1/processrequest";
const AUTH_QS = "grant_type=client_credentials";

const KEY = process.env.MPESA_KEY ?? "";
const SECRET = process.env.MPESA_SECRET ?? "";
const SHORTCODE = process.env.MPESA_SHORTCODE ?? "";
const PASSKEY = process.env.MPESA_PASSKEY ?? "";
const CB_URL = process.env.MPESA_CB_URL ?? "";

type StkParams = {
  amount: number;
  phone: string;
  accountRef: string;
  desc?: string;
};

function normalize(phone: string): string {
  const digits = phone.replace(/\D/g, "");
  if (digits.startsWith("0")) {
    return "254" + digits.slice(1);
  }
  return digits;
}

function stamp(): string {
  const d = new Date();
  const p = (n: number) => String(n).padStart(2, "0");
  let s = String(d.getFullYear());
  s += p(d.getMonth() + 1) + p(d.getDate());
  s += p(d.getHours()) + p(d.getMinutes());
  s += p(d.getSeconds());
  return s;
}

function password(time: string): string {
  const raw = SHORTCODE + PASSKEY + time;
  return Buffer.from(raw).toString("base64");
}

async function getToken(): Promise<string> {
  const raw = KEY + ":" + SECRET;
  const creds = Buffer.from(raw).toString("base64");
  const url = API + AUTH_PATH + "?" + AUTH_QS;
  const res = await fetch(url, {
    headers: { Authorization: "Basic " + creds },
  });
  if (!res.ok) {
    throw new Error("Token failed: " + res.status);
  }
  return (await res.json()).access_token;
}

export async function stkPush(p: StkParams) {
  const at = await getToken();
  const time = stamp();
  const payload = {
    BusinessShortCode: SHORTCODE,
    Password: password(time),
    Timestamp: time,
    TransactionType: "CustomerPayBillOnline",
    Amount: p.amount,
    PartyA: normalize(p.phone),
    PartyB: SHORTCODE,
    PhoneNumber: normalize(p.phone),
    CallBackURL: CB_URL,
    AccountReference: p.accountRef,
    TransactionDesc: p.desc ?? "",
  };

  const res = await fetch(API + STK_PATH, {
    method: "POST",
    headers: {
      Authorization: "Bearer " + at,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  });
  if (!res.ok) {
    const text = await res.text();
    throw new Error(res.status + ": " + text);
  }
  return res.json();
}
With the SDK
@singularity-payments/core
10 lines
import { createMpesa } from
  "@singularity-payments/core";

// Reads MPESA_* env vars for you.
const mpesa = createMpesa();
const res = await mpesa.stkPush({
  amount: 100,
  phoneNumber: "254708374149",
  accountReference: "ORDER-123",
});

Works with your favourite languages

TypeScriptPython

and

your favourite frameworks

ReactNext.jsSvelteExpressNuxtFastAPIFlaskDjango

Async first

Non-blocking requests with automatic retries and exponential backoff built in.

Type safe

Full type coverage in TypeScript and validated Pydantic models in Python.

Complete coverage

STK Push, C2B, B2C, B2B, reversals, balances, QR codes and callbacks.

Quick start

Install the SDK, configure your credentials and start accepting payments in minutes.

TypeScript

TypeScript / JavaScript

1

Install the package

npm install @singularity-payments/nextjs
2

Create a client

const mpesa = createMpesa({
  consumerKey: process.env.MPESA_CONSUMER_KEY!,
  consumerSecret: process.env.MPESA_CONSUMER_SECRET!,
  shortcode: process.env.MPESA_SHORTCODE!,
  passkey: process.env.MPESA_PASSKEY!,
});
3

Collect a payment

await mpesa.client.stkPush({
  amount: 100,
  phoneNumber: "254712345678",
  accountReference: "ORDER-123",
  transactionDesc: "Quick start",
});
Python

Python

1

Install the package

pip install singularity-payments
2

Create a client

import os
from singularity_payments import MpesaClient, MpesaConfig

mpesa = MpesaClient(
    MpesaConfig(
        consumer_key=os.environ["MPESA_CONSUMER_KEY"],
        consumer_secret=os.environ["MPESA_CONSUMER_SECRET"],
        shortcode=os.environ["MPESA_SHORTCODE"],
        passkey=os.environ["MPESA_PASSKEY"],
        callback_url=os.environ["MPESA_CALLBACK_URL"],
    )
)
3

Collect a payment

from singularity_payments import STKPushRequest

await mpesa.stk_push(
    STKPushRequest(
        amount=100,
        phone_number="254712345678",
        account_reference="ORDER-123",
        transaction_desc="Quick start",
    )
)

Ready to get started?

Read the guides and ship your first M-Pesa integration today.

[email protected]