Every payment integration we've seen built for the Botswana market starts the same way: Stripe or a card gateway goes in first, then someone asks about mobile money in week three. By then, the architecture is already set, and mobile money gets bolted on as a secondary flow with a different UI, different error handling, and half the QA attention. The product ships. Most users quietly abandon checkout.
The assumption baked into most payment libraries
The global payments ecosystem was built around card rails. Stripe, PayPal, Braintree — these tools assume a user has a bank account, a card number, an expiry date, and a CVV. They're excellent products. They're also designed for a different user.
In Botswana, mobile money penetration is high and growing. Orange Money and MyZaka (Mascom) handle a significant share of everyday transactions — airtime, groceries, school fees, rent. A non-trivial portion of the population that uses these services regularly does not have a traditional bank account, or has one they rarely use for digital payments. The mental model for "how do I pay for something on my phone" is a USSD prompt or an app push notification — not a card form.
When you default to card-first, you are not building a payment flow for your actual users. You are building one for a demographic that may not represent the majority of your market.
What treating mobile money as a default actually means
It does not mean removing card support. It means reversing the priority.
In practice, this changes three things:
Architecture first. Mobile money flows are pull-based — the user initiates, the provider sends a prompt to their phone, and they confirm. This is fundamentally different from a card charge. If your backend assumes a synchronous payment confirmation, you'll need to redesign it when mobile money comes in. Build for async payment states from day one: pending, confirmed, failed, expired. Every payment method then fits into this model cleanly, including cards.
The checkout UI. Most card-first UIs open with a form — card number, expiry, CVV. For mobile money, the input is a phone number. Showing a card form first and burying mobile money under a "more options" link is not neutral design. It signals who the product was built for. Lead with phone number input. Let the user select their provider. The card option sits alongside it, not above it.
Error handling and edge cases. Mobile money has failure modes that card integrations don't. A user might ignore the USSD prompt. Their balance might be insufficient. The provider request might time out. These need explicit handling — retry logic, expiry windows, clear user messaging — not a generic "payment failed" screen that was written for a declined card.
Providers like DPO Group and Peach Payments offer APIs that support both Orange Money and MyZaka alongside card rails. The integration effort is comparable. The decision to deprioritise it is rarely technical — it's a habit imported from a different market.
The Practical Checklist of payment integration
Before writing a line of payment code for a Botswana product, answer these:
- What percentage of your target users have a bank-linked card they use for online payments? Validate this — do not assume.
- Is your payment state model async-first? If not, redesign it before touching any provider SDK.
- Does your checkout UI lead with phone number or card number? If card, ask why.
- Have you mapped the full failure flow for a timed-out mobile money request? If not, do it before QA.
- Are Orange Money and MyZaka covered under the same error handling and logging as your card gateway? If they're treated differently in the code, they'll be treated differently in the product.
Mobile money is not a feature request from a niche user segment. In Botswana, it is the primary mental model for digital payment. Build accordingly from the start, or budget for the rework.
