M-Pesa checkout: what a good flow looks like

Where online stores lose sales between the cart and the Safaricom STK prompt, and the exact UX and backend architecture that closes the gap.

A client listening across a meeting table, a laptop open between them.

In Kenyan e-commerce, the cart-to-payment transition is where revenue evaporates. A customer spends twenty minutes browsing products, adds items to their cart, fills in their delivery location, and taps “Pay with M-Pesa”. Then, the screen displays a generic spinning wheel with no explanation. The customer glances at their phone, nothing happens for fifteen seconds, they assume the checkout crashed, tap the button three more times, and abandon the purchase.

The M-Pesa API itself (Safaricom's Daraja platform) is reliable. What fails is the customer experience built around it. An exceptional checkout flow guides the buyer through every second of the transaction, handles network failures gracefully, and ensures that not a single paid order is lost to a closed browser tab.

The anatomy of a frictionless STK Push flow

A production-grade Lipa Na M-Pesa Online (STK Push) checkout requires four carefully orchestrated steps:

  • 1. Lenient phone number parsing: Kenyan phone numbers are entered in multiple formats: 0712345678, 0112345678 (Airtel/Safaricom 01x series), +254712345678, or 254712345678 with spaces and dashes. Never throw a validation error because a customer typed a leading zero. Your frontend should sanitize, format, and display the number back to them in standardized +254 7XX XXX XXX format.
  • 2. Pre-prompt confirmation: Before triggering the Safaricom API, state the exact amount in KES and the phone number that will receive the prompt. This prevents accidental triggers to stale numbers saved in browser autofill.
  • 3. Active waiting screen with countdown: The moment the lipaNaMpesaOnline request is dispatched, switch the UI to a dedicated waiting modal. Display a 45-second visual countdown timer with prominent instructions: *“A prompt has been sent to your phone. Unlock your handset and enter your M-Pesa PIN to complete payment of KES 2,400.”*
  • 4. Instant visual acknowledgement: When the callback arrives, don't leave the customer guessing. Show a success badge, display the Safaricom M-Pesa confirmation receipt code (e.g. NL74QX91MP), and trigger an instant SMS/WhatsApp order confirmation.

A spinner with no words reads as a broken website. Tell the customer what is happening on their phone screen.

Handling Daraja error codes like a human

Safaricom's Daraja API returns structured numeric ResultCode values in its callback payload. A sloppy checkout dumps raw technical errors or a vague “Payment failed” message. A high-converting checkout translates each error into an immediate, actionable solution:

Daraja ResultCodeAPI MeaningWhat Bad Checkouts ShowWhat High-Converting Flows Show
1032Request cancelled by userTransaction cancelled [Error 1032]“You cancelled the prompt on your phone. Need to change your number or try again?”
1Insufficient M-Pesa fundsTransaction failed: balance low“Your M-Pesa balance was insufficient for this amount. Top up or use Fuliza, then tap Retry.”
1037DS timeout / User unreachableNetwork timeout occurred“We couldn't reach your phone. Ensure your handset is on and unlocked, then tap Retry.”
2001Invalid PIN enteredAuthentication failure“An incorrect M-Pesa PIN was entered. Tap below to send a fresh prompt.”

The fallback: when the STK push never arrives

Even on a perfect day, Safaricom SIM toolkit prompts can suffer latency during national peak hours (such as Friday evenings or holiday sales), or if a customer's phone has “Do Not Disturb” or a locked screen. If the countdown timer hits zero without a callback, your checkout must offer an immediate manual fallback:

  • Display direct Paybill / Buy Goods Till instructions: Show your Business Shortcode (Paybill or Till number), the Account Number (e.g. Order #1042), and the exact amount.
  • Transaction code verification field: Provide an input field: *“Already paid manually? Enter your M-Pesa confirmation code (e.g. NL498X7Z21)”* with a “Verify Payment” button.
  • Server verification endpoint: Your backend queries the Daraja Transaction Status API or matches against incoming C2B payment notifications, confirms the payment within three seconds, and marks the cart fulfilled without manual staff intervention.

Backend architecture: webhooks vs. client polling

The single biggest architectural flaw in rookie M-Pesa integrations is relying on the browser to record payment. A customer receives the prompt, types their PIN, hears the Safaricom SMS chime, and immediately closes their mobile browser to look at the text message. If your website only recorded payment when the browser redirected, that customer was charged, but your database still lists the order as “Unpaid”.

The Golden Rule of M-Pesa Architecture

Never trust the client browser to confirm an order. The authoritative record is Safaricom's asynchronous Webhook Callback hitting your server. Your backend must process the callback, verify the transaction amount and shortcode, enforce idempotency with CheckoutRequestID, and persist the receipt before notifying the frontend via Server-Sent Events (SSE) or polling.

To learn what it costs to engineer a robust, production-grade payment architecture, check out our M-Pesa integration cost guide or explore our M-Pesa and payment engineering services.

Keep reading

All insights
  1. Insight 10SEO8 min read

         

    The three performance metrics Google uses to judge your site's user experience in search results — in plain business words, without developer jargon.

    Read the article
  2. Insight 11Pricing7 min read

          

    A complete walkthrough of the Growth tier as a deliverable contract, not a vague price range, so you know exactly what your business is buying.

    Read the article

Want an answer for your site?

Tell us what you're building and we'll reply within one working day with a flexible quote, or book 20 minutes and ask us directly.

Chat with us