M-PESA is a set of payment capabilities, not one recurring-billing API
A recurring business may use several M-PESA capabilities during one billing lifecycle. The important thing is to understand what each one does, which identifier it returns and where it fits.
PayBill and Buy Goods: where the customer sends money
PayBill is useful when the business needs an account or bill reference alongside the payment. Buy Goods/Till is oriented around merchant purchase payments. Which merchant product is appropriate depends on the business and its Safaricom or PSP arrangement.
For recurring invoicing, PayBill references can be especially useful because the account field can help map the payment to a customer or invoice.
C2B: receiving and validating customer-initiated payments
Safaricom's Customer to Business API supports merchant registration of Validation and Confirmation URLs for C2B payments.
The validation step can be used where enabled to check a payment before it is completed. For a recurring merchant, that can help reject an unknown account reference instead of accepting money that finance cannot identify later.
The confirmation payload exposes fields such as TransID, TransTime, TransAmount, BusinessShortCode and BillRefNumber. Those are useful reconciliation fields, not substitutes for the merchant's own invoice ID.
M-PESA Express: asking the customer to authorize a specific payment
M-PESA Express, commonly called STK Push, lets the merchant initiate a PayBill or Buy Goods payment request to the customer's phone.
The initial response includes a MerchantRequestID and CheckoutRequestID. The merchant should persist the CheckoutRequestID against the payment attempt because it is the key identifier for the STK request lifecycle.
M-PESA Express Query: checking a missing or late STK result
If the STK callback is late or missing, use the M-PESA Express Query API with the CheckoutRequestID to check that STK request.
This is the appropriate status-check path for an unresolved M-PESA Express request before the merchant decides to retry.
Transaction Status: checking a recent M-PESA transaction
Safaricom documents Transaction Status as a secondary reconciliation mechanism when callbacks are not received. It checks a recent business-account transaction using an M-PESA receipt number or an Originator Conversation ID.
That makes it useful for completed or known transactions and for reconciliation. It is not a substitute for M-PESA Express Query when the merchant has only the CheckoutRequestID from an unanswered STK request.
How the pieces fit around one recurring invoice
- Billing system creates the invoice.
- Customer may pay manually to PayBill, producing a C2B transaction with BillRefNumber.
- Or the customer may choose an invoice-linked M-PESA Express request.
- Merchant stores the CheckoutRequestID against the payment attempt.
- Callback reports the result; if it is missing, M-PESA Express Query checks the request.
- Once payment is confirmed, the invoice is closed.
- Transaction Status can support later verification or reconciliation when the necessary transaction identifier exists.
What M-PESA does not decide for the merchant
The payment APIs do not define the merchant's subscription plan, grace period, retry limit, service suspension policy or reconciliation workflow. Those belong to the merchant's billing system.
This is why recurring payment architecture should keep the commercial invoice separate from M-PESA-specific request and transaction identifiers.
Sources
- Safaricom Daraja C2B API: https://developer.safaricom.co.ke/apis/CustomerToBusiness
- Safaricom M-PESA Express API: https://developer.safaricom.co.ke/apis/MpesaExpressSimulate
- Safaricom M-PESA Express Query API: https://developer.safaricom.co.ke/apis/MpesaExpressQuery
- Safaricom Transaction Status API: https://developer.safaricom.co.ke/apis/TransactionStatus



