Logo Lanfrica

rauell1/mpesa-stk

Domain:

digital infrastructure

Record type:

software
Creator:
rau
Host:
TypeScript library for the M-Pesa STK Push lifecycle with built-in webhook relay server. # mpesa-stk M-PESA for TypeScript, in two packages you can use separately or together. | Package | Covers | Use it when | |---|---|---| | **`mpesa-stk`** (this one) | STK Push, end to end | You need the STK lifecycle done properly — idempotency, dedup, a poll fallback, reconciliation, a signing relay | | **`mpesa-billing`** | STK Push, C2B, B2C, B2B, Stripe Checkout | You need more than one rail, settling through one exactly-once contract | Node 18+ · Postgres · zero-config TypeScript types. Start with `mpesa-billing` if you want the other rails; everything below is `mpesa-stk` itself. --- The M-Pesa STK Push lifecycle, done properly. Daraja gives you "send a push" and "receive one callback" — this library is everything in between: idempotent initiation, atomic callback dedup, a polling fallback, and reconciliation. TypeScript · Node 18+ · Postgres. STK Push only — for B2C, C2B, B2B, or cards, use `mpesa-billing`. ## Why Daraja's docs are a request/response spec. They stop where production starts. Pointed at the live sandbox, the API actually: - re-fires the same callback multiple times under load — dedupe or you double-credit - drops the callback entirely if your server blinks — no retry, no dead-letter - rate-limits the STK Query (5 req/min in sandbox) and returns undocumented transient codes like `4999` mid-flight — a naive poller marks a still-pending payment FAILED - masks the customer's phone number in 2026+ callbacks - has no idempotency key — a double-tapped "Pay" sends two pushes and charges twice Each of those is a wrong refund or a missed order waiting to happen. This library is that missing layer. ## Install ```bash npm install mpesa-stk pg ``` ## Usage ```typescript import { MpesaStk, PostgresAdapter } from 'mpesa-stk' import { Pool } from 'pg' const adapter = new PostgresAdapter(new Pool({ connectionString: process.env.DATABASE_URL })) await adapter.migrate() // creates mpesa_payments; safe on every startup (IF NOT EXISTS) const mpesa = …

Languages

Licenses