Date: Oct 15, 2026

Subject: STK Push Explained: Building a Smooth M-Pesa Checkout

STK Push Explained: Building a Smooth M-Pesa Checkout

$ curl -X POST https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest

> Initiating Lipa Na M-Pesa Online request...

> Customer prompt sent to 2547XXXXXXXX

> Waiting for PIN entry...

> Status: PENDING

> Callback expected at: /api/mpesa/callback

$ _

Person checking phone for M-Pesa payment prompt

If you have ever bought anything online from a Kenyan business — a boda ride top-up, a school fee payment, a clinic consultation deposit, a SACCO contribution — you have probably seen that small pop-up on your phone asking you to enter your M-Pesa PIN. That pop-up is STK Push, and it is now the default way Kenyans expect to pay for things online. For business owners and developers, understanding how it works — and where it tends to break down — is the difference between a checkout that feels effortless and one that generates support calls and abandoned carts.

This article walks through what STK Push actually is, how the flow works end to end, and the practical decisions you need to make to build a checkout experience that holds up under real Kenyan conditions — patchy connectivity, shared phones, impatient customers, and the occasional Safaricom API hiccup.

What STK Push Actually Is

STK Push — short for SIM Toolkit Push — is a feature of Safaricom's Lipa Na M-Pesa Online API, part of the broader Daraja developer platform. Instead of asking a customer to dial a USSD code, enter a till or paybill number, type an amount, and confirm manually, your system sends a request to Safaricom's servers, which then "pushes" a payment prompt directly onto the customer's phone through the SIM toolkit menu. The customer sees the amount and the business name, enters their M-Pesa PIN, and the transaction completes — all without them touching a paybill number or leaving your website or app.

From the customer's point of view, it feels instant and native. From your system's point of view, it is an asynchronous process: you send a request, Safaricom acknowledges that the request was received, and then — separately, sometimes seconds later, sometimes after a delay — Safaricom sends your server a callback telling you whether the customer actually paid, cancelled, or let the prompt time out. That separation between "request sent" and "payment confirmed" is the single most important thing to understand about STK Push, because almost every bug and every awkward user experience in M-Pesa checkouts comes from treating it as if it were synchronous.

Why Businesses Prefer It Over Paybill-Only Flows

Before STK Push became common, many small businesses simply displayed a paybill or till number and asked customers to pay manually, then type in a reference code. This works, but it puts the burden of correctness entirely on the customer — wrong reference numbers, underpayments, and "I paid but you didn't receive it" disputes are common. STK Push removes most of that friction because the amount and reference are set by your system in advance, not typed in by the customer. For a school collecting fees, a clinic collecting deposits, or an online shop collecting payment at checkout, this cuts down reconciliation headaches considerably, because each payment arrives already tagged with the order or invoice it belongs to.

How the Flow Works, Step by Step

It helps to walk through the actual sequence of events, because each step is a place where things can go right or wrong.

1. Your Server Initiates the Request

When a customer clicks "Pay with M-Pesa" on your site or app, your backend — not the customer's browser — sends a request to Safaricom's Daraja API. This request includes the phone number, the amount, your shortcode (paybill or till number), a reference, and a callback URL where Safaricom should send the result. This must happen server-side because it requires authenticated credentials that should never be exposed in a mobile app or website front end.

2. Safaricom Pushes the Prompt

Safaricom's systems then send the STK prompt to the customer's phone. This typically happens within a few seconds, but on congested networks or with certain older handsets, it can take longer. Your frontend, meanwhile, should be showing the customer a clear "check your phone" message rather than a spinning wheel with no explanation — more on that below.

