← All Articles
Tutorial8 min read10 March 2026

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.

JM
James Maroko
Full-Stack Engineer & Cybersecurity Specialist

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 →