Checking whether an M-Pesa transaction completed
How a Kenyan business confirms whether one M-Pesa transaction completed, failed or expired, using Safaricom's Transaction Status API, before paying again.
By Achekam · · 4 min read · For Running a business businesses in Kenya
A field agent rings to say this month's commission has not arrived on her phone. Your system sent the payment, but no result ever came back. Pay her again and you may pay twice; refuse and you may be wrong. What you need is a firm answer about one transaction: did it go through or not?
Safaricom provides a tool for exactly that question. This article explains the Transaction Status API, the transactions it covers, how to read the statuses it returns, and the rule that should govern every "shall we just send it again?" conversation.
The Transaction Status API as a fallback
Safaricom says the Transaction Status API can be used as a secondary reconciliation mechanism when callbacks are not received. To look up a transaction it needs either the M-Pesa receipt number or the Originator Conversation ID of the transaction.
"Secondary" is the right way to think of it. The callback, the message M-PESA sends your system when a transaction finishes, is still the main channel. The status query is what you use when that message is missing or in doubt.
The two identifiers come from different places:
- The M-Pesa receipt number is the code in the confirmation message the customer or recipient receives. For a payment a customer made to you, ask for it.
- The Originator Conversation ID is the identifier your own system attached to a request it started, such as a B2C payout. Safaricom says every B2C request should carry a unique one generated by the business. Store it with every payment you send, or you will have nothing to query by.
Transaction types it can query
Safaricom says the API can query C2B, B2B, B2C, IMT and reversal transactions. In everyday terms that covers payments customers make to your paybill or till, payments between your business and other businesses, payouts from your business to people's phones, and reversals. One tool answers the question for money coming in and money going out.
The three status stages
Safaricom says M-PESA transactions move through three statuses: initiated (pending revalidation), then authorised or pending authorised, then a final status of Cancelled, Declined, Completed or Expired.
What each answer means for the business:
| Status returned | What it tells you | What to do |
|---|---|---|
| Initiated, pending revalidation | The transaction has started but is not settled | Wait, then query again |
| Authorised or pending authorised | It is still moving through M-PESA | Wait, then query again |
| Completed | The money moved | Record it; do not pay again |
| Cancelled, Declined or Expired | It ended without the money moving | A fresh attempt is a new transaction |
The dangerous answers are the middle ones. A transaction that is still pending may yet complete. Sending a second payment while the first is pending is how businesses end up paying twice.
Creating an API initiator
The query is made by an API user, not a person. Safaricom describes the set-up: a Business Administrator first creates a Business Manager on the M-PESA portal, then an API operator with the access channel set to API and the roles it needs, and the Business Manager sets the API user's password.
Give the status-checking user only the roles it needs. A user that can check transactions has no reason to be able to reverse them as well.
How Achekam asks the provider about open payments
In Achekam, a Kenyan business can send an M-Pesa payment prompt to a customer's phone for a shilling invoice, through the business's own Daraja app, and the payment is recorded only after it has been confirmed with Safaricom. A notification alone does not mark an invoice paid.
When the notification never arrives, the payment is still picked up: for M-Pesa, Paystack and Pesapal, Achekam's server asks the provider about open payments on a schedule and while the pay page is open. The customer who paid while your server was briefly unavailable does not end up chased for money they have already paid.
That covers payments Achekam started. Payouts your business sends outside Achekam, such as B2C salary or commission payments, need their own status checks in whatever system sends them; paying staff or customers through M-Pesa B2C explains why.
When to query before paying again
Make these rules part of the finance team's routine:
- A payout with no result: query it by its Originator Conversation ID before anyone considers sending it again.
- A recipient says the money never arrived: query first, then answer.
- A pending status: wait and query again later; do not resend.
- A final failure (cancelled, declined or expired): only now is a new payment the right step.
- A customer says a payment prompt failed: check the invoice and the status before sending another. Achekam lets the same phone be prompted only once a minute, which gives you time to look.
Keep a short log of every status query: the date, the identifier used, the status returned and who asked. When a supplier or employee raises the same payment again months later, the log shows what was known at the time and why a second payment was or was not made. It also shows patterns, such as one integration that regularly loses its results, which point to a fault worth fixing.
Prompts that fail for other reasons are covered in when an STK push fails, and recovering a whole period of missed paybill notifications in recovering M-Pesa payments whose alerts never came.
Safaricom's Transaction Status API page explains how to use the API as a back-up reconciliation check when callbacks are not received, by receipt number or originator conversation ID.
General guidance only, not advice on your own circumstances. Tax and payroll rules change: check the current position with the authority or your adviser.