Bonaventure OgetoBy Bonaventure Ogeto|

How to Build an E-Commerce Checkout With MoMo in Rwanda

To build an e-commerce checkout with MoMo in Rwanda: (1) build your cart and checkout page, (2) at checkout, collect the customer's MoMo phone number and selected items, (3) send a Request to Pay to the MoMo Collections API, (4) show a waiting screen that tells the customer to check their phone, (5) handle the MoMo callback to confirm payment, (6) display the order confirmation and trigger fulfillment. The critical UX decision is the waiting state between payment request and confirmation, which typically takes 10 to 30 seconds.

The Complete Checkout Flow

Here is the full flow from the customer's perspective, and what your code needs to do at each step.

Step 1: Cart review. The customer reviews their items, quantities, and total. Standard e-commerce. Nothing MoMo-specific here.

Step 2: Payment method selection. The customer chooses MoMo or Airtel Money. Show both options clearly with recognizable branding. If your checkout only supports MoMo, you lose every Airtel Money customer.

Step 3: Phone number entry. The customer enters their mobile money phone number. Validate the format before proceeding. Show which provider is associated with their number prefix (078/079 for MTN, 072/073 for Airtel) as a confirmation.

Step 4: Payment initiation. Your server sends a Request to Pay to the MoMo API (or Airtel Money API). Create an order record in your database with status "pending." Return a reference ID to the front end.

Step 5: The waiting state. This is where most e-commerce checkouts built by developers unfamiliar with mobile money go wrong. The customer's browser shows a waiting screen. A clear message says: "We sent a payment request to your phone. Please check your MoMo and enter your PIN to confirm." A spinner or progress indicator shows that the process is active. The customer picks up their phone, sees the USSD prompt, and enters their PIN.

Step 6: Confirmation. Your server receives the callback from MoMo. If successful, update the order status to "confirmed." The front end polls your server (or uses WebSocket/SSE) to detect the status change and displays the confirmation page. If the callback indicates failure, display a clear error message with the option to retry.

The Waiting State: Where Checkouts Succeed or Fail

The time between "I clicked pay" and "my payment is confirmed" is typically 10 to 30 seconds with mobile money. During this time, the customer is interacting with their phone, not your website. If your website does not communicate this clearly, the customer thinks something is broken.

Good practices for the waiting state:

  • Show a clear, prominent message explaining that the customer should check their phone.
  • Include a visual indicator (animated spinner, progress bar) that communicates "we are waiting for your confirmation."
  • Show a countdown or timeout notice (e.g., "This request will expire in 60 seconds").
  • Provide a "Resend" or "Try again" button that becomes active after the timeout.
  • Do not redirect away from this page. The customer needs to see the confirmation when it arrives.

The front end should poll your server every two to three seconds to check if the callback has been received. When the status changes from "pending" to "successful" or "failed," update the UI immediately. WebSockets or Server-Sent Events are more elegant than polling but add complexity. For most e-commerce sites, polling every few seconds is perfectly adequate.

Handling Payment Failures

Failure is a normal part of mobile money payments. Your checkout must handle these scenarios without confusing the customer:

Timeout: The customer did not confirm within the time limit. Message: "The payment request expired. Please try again." Show a retry button.

Insufficient funds: The customer does not have enough money in their MoMo wallet. Message: "Insufficient funds. Please top up your MoMo account and try again." Do not reveal the customer's balance.

Wrong PIN: The customer entered the wrong PIN. Message: "The payment was not authorized. Please try again and ensure you enter the correct PIN."

Network error: A communication failure between your server and the MoMo API. Message: "We could not process your payment due to a network issue. Please try again in a few minutes."

Callback not received: Your server did not receive a callback within the expected time. Use the transaction status polling endpoint as a fallback. If polling also fails, ask the customer to check their MoMo transaction history and contact support.

For the complete list of MoMo error codes and how to handle each one, see our guide to common MoMo API errors.

Technical Architecture

The minimal architecture for an e-commerce checkout with MoMo:

  • Front end: React (or any framework) handling cart, checkout form, waiting state, and confirmation display.
  • Back end: Node.js with Express handling API calls to MoMo, storing order records, receiving callbacks, and providing status endpoints for the front end to poll.
  • Database: PostgreSQL (or similar) storing orders with payment status, transaction references, and customer details.
  • Callback endpoint: A publicly accessible POST route that MoMo calls when a transaction completes.

Critical security considerations:

  • Never expose your MoMo API credentials to the front end. All API calls go through your server.
  • Validate callback requests to ensure they come from MoMo, not a malicious source.
  • Use HTTPS for all communication.
  • Store transaction references and use them for reconciliation.

This architecture is exactly what McTaba teaches. The Full-Stack course (approximately RWF 1,200,000) covers React, Node.js, PostgreSQL, and deployment. The M-Pesa Integration course (approximately RWF 100,000) adds the mobile money layer. Together, they give you everything needed to build a production checkout like this.

Key Takeaways

  • An e-commerce checkout with MoMo has a fundamentally different UX from Stripe or PayPal. The customer confirms payment on their phone, not in the browser. Your UI must guide them through this two-device flow.
  • The waiting state between payment request and confirmation is the most critical UX element. Customers need clear instructions: "Check your phone for a MoMo prompt and enter your PIN."
  • Handle all failure states gracefully: timeout (customer did not confirm), insufficient funds, wrong PIN, network error. Each needs a clear message and a retry option.
  • Build the order as "pending" when the payment request is sent. Only mark it as "confirmed" when the callback arrives with a success status. Never assume success before the callback.
  • Support both MoMo and Airtel Money at checkout. A significant portion of Rwandan customers use Airtel Money, and excluding them means lost sales.

Frequently Asked Questions

Can I build a MoMo checkout without a back end?
No. Mobile money payments require a server-side component for API calls and callback handling. You cannot securely process MoMo payments from a purely client-side application. At minimum, you need a simple Node.js or Python server.
How long does the MoMo payment confirmation take?
Typically 10 to 30 seconds from when the request is sent to when the callback arrives, assuming the customer confirms promptly. Set a timeout of 60 to 120 seconds in your application to account for slow confirmations.
Should I support both MoMo and Airtel Money at checkout?
Yes. A significant portion of Rwandan customers use Airtel Money. Supporting only MoMo excludes them. Use a payment aggregator for the simplest multi-provider setup, or build both integrations if you need maximum control.

Ready to build real-world apps?

Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.

Apply to the McTaba Marathon