M-Pesa Daraja API Integration: A Developer's Guide (STK Push, C2B, B2C)
A developer's guide to M-Pesa Daraja API integration in Kenya — OAuth authentication, STK Push, C2B and B2C, handling callbacks, and going to production. From Neurobyte Technologies.
M-Pesa Daraja integration — the short version
Daraja is Safaricom's developer API for M-Pesa. To integrate it you create an app on the Daraja portal to get a Consumer Key and Secret, exchange those for a short-lived OAuth access token, then call the right payment API for your use case: STK Push to prompt a customer to pay, C2B to receive paybill/till payments, or B2C to send money out. Every result comes back asynchronously to a callback URL you host. Get the authentication, the callback handling, and the move from sandbox to production right, and the rest is detail.
This guide walks through each of those pieces from a developer's point of view.
Before you start
Sign up at the Daraja portal (developer.safaricom.co.ke) and create an app. You'll get a Consumer Key and Consumer Secret — these are your credentials. Daraja has two environments: sandbox for testing (with test shortcodes and a test passkey) and production for real money. Build and test everything in sandbox first; the endpoints are identical apart from the base URL and credentials.
You'll also need a publicly reachable HTTPS URL for callbacks. M-Pesa pushes transaction results to your server asynchronously, so localhost won't work — use a tunnel like ngrok during development.
Step 1: Authenticate (OAuth)
Every Daraja call needs a bearer token. You get one by calling the OAuth endpoint with HTTP Basic auth, where the username is your Consumer Key and the password is your Consumer Secret:
GET /oauth/v1/generate?grant_type=client_credentials Authorization: Basic base64(ConsumerKey:ConsumerSecret)
The response gives you an access_token and expires_in (about 3600 seconds). The token lasts roughly an hour, so cache it and refresh on expiry rather than requesting a new one on every call — hammering the OAuth endpoint is a common rookie mistake.
Step 2: Pick the right API
Daraja isn't one API; it's several. Choose by what you're trying to do:
STK Push (M-Pesa Express / Lipa na M-Pesa Online) — you push a payment prompt to the customer's phone and they enter their PIN to approve. This is what you want for checkout flows, where the customer pays you on demand.
C2B (Customer to Business) — the customer initiates payment to your paybill or till number from their own phone. You register a validation and confirmation URL so M-Pesa notifies your system when payments arrive.
B2C (Business to Customer) — you send money out: salaries, refunds, payouts, promotions. This requires extra security (an encrypted initiator credential) because you're moving money outward.
There are also Transaction Status, Account Balance and Reversal APIs for operations and reconciliation.
Step 3: STK Push in practice
STK Push is the most common integration, so here's the shape of it. You POST to:
POST /mpesa/stkpush/v1/processrequest
The key fields are the BusinessShortCode, a Password, a Timestamp, the Amount, the customer's PhoneNumber (in 2547XXXXXXXX format), and your CallBackURL. The Password is generated by Base64-encoding the shortcode, your passkey and the timestamp together:
Password = base64(BusinessShortCode + Passkey + Timestamp) Timestamp = YYYYMMDDHHmmss
The Timestamp used to build the password must match the Timestamp you send in the request — a mismatch is the single most common cause of STK Push failures.
When the request is accepted, you get back a CheckoutRequestID. That's not the payment result — it just means the prompt was sent. The actual result arrives later at your callback.
Step 4: Handle the callback
M-Pesa POSTs the outcome to your CallBackURL. For STK Push, look at the ResultCode: 0 means success; anything else means the payment failed or was cancelled. On success, the CallbackMetadata contains the Amount, the MpesaReceiptNumber (the customer's confirmation code), the TransactionDate and the PhoneNumber.
Three rules for callbacks that save you pain in production: - Always respond quickly with a success acknowledgement so M-Pesa doesn't retry needlessly. - Treat callbacks as untrusted input and validate them; never mark an order paid on the STK Push response alone — wait for the callback (or query the status). - Make your handler idempotent. M-Pesa can deliver a callback more than once, so use the receipt number or CheckoutRequestID to avoid double-processing.
If a callback never arrives (network issues happen), use the STK Push Query endpoint to reconcile the transaction's final status.
Common pitfalls
- Using localhost or HTTP for the callback URL — it must be public and HTTPS. - Wrong phone format — Daraja expects 254 followed by the number, no plus sign or leading zero. - Caching credentials across environments — sandbox and production keys are different. - Forgetting B2C's SecurityCredential, which is your initiator password encrypted with Safaricom's M-Pesa public certificate, not the plain password. - Assuming the synchronous response means payment succeeded. It doesn't — the callback is the source of truth.
Going to production
Moving from sandbox to production means applying for a "Go Live" on the Daraja portal, getting your real shortcode and production passkey, and swapping the base URL and credentials. Before you flip the switch, make sure your callback handling is robust, your reconciliation works, and you've stored secrets securely (never in client-side code or a public repository). Test with small real amounts first.
How Neurobyte helps
Neurobyte Technologies builds and maintains M-Pesa integrations for businesses across Kenya — STK Push checkouts, C2B collections, B2C disbursements, and the reconciliation and security around them. We've handled the edge cases (duplicate callbacks, timeouts, failed disbursements, PCI-style secret handling) so your payments are reliable and auditable from day one.
Need an M-Pesa integration done properly? Book a free consultation: +254 725 722 965 or info@neurobyte.co.ke.
Frequently asked questions
What is the M-Pesa Daraja API?
Daraja is Safaricom's official developer API for M-Pesa. It lets your application accept and send mobile money in Kenya through services like STK Push, C2B and B2C, using OAuth authentication and asynchronous callbacks.
What's the difference between STK Push, C2B and B2C?
STK Push prompts a customer to approve a payment on their phone (best for checkout). C2B receives payments the customer initiates to your paybill or till. B2C sends money out from your business, such as refunds, payouts or salaries.
How long does a Daraja access token last?
About one hour (the response's expires_in is roughly 3600 seconds). Cache the token and refresh it only when it expires, rather than requesting a new one on every API call.
Why is my STK Push failing?
The most common cause is a mismatch between the Timestamp used to build the password and the Timestamp sent in the request. Also check the phone number format (2547XXXXXXXX), that your callback URL is public HTTPS, and that you're using the correct environment's credentials.
Do I need an HTTPS callback URL for M-Pesa?
Yes. M-Pesa delivers transaction results asynchronously to a callback URL that must be publicly reachable over HTTPS. During development, use a tunnel such as ngrok; in production, host it on your secured domain.