✳ Nairobi, Kenya
- WhatsApp+254 799 756 331
- Emailhello@muvevi.com
- LinkedInlinkedin.com/in/muvevi
- GitHubgithub.com/mutua-muvevi
- Twitter / X@muvevi
Available for freelance & full-time roles.
Let's build something great.
M-Pesa Daraja API integration in Next.js
— a complete guide
Safaricom's docs are incomplete and the sandbox is unreliable. Here's what actually works for STK Push in a Next.js API route, with error handling for the edge cases they don't document.
M-Pesa is the dominant payment method in Kenya — 98% of our commerce platform's orders came through it — but Safaricom's Daraja API documentation has gaps that cost you days of debugging.
The core flow for STK Push (Lipa Na M-Pesa Online) is: generate an OAuth token, construct a Base64-encoded password from (Shortcode + Passkey + Timestamp), POST to /mpesa/stkpush/v1/processrequest, then handle the async callback at your registered URL.
The parts the docs gloss over:
Timestamp format. It must be YYYYMMDDHHmmss in EAT (East Africa Time, UTC+3), not UTC. Sending UTC timestamps produces a cryptic "invalid request" error with no further detail.
Sandbox phone numbers. The sandbox only accepts test numbers in the format 254708374149. Your real number will return success responses in the sandbox but no actual STK push will fire — which makes testing feel broken.
Callback URL requirements. Must be HTTPS, publicly reachable, and not localhost. During development, use ngrok to expose your local Next.js API route: ngrok http 3000. The callback URL in your Daraja app registration must match exactly — no trailing slashes, no query params.
Idempotency. STK Push responses come back quickly but the actual user payment can take 30–90 seconds. Build your checkout to poll a status endpoint rather than waiting on the initial response. Store CheckoutRequestID from the STK Push response and query /mpesa/stkpush/v1/query every 5 seconds until you get ResultCode 0 (success) or a terminal failure code.
Error codes. ResultCode 1032 means the user cancelled. 1037 means the STK push timed out. 2001 means wrong PIN. None of these are documented in the main Daraja docs — they're buried in a PDF in the developer portal.