M-Pesa at the Point of Sale: How STK-push Works in a Kenyan Till

Published 20 October 2026 5 min read BiznaPOS

Nearly every Kenyan till ends up taking M-Pesa. The difference between a system that handles it and one that merely allows it shows up later, in the daily cash-up, when someone has to prove that the money in the M-Pesa statement matches the sales in the report.

Here is what actually happens on an STK-push, what to ask a POS vendor about reconciliation, and how to keep the drawer honest when a customer pays part cash and part M-Pesa.

What STK-push is, in one paragraph

STK-push is Safaricom’s Daraja API flow that sends a PIN prompt to a customer’s phone from your shop’s shortcode. The till sends the amount and the customer’s number; Daraja returns an immediate response with a CheckoutRequestID; the customer enters their PIN; Safaricom then posts the real result — success or failure, plus an M-Pesa receipt code — to your callback URL, asynchronously, some seconds later.

Two consequences matter for a point of sale:

  • The initial “success” is not payment. It only means the request was accepted. A sale is confirmed by the async callback, and a system that closes the receipt on the first response will book money that never arrived.
  • The callback can be late or missed. Networks fail. A system needs a way to query a still-pending checkout by its CheckoutRequestID and settle it afterwards, or the sale hangs in limbo and someone marks it paid by hand.

PayBill or Buy Goods — pick the one your shortcode is

An STK-push request carries the account type along with the shortcode: CustomerPayBillOnline for a PayBill, CustomerBuyGoodsOnline for a Buy Goods (till number) shortcode. Sending the wrong type fails at Daraja, not at your till, and the error is rarely obvious to whoever is standing at the counter. If you are quoted a “M-Pesa integration”, ask which types it supports and whether the account reference is configurable — on a PayBill, that reference is how you identify which branch or which sale a payment was for.

Sandbox first, then a KES 1 test

Daraja has a sandbox environment with its own credentials and test shortcodes, and a sane rollout uses it: confirm the request shape, the callback delivery and the pending-payment reconciliation against a sandbox before any real money moves. Then do one live transaction for a small amount, in front of the person who does the cash-up, and check the receipt code, the sale record and the M-Pesa statement all name the same transaction. Any vendor who cannot show you that sequence has not integrated M-Pesa; they have switched it on.

Reconciliation: where the 30 minutes go

The mechanic to look for is simple to describe and expensive to retrofit: the payment must be attached to the sale, not to the day.

  • The M-Pesa leg is a payment row against that sale, with the amount, the receipt code and the customer number.
  • The sales report totals M-Pesa separately from cash and card, per till and per shift, so a cashier’s cash-up only has to reconcile the drawer.
  • A pending or failed checkout is visible as pending or failed rather than silently dropped, so a customer’s “I paid, the message came” conversation starts from a record.
  • The daily M-Pesa total equals the statement total for the same shortcodes, with any difference explained by named transactions.

In BiznaPOS, M-Pesa is one of the payment types at the counter alongside cash, card, bank transfer, store credit and loyalty, and it is stored against the sale it belongs to — which is why the till’s cash-up and the group’s sales report can disagree with the drawer and still be traceable to the exact row. See how the payment screen behaves on the shop and pharmacy page and the restaurant and bar page.

Split payments: the case most integrations forget

A guest paying half a bill by M-Pesa and half in cash is not an exception in Kenya; it is Tuesday. The system must record two payment legs on one sale, print both on the receipt and count each into the right drawer column. Anything that forces the cashier to close two separate sales to make the money fit will produce a variance by the end of the shift, and a variance nobody can explain is normally written off as a loss.

What it should cost

M-Pesa at the till should not be a separate module with a separate subscription; it is a property of the payment screen. On BiznaPOS it is in the product from the first day of the trial — see the plans and pricing — and the platform’s own billing uses the same Daraja rails, so the callback handling is exercised on our side every day.

One honest caveat on charges: Safaricom’s transaction fees on a merchant shortcode are between you and Safaricom, and they are charged per confirmed transaction regardless of which POS you use. A vendor promising to remove that cost is describing something else.

Checklist before you sign

  1. Does the STK-push fire from the sale screen, and does the receipt appear against that sale?
  2. Which account types does it support for your shortcode?
  3. What happens if the callback is late — is there a pending list and a re-query?
  4. Are M-Pesa, cash and card totalled separately per till and per shift?
  5. Can one bill be part M-Pesa, part cash, part store credit?
  6. Is any of this an add-on, and what does the add-on cost per month?

Test all six in your own account with your own shortcode credentials before a customer is at the counter: start a free 14-day trial.

Related reading

Payments M-Pesa