Accepting mobile money looks simple in a demo: send a request, the customer approves on their phone, done. In production the hard part is everything in between: delays, duplicates, timeouts and callbacks that arrive late or not at all.
Choose the route: aggregator or direct
A licensed aggregator gives you several networks through one integration and one agreement. Direct integration with each operator can lower fees at high volume but means separate agreements, credentials and maintenance. Decide based on volume, timeline and how much integration work you want to own.
Treat every payment as a state machine
- Pending: request sent, waiting for the customer.
- Successful: confirmed by the operator.
- Failed: declined, cancelled or insufficient balance.
- Unknown: no answer yet. Never assume success or failure.
Your interface and your records should reflect each state honestly. “Unknown” payments need a scheduled status check, not a guess.

Make callbacks idempotent
Operators may send the same callback more than once. Store a unique reference for every transaction and ignore repeats, so a duplicated message can never credit an order twice.
Reconcile every day
Compare your records with the operator or aggregator statement automatically. Exceptions, payments you have that they do not, or the reverse, should land in a queue for a person to review.
Tell the customer what is happening
Show which number will receive the prompt, what amount to approve and what to do if nothing arrives. Clear instructions in Swahili and English cut abandoned payments more than any technical tweak.
A payment integration is finished when your records match the statement, not when the first test succeeds.


