Why M-Pesa Integration Matters
M-Pesa processes over $300 billion in transactions annually and has over 51 million active users across Africa. If your business operates in Kenya β or anywhere M-Pesa is active β failing to integrate it isn't just inconvenient. It's leaving money on the table.
In this guide, we'll walk through everything you need to know about integrating M-Pesa's Daraja API into your website or application, from sandbox setup to production go-live.
Understanding the Daraja API
Safaricom's Daraja API is the official developer interface for M-Pesa. It supports several transaction types:
- STK Push (Lipa Na M-Pesa Online) β Initiates a payment prompt directly on the customer's phone. The most common integration for e-commerce.
- C2B (Customer to Business) β Accepts payments where the customer initiates from their phone (Paybill / Buy Goods).
- B2C (Business to Customer) β Sends money from your business to a customer's phone. Used for refunds, disbursements, and payouts.
- B2B (Business to Business) β Transfers between business accounts.
- Transaction Status API β Queries the status of any transaction.
- Account Balance API β Checks your M-Pesa business account balance.
Step 1: Register on the Daraja Developer Portal
Head to developer.safaricom.co.ke and create a developer account. Once registered:
- Create a new app to get your Consumer Key and Consumer Secret
- Enable the APIs you need (Lipa Na M-Pesa Online, C2B, B2C, etc.)
- Note down your sandbox shortcode:
174379(test only) - Note your sandbox passkey for STK Push tests
Step 2: Get an OAuth Token
Before every API call, you need a Bearer token. Here's how to get one in Node.js:
const getOAuthToken = async () => {
const credentials = Buffer.from(
`${process.env.MPESA_CONSUMER_KEY}:${process.env.MPESA_CONSUMER_SECRET}`
).toString('base64');
const response = await fetch(
'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
{ headers: { Authorization: `Basic ${credentials}` } }
);
const data = await response.json();
return data.access_token;
};
Step 3: Initiate an STK Push
STK Push is the most customer-friendly integration. It sends a payment prompt directly to the user's phone:
const stkPush = async (phone, amount, reference) => {
const token = await getOAuthToken();
const timestamp = new Date().toISOString().replace(/[^0-9]/g, '').slice(0, 14);
const password = Buffer.from(
`${shortcode}${passkey}${timestamp}`
).toString('base64');
const response = 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, // Format: 254712345678
PartyB: shortcode,
PhoneNumber: phone,
CallBackURL: 'https://yourdomain.com/api/mpesa/callback',
AccountReference: reference,
TransactionDesc: 'Payment',
}),
}
);
return response.json();
};
Step 4: Handle the Callback
M-Pesa will POST the transaction result to your CallBackURL. Here's how to handle it:
app.post('/api/mpesa/callback', (req, res) => {
const { Body } = req.body;
const { stkCallback } = Body;
if (stkCallback.ResultCode === 0) {
// Payment successful
const metadata = stkCallback.CallbackMetadata.Item;
const amount = metadata.find(i => i.Name === 'Amount').Value;
const mpesaRef = metadata.find(i => i.Name === 'MpesaReceiptNumber').Value;
const phone = metadata.find(i => i.Name === 'PhoneNumber').Value;
// Update your database, fulfill the order, etc.
console.log(`Payment of KES ${amount} received. Ref: ${mpesaRef}`);
} else {
// Payment failed or cancelled
console.log('Payment failed:', stkCallback.ResultDesc);
}
res.json({ ResultCode: 0, ResultDesc: 'Accepted' });
});
Step 5: Going Live
To go live, you need Safaricom's approval. The process typically takes 1β2 weeks:
- Complete your sandbox testing thoroughly β Safaricom will review your implementation
- Submit a go-live request via the Daraja portal with your business details
- Provide your Paybill number or till number (obtained separately from Safaricom)
- Submit your CallbackURL β it must be HTTPS and publicly accessible
- Switch your base URL from
sandbox.safaricom.co.ketoapi.safaricom.co.ke
Common Mistakes to Avoid
- Not formatting phone numbers correctly β always use
254712345678format, not0712345678 - Callback URLs must be HTTPS in production β use ngrok for local testing
- Not handling duplicate callbacks β M-Pesa may send the same callback multiple times
- Not storing the
CheckoutRequestIDβ you'll need it to query transaction status - Token caching β OAuth tokens are valid for 1 hour; cache them to avoid rate limiting
Need Help with M-Pesa Integration?
M-Pesa integration is one of our core competencies at Trabicon. We've done it dozens of times and can have your integration production-ready in days, not weeks. Get in touch and let's talk.