Recovering M-Pesa payments whose alerts never came
Why M-Pesa payment notifications go missing, how Safaricom's Pull Transactions API recovers them within 48 hours, and a daily check for Kenyan businesses.
By Achekam · · 4 min read · For Running a business businesses in Kenya
The customer holds up a phone with the M-PESA confirmation message: paid to your paybill, amount right, account number right. Your system shows the invoice still open. Somewhere between Safaricom and your server, the notification that should have told you about the payment was lost.
For a business taking a steady flow of paybill or till payments, this is not a rare event to be handled by apology. It is an operational gap to close. Safaricom provides the tools to do it, but some of them have to be set up before they are needed.
Why notifications get lost
Safaricom's Daraja documentation explains that M-Pesa APIs are asynchronous: they send their results to the business's CallBackURL or ResultURL some time after the request. If the receiving server is unavailable at that moment, the API gateway logs a 503 error and discards the results.
"Discards" is the word to notice. Safaricom does not hold the notification and try again later. A server restarting for an update, a hosting outage or a network fault at the wrong moment means that particular notification is gone, even though the customer's money arrived safely in your M-PESA account.
Safaricom's two recovery routes
For customer-to-business payments, Safaricom says that where notifications fail, the merchant can use the Pull Transaction API or check the M-PESA Org portal.
The org portal is the manual route: a person logs in, looks at the statement and finds the payment. The Pull Transactions API is the automated one, and it suits a business with enough volume that checking by hand every day is unrealistic.
The Pull Transactions API and its 48-hour window
Safaricom says the Pull Transactions API lets a business query all C2B transactions on its paybill or till number within the last 48 hours, so that it can recover payments whose callbacks were missed and reconcile its records.
The window is the design constraint. A pull that runs once a week will miss most of the week. Schedule it to run at least daily, and more often if your volumes are high, so that every period is covered twice before it falls out of reach. If a pull fails over a long weekend, go to the org portal for the days the API can no longer return.
Registering the short code for pull
Safaricom says the short code must first be registered once through the Register Pull endpoint, and that only a short code that is live in production, with an existing C2B API integration, can use Pull Transactions.
That rules out testing this in the sandbox and switching it on later as an afterthought. Plan for it as part of going live: once the short code is in production and its C2B integration is working, register it for pull straight away, before the first missed notification rather than after it.
Paging through the results
Safaricom says the query takes a start date, an end date and an offset value starting from 0 for paging. Each result carries the transaction's M-PESA ID, date, customer number, type, bill reference and amount. A response code of 1000 means transactions were fetched; 1001 means none were available for the period.
In practice the integration asks for the first page at offset 0, then moves the offset on and asks again until no more transactions come back. Each result is then matched against what the business already knows:
- the M-PESA ID shows whether this payment has been recorded before;
- the bill reference is the account number the customer typed, usually the invoice number;
- the amount confirms whether the invoice is paid in full or in part.
Achekam's scheduled checks and the allocation list
In Achekam, a Kenyan business can register its paybill or till so that a payment quoting an open shilling invoice number as the account number is receipted automatically, while any other payment waits in a list for a person to allocate.
For payments Achekam is waiting on, such as a payment prompt sent from the invoice's pay page, a lost notification is covered: for M-Pesa, Paystack and Pesapal, the server asks the provider about open payments on a schedule and while the pay page is open, so the payment is still picked up.
A payment the customer makes straight to the paybill, whose notification never reached Achekam, is different: there is no open request for Achekam to ask about. Find it on the org portal statement, or through your own pull integration, and record it as a customer receipt. Achekam lets a business record a payment against one invoice or spread it across a customer's invoices; a part payment leaves the invoice part-paid, and any extra is held on the customer's account. Reconciling M-Pesa takings follows the money on to the bank.
A daily reconciliation
- Clear the list of M-PESA payments waiting for allocation.
- Download yesterday's statement from the org portal, or review the latest pull results.
- For every M-PESA ID on the statement that is not in the books, find the invoice and record the receipt.
- For every receipt in the books that is not on the statement, investigate before the day ends.
- Confirm the pull ran for every hour of the last 48, and go to the org portal for any gap.
- When a customer says they paid, check the M-PESA code first, then reply.
Where you need to confirm one specific transaction rather than a whole period, the Transaction Status API is the tool; see checking whether an M-Pesa transaction completed.
Safaricom's Pull Transactions API page describes how to retrieve the last 48 hours of C2B transactions on a paybill or till, register the short code and page through the results.
General guidance only, not advice on your own circumstances. Tax and payroll rules change: check the current position with the authority or your adviser.