Safaricom M-Pesa dominates Kenya payments: 90% transactions, 30M+ users. To sell online Kenya, M-Pesa is non-negotiable. STK Push (Sim Toolkit Push) enables web/app checkout: user enters number, payment popup on phone, validates PIN. Here's complete Daraja API 2026 integration.
TL;DR
- Daraja API: Safaricom portal to integrate M-Pesa.
- STK Push: payment push notification on customer phone.
- C2B: Customer to Business (receive customer payments).
- Fees: 1.5-2.5% per transaction (volume negotiable).
Understanding Kenya M-Pesa 2026
| Service | Usage | Monthly volume |
|---|---|---|
| M-Pesa P2P (peer-to-peer) | Personal transfer | $4B/month |
| M-Pesa Pay Bill | Bill payment | $2B/month |
| M-Pesa Buy Goods | Merchant payments | $3B/month |
| M-Pesa STK Push | E-commerce / app | Rapidly growing |
| M-Shwari | Savings / micro-loans | 8M users |
90% of Kenyan adults have M-Pesa account. Airtel Money minority competitor.
M-Pesa Business accounts
- Pay Bill Account
- Format : 5-7 digit Pay Bill number + Account Reference
- Usage : bills, subscriptions, e-commerce
- Till Number (Buy Goods)
- Format : 5-7 digit Till number
- Usage : physical POS, restaurants, retail
- Stock Account
- For distribution / agents
For e-commerce / SaaS, Pay Bill Account = standard.
Daraja API registration
- Go to developer.safaricom.co.ke
- Create developer account (free)
- Create an App:
- Sandbox first (tests)
- Production after go-live + KYC
- Get Consumer Key + Consumer Secret
- Request product activation:
- M-Pesa Express (STK Push)
- C2B
- B2C (payouts)
- Account Balance
Production activation: 5-15 business days after complete KYC request.
STK Push integration (Node.js)
Step 1 — get access token
`typescript
import axios from 'axios';
async function getMpesaToken() {
const auth = Buffer.from(
${process.env.MPESA_CONSUMER_KEY}:${process.env.MPESA_CONSUMER_SECRET}
).toString('base64');
const res = await axios.get(
'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
{ headers: { Authorization: Basic ${auth} } }
);
return res.data.access_token;
}
`
Step 2 — initiate STK Push
`typescript
async function initiateSTKPush({
phoneNumber, // Format: 254712345678
amount, // KES, integer
accountReference,
description,
}) {
const token = await getMpesaToken();
const timestamp = new Date()
.toISOString()
.replace(/[^0-9]/g, '')
.slice(0, 14);
const password = Buffer.from(
${process.env.MPESA_SHORTCODE}${process.env.MPESA_PASSKEY}${timestamp}
).toString('base64');
const res = await axios.post(
'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest',
{
BusinessShortCode: process.env.MPESA_SHORTCODE,
Password: password,
Timestamp: timestamp,
TransactionType: 'CustomerPayBillOnline',
Amount: amount,
PartyA: phoneNumber,
PartyB: process.env.MPESA_SHORTCODE,
PhoneNumber: phoneNumber,
CallBackURL: ${process.env.APP_URL}/api/mpesa/callback,
AccountReference: accountReference,
TransactionDesc: description,
},
{ headers: { Authorization: Bearer ${token} } }
);
return res.data; // { CheckoutRequestID, MerchantRequestID, ... }
}
`
Step 3 — handle callback
`typescript
// app/api/mpesa/callback/route.ts (Next.js)
export async function POST(req: Request) {
const body = await req.json();
const callback = body.Body.stkCallback;
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
if (callback.ResultCode === 0) {
// Successful payment
const items = callback.CallbackMetadata.Item;
const amount = items.find((i) => i.Name === 'Amount').Value;
const mpesaReceipt = items.find((i) => i.Name === 'MpesaReceiptNumber').Value;
const phoneNumber = items.find((i) => i.Name === 'PhoneNumber').Value;
// Mark transaction OK in DB
await markPaymentSuccess({
checkoutRequestId: callback.CheckoutRequestID,
mpesaReceipt,
phoneNumber,
amount,
});
} else {
// Failed payment (cancel, timeout, insufficient funds)
await markPaymentFailed({
checkoutRequestId: callback.CheckoutRequestID,
reason: callback.ResultDesc,
});
}
return Response.json({ ResultCode: 0, ResultDesc: 'Success' });
}
`
Step 4 — verify status (poll if needed)
`typescript
async function queryTransaction(checkoutRequestId: string) {
const token = await getMpesaToken();
const timestamp = new Date()
.toISOString()
.replace(/[^0-9]/g, '')
.slice(0, 14);
const password = Buffer.from(
${SHORTCODE}${PASSKEY}${timestamp}
).toString('base64');
const res = await axios.post(
'https://api.safaricom.co.ke/mpesa/stkpushquery/v1/query',
{
BusinessShortCode: SHORTCODE,
Password: password,
Timestamp: timestamp,
CheckoutRequestID: checkoutRequestId,
},
{ headers: { Authorization: Bearer ${token} } }
);
return res.data;
}
`
STK Push UX best practices
- Number format: auto-prefix +254 if user types 07XXXXXXXX
- Show loader during wait (max 60s timeout)
- Success toast / sound when callback received
- "Resend" button if not received after 30s
- Manual Pay Bill fallback if STK Push fails
- Store MpesaReceiptNumber for reconciliation
2026 pricing
| Monthly volume | Transaction fees |
|---|---|
| <50K KES | 2.5% |
| 50K-500K | 2% |
| 500K-5M | 1.7% |
| >5M | 1.5% negotiable |
Business account withdrawal fees: 50-150 KES per amount.
Common mistakes
- Incorrect timestamp — non-UTC formats. Use strict YYYYMMDDHHMMSS format.
- Non-public callback URL — localhost OK sandbox. Production = HTTPS public mandatory.
- No idempotence — callback can arrive multiple times. Check unique MpesaReceiptNumber.
- Not handling timeout — STK Push expires 60s. If no callback, query status.
- Testing direct production — sandbox first mandatory.
Daraja sandbox vs production
Sandbox :
- URL : sandbox.safaricom.co.ke
- Test phone : 254708374149
- Test PIN : 12345
- Test shortcode : 174379
Production :
- URL : api.safaricom.co.ke
- Real shortcode after KYC + activation
- Real transactions = real money
Kenya alternatives
- Airtel Money: minority but growing
- Pesalink: fast inter-bank transfers
- Card payments: Stripe (via Hong Kong) or DPO Group
- Crypto: Yellow Card USDT (strong growth 2024+)
FAQ
Q: KYC for Daraja business?
A: Yes. Company docs, incorporation cert, director IDs, business address proof.
Q: Multi-currency M-Pesa?
A: No. KES only. For USD/EUR, external bank conversion.
Q: Payouts to M-Pesa users (B2C)?
A: Yes via Daraja B2C API. Use cases: refunds, gig worker payroll, marketplace payouts.
Conclusion
M-Pesa STK Push Kenya 2026 = checkout standard. Daraja API mature but 2-4 week setup (KYC + tests). 1.5-2.5% fees. Any startup selling Kenya must integrate D1. Alternative stack: DPO Group if want unified Pan-Africa.
Mohamed Bah
Fondateur, Kolonell
Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.
