How to Integrate M-Pesa STK Push in Next.js
A complete step-by-step guide to integrating Safaricom M-Pesa STK Push payments into a Next.js application using the Daraja API.
Introduction
M-Pesa is Kenya's dominant mobile payment platform, processing millions of transactions daily. If you are building any e-commerce or SaaS product for the Kenyan market, M-Pesa integration is not optional — it is essential.
What is STK Push?
STK Push triggers a payment prompt directly on the customer's phone. The customer enters their M-Pesa PIN and the payment is processed without leaving your website.
Step 1 — Environment Variables
MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret
MPESA_SHORTCODE=174379
MPESA_PASSKEY=bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919
MPESA_CALLBACK_URL=https://yourdomain.com/api/mpesa/callback
MPESA_ENV=sandbox
Step 2 — Get an Access Token
import { NextResponse } from "next/server"
export async function GET() {
const key = process.env.MPESA_CONSUMER_KEY!
const secret = process.env.MPESA_CONSUMER_SECRET!
const auth = Buffer.from(`${key}:${secret}`).toString("base64")
const url = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials"
const res = await fetch(url, { headers: { Authorization: `Basic ${auth}` } })
const data = await res.json()
return NextResponse.json({ token: data.access_token })
}
Step 3 — STK Push Route
export async function POST(req: Request) {
const { phone, amount, orderId } = await req.json()
const timestamp = new Date().toISOString().replace(/[^0-9]/g, "").slice(0, 14)
const shortcode = process.env.MPESA_SHORTCODE!
const passkey = process.env.MPESA_PASSKEY!
const password = Buffer.from(shortcode + passkey + timestamp).toString("base64")
const tokenRes = await fetch(`${process.env.NEXT_PUBLIC_URL}/api/mpesa/token`)
const { token } = await tokenRes.json()
const res = await fetch("https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest", {
method: "POST",
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
body: JSON.stringify({
BusinessShortCode: shortcode, Password: password, Timestamp: timestamp,
TransactionType: "CustomerPayBillOnline", Amount: amount,
PartyA: phone, PartyB: shortcode, PhoneNumber: phone,
CallBackURL: process.env.MPESA_CALLBACK_URL,
AccountReference: orderId, TransactionDesc: `Payment for order ${orderId}`,
}),
})
return NextResponse.json(await res.json())
}
Step 4 — Handle the Callback
export async function POST(req: Request) {
const { Body: { stkCallback } } = await req.json()
if (stkCallback.ResultCode === 0) {
const items = stkCallback.CallbackMetadata.Item
const amount = items.find((i: any) => i.Name === "Amount")?.Value
const mpesaRef = items.find((i: any) => i.Name === "MpesaReceiptNumber")?.Value
console.log({ amount, mpesaRef })
}
return NextResponse.json({ ResultCode: 0, ResultDesc: "Success" })
}
Testing in Sandbox
Use test phone 254708374149 with any 6-digit PIN and shortcode 174379.
Conclusion
M-Pesa STK Push is one of the most powerful payment tools for Kenyan developers. If you need help integrating M-Pesa into your project, feel free to reach out.
Work With James
Need help with your project?
Whether it’s M-Pesa integration, a full web application, or a performance audit — reach out and let’s build something great.
Get In Touch →