- pending — intent recorded, STK push sent to the customer's handset.
- completed — the rail confirmed payment on its callback. The gateway posts a balanced double-entry journal (debit M-Pesa clearing / credit your wallet / credit fee revenue), your
balance_minor reflects it immediately, and a signed collection.completed webhook is delivered to your endpoint. - failed — cancelled/timed out on the handset or rejected by the rail; a
collection.failed webhook is sent. Nothing is posted.
Rail callbacks are not your webhooks
The M-Pesa rail calls the gateway on internal callback URLs (/v4/callbacks/mpesa/stk/{secret}, /v4/callbacks/mpesa/b2c/{secret}). These are for the rail only — your systems should consume the signed merchant webhooks, never poll rail callbacks.
Fees are applied in basis points per your fee plan and rounded once at posting time — what you see on the webhook is exactly what the ledger holds.