3. The Customer Responds (or Doesn't)

The customer enters their PIN, cancels, or simply ignores the prompt until it expires. All three are valid, common outcomes, and your system needs to handle all of them gracefully. A significant share of "failed" checkouts in Kenyan e-commerce are simply customers who got distracted, had the prompt appear while they were driving or in a meeting, or mistyped their PIN and didn't retry.

4. Safaricom Sends a Callback to Your Server

This is the step developers most often get wrong. Safaricom does not tell your frontend directly what happened — it sends a callback to the URL you specified, as a server-to-server request. Your server must receive this callback, verify it, update the order status in your database, and only then can your frontend be informed that payment succeeded or failed. If your callback endpoint is slow, misconfigured, or behind a firewall that blocks Safaricom's servers, the customer may have paid successfully but your system never finds out — a serious and entirely avoidable problem.

Handling the Query API as a Backup

Because callbacks can occasionally be delayed or lost due to network issues on either side, Daraja also provides a transaction status query you can call to ask Safaricom directly whether a given request succeeded. A well-built checkout uses this as a safety net — if no callback has arrived after a reasonable wait, your system queries the status directly rather than leaving the customer in limbo.

Designing the Customer Experience

The technical integration is only half the job. The other half is designing what the customer sees and feels while all of this is happening, because a confusing checkout loses sales regardless of how correct your backend code is.

Set Expectations Immediately

The moment the request is sent, tell the customer clearly: "Check your phone and enter your M-Pesa PIN to complete payment of KES [amount]." Many abandoned transactions happen simply because the customer didn't realise they needed to look at their phone, especially if they're checking out on a desktop browser while the prompt appears on a separate mobile device.

Handle the Waiting Period Honestly

Avoid a blank spinner. Show a countdown or a reassuring message, and be upfront that it can take a short while. If the prompt times out — which happens — give the customer a clear, low-friction way to retry rather than forcing them to restart the entire checkout process from scratch.

Common Failure Messages and What They Mean

Customers will encounter outcomes such as insufficient balance, PIN entry cancelled, or request timed out. Resist the temptation to show a generic "payment failed" message for all of these — translating the actual result into plain, specific language reduces confused customers contacting your support line asking why "the app is broken" when in fact they simply had insufficient funds.

Don't Let One Attempt Be the Only Attempt

Build your checkout so a customer can retry an STK push for the same order without creating a duplicate order or a duplicate invoice. This sounds obvious but is one of the more common bugs in homegrown integrations — each retry should reference the same underlying transaction record, not spawn a new one.

Getting the Backend Right

Idempotency and Reconciliation

Every STK push request and callback should be tied to a unique internal reference that you generate and control, not just Safaricom's transaction identifiers. This matters enormously when you're reconciling your books at the end of the day or month, and it matters for your relationship with KRA and eTIMS reporting obligations, since sales records need to tie cleanly back to actual payments received. Keep a clear, append-only log of every request sent and every callback received, with timestamps — this becomes invaluable both for debugging and for resolving customer disputes.

Security and Credential Handling

Your Daraja API credentials, consumer keys, and passkeys should be stored as environment variables or secrets, never committed to source code or exposed in a mobile app bundle. Your callback endpoint should validate that incoming requests genuinely originate from Safaricom's infrastructure rather than blindly trusting any POST request that arrives at that URL. If you're handling customer phone numbers and transaction data, remember this is personal data under Kenya's data protection framework — the Office of the Data Protection Commissioner expects reasonable safeguards around how you store and process it, so avoid logging full PINs or sensitive payment details in plaintext logs, and limit who on your team can access raw transaction data.

Test Environment vs Production

Daraja provides a sandbox environment for development, which behaves similarly to production but uses test credentials and simulated phone numbers. It's tempting to rush straight to production once a sandbox integration works, but give yourself real time to test with actual phones on actual networks, including deliberately letting prompts time out and cancelling a few to confirm your system handles those paths correctly. The jump from sandbox to live traffic is where most unpleasant surprises surface.

Operational Realities Worth Planning For

Connectivity and Power

Your server-side integration needs to tolerate the realities of East African connectivity — occasional timeouts, slower mobile networks outside major towns, and power interruptions affecting either your infrastructure or the customer's device. Build retries with sensible backoff into your API calls to Safaricom, and make sure your own servers or hosting provider have reasonable uptime guarantees, since a checkout that's down during a customer's one attempt at paying is a lost sale.

Costs and Forex Exposure

If you're building this yourself rather than buying an off-the-shelf payment gateway, remember that Safaricom's transaction charges and any third-party payment aggregator fees are real costs that should be built into your pricing, and these figures do change from time to time — confirm current rates directly with Safaricom or your aggregator rather than relying on older figures you've seen online. If your development tools, hosting, or any third-party payment SDKs are priced in US dollars, factor in shilling exchange rate movement when budgeting, particularly for small businesses on tight margins.

Build, Buy, or Blend

Many SMEs, SACCOs, and schools are better served by a reputable local payment aggregator that has already solved the callback reliability, retry logic, and reconciliation problems, rather than building a direct Daraja integration from scratch. This costs more per transaction but saves significant developer time and reduces the risk of a badly handled edge case costing you a customer's trust. Fintechs and larger platforms with in-house engineering capacity may have good reason to integrate directly, but should budget real time for the operational hardening described above rather than treating it as a quick weekend project.

STK Push has become the expected standard for digital payment in Kenya precisely because, done well, it removes friction for the customer. The technical integration itself is well documented and not especially difficult — the real engineering work is in handling the asynchronous nature of the callback, designing honest and clear customer messaging around waiting and failure, and building the reconciliation discipline that keeps your books, your tax records, and your customers' trust all pointing in the same direction.

Want this handled for you?

We build AI agents and automation for Kenyan businesses — and the infrastructure underneath them. Run the automation scan and find out what's worth building first.

Run the Automation Scan < Back to Blog
SYSTEM INITIALIZATION...

We Engineer Certainty.

GeekforGigs isn't just a consultancy. We are a specialized unit of Cloud Architects and DevOps Engineers based in Nairobi.

We don't believe in "patching" problems. We believe in building self-healing infrastructure that scales automatically.

The Partnership Protocol

We work best with forward-thinking companies tired of manual deployments and surprise AWS bills.

We embed ourselves into your team to automate the boring stuff so you can focus on innovation.

Identify Target Objective

Current System Status?

Where's the manual work happening?

What are you using to manage it today?

> SCAN COMPLETE
AUTOMATION OPPORTUNITY: —

Establish Uplink

Mission parameters received. Enter your details to initialize the request.