C2B is the Daraja flow that catches paybill and till payments a customer initiates from the M-PESA menu. Safaricom notifies your server via a Confirmation callback after the money moves; you record it against the account reference the customer typed. It is the workhorse for rent, school fees, utility bills and any offline channel where STK Push does not fit. Safaricom's FY26 numbers show 41.68 trillion KES moving on M-PESA rails, most of which is C2B rather than STK Push (Source: Safaricom PLC Annual Report FY2026).
For the endpoint catalogue, see the Daraja API complete guide. For the customer-initiated checkout alternative, see the STK Push integration guide.
C2B versus STK Push, when to use which
| Scenario | Recommended flow |
|---|---|
| E-commerce checkout | STK Push |
| School fees | C2B (parents pay from their own phone, offline) |
| Rent, monthly recurring | C2B |
| Utility bill (KPLC, water, gas) | C2B (long-established habit) |
| Physical retail till | C2B (customer scans QR or types till) |
| Restaurant on-table payment | Either; STK Push if the waiter has a POS, C2B if the customer scans |
| SaaS subscription first payment | STK Push |
| SaaS subscription recurring | C2B (STK Push cannot be scheduled) |
Register URL
Before Safaricom can call your Confirmation URL, you must register it. POST to https://sandbox.safaricom.co.ke/mpesa/c2b/v1/registerurl (production: api.safaricom.co.ke) with a Bearer token and this body:
{
"ShortCode": 600988,
"ResponseType": "Completed",
"ConfirmationURL": "https://api.yourdomain.co.ke/mpesa/c2b/confirmation",
"ValidationURL": "https://api.yourdomain.co.ke/mpesa/c2b/validation"
}ResponseType controls the fallback behaviour when your Validation URL is unreachable:
- Completed: Safaricom accepts the payment even if Validation is unreachable. Recommended for most merchants; failure to validate should not lose the sale.
- Cancelled: Safaricom rejects the payment if Validation is unreachable. Only choose this when your business genuinely cannot accept an invalid reference (regulated industries, tax collection).
The Validation callback (optional)
If Safaricom has enabled Validation for your short code (opt-in through Safaricom Compliance), every incoming payment first POSTs to your ValidationURL before the money moves. You reply within 8 seconds to accept or reject:
// Accept
{"ResultCode": 0, "ResultDesc": "Accepted"}
// Reject (customer sees the ResultDesc on their phone)
{"ResultCode": "C2B00012", "ResultDesc": "Invalid account number"}Rejection codes Safaricom recognises: C2B00011 (Invalid MSISDN), C2B00012 (Invalid account number), C2B00013 (Invalid amount), C2B00014 (Invalid KYC), C2B00015 (Invalid short code), C2B00016 (Other error).
The Confirmation callback
This is where you actually record the payment. Sample payload:
{
"TransactionType": "Pay Bill",
"TransID": "TA57ZBCAM3",
"TransTime": "20260901123045",
"TransAmount": "1500.00",
"BusinessShortCode": "600988",
"BillRefNumber": "STUDENT-2045",
"InvoiceNumber": "",
"OrgAccountBalance": "245000.00",
"ThirdPartyTransID": "",
"MSISDN": "254712345678",
"FirstName": "Jane",
"MiddleName": "Wanjiku",
"LastName": "Kamau"
}- TransID is the M-PESA receipt number, 10-character alphanumeric, globally unique. Use it as your idempotency key.
- BillRefNumber is what the customer typed as the account reference. Trust nothing about it; validate before booking to a student, tenant or invoice.
- MSISDN is the customer's phone in 254 format.
- OrgAccountBalance is your paybill balance after the payment (useful for reconciliation dashboards).
The acknowledgement response
After processing the callback, reply with HTTP 200 and this body:
{
"ResultCode": 0,
"ResultDesc": "Confirmation received successfully"
}A plain 200 with an empty body triggers Safaricom to retry the callback, causing duplicates. Every C2B handler must return the structured acknowledgement.
Testing on sandbox
Sandbox provides /mpesa/c2b/v1/simulate so you can trigger fake payments without a real phone:
{
"ShortCode": 600988,
"CommandID": "CustomerPayBillOnline",
"Amount": 100,
"Msisdn": 254708374149,
"BillRefNumber": "TEST-01"
}This endpoint does not exist on production; on production, only real customer payments trigger the callback.
Related reading
- M-PESA for Business hub
- Daraja API complete guide
- STK Push integration
- B2C integration
- M-PESA payment gateways compared
- Daraja API (original integration guide)
- M-PESA charges 2026
- Kenya mobile money statistics 2026
FAQ
What is M-PESA C2B?
C2B (Customer-to-Business) is the Daraja flow where a customer pays your paybill or till using the normal M-PESA menu (Lipa na M-PESA, Paybill or Buy Goods) and Safaricom notifies your server via a Confirmation callback. It is the pattern for rent, school fees, utility bills and any payment where the customer already knows the paybill and account number.
When should I use C2B instead of STK Push?
Use C2B when the customer initiates the payment (walking into a shop and dialling *334#, paying school fees from home, sending rent) or when your channel is offline. Use STK Push when you initiate the payment (e-commerce checkout, on-site invoice, in-app top-up). Many businesses need both.
What is the difference between Validation and Confirmation callbacks?
Validation runs before the money moves: Safaricom asks your server "is this account reference and amount acceptable?" and you reply accept or reject within 8 seconds. Confirmation runs after the money moves: Safaricom tells you "customer X paid amount Y for reference Z" and you record the payment. Validation is opt-in and only enabled for select merchants by Safaricom Compliance.
How do I register the Confirmation URL?
POST to /mpesa/c2b/v1/registerurl with the short code, response type (Completed or Cancelled), Confirmation URL and Validation URL. You only need to call this once per short code per environment. Re-register when the URL changes.
What does Safaricom send in the Confirmation callback?
TransactionType, TransID (the M-PESA receipt number, 10 chars), TransTime, TransAmount, BusinessShortCode, BillRefNumber (the account reference the customer typed), MSISDN (masked phone), FirstName, MiddleName, LastName. Read TransID as the primary key and treat repeats as duplicates.
What if my Confirmation URL is down when the customer pays?
The money still moves; Safaricom retries the Confirmation callback several times over 24 hours. When your endpoint comes back online, you receive the queued callbacks. Design idempotently and query Transaction Status if a customer complains before the retry catches you up.
Do I need HTTPS for C2B callbacks in production?
Yes. Since 2023 Safaricom rejects HTTP callback URLs on production. Let's Encrypt is acceptable; self-signed is not. Sandbox still accepts HTTP for local testing.
Verified 1 September 2026. C2B endpoint paths and callback schema verified against the current Safaricom Daraja portal at developer.safaricom.co.ke. Volume context from Safaricom PLC Annual Report FY2026.
Related reading
Curated external sources we cite. Open in a new tab.
M-Pesa Paybill Calculator
Calculator focused on Paybill transactions specifically.
mpesa.or.ke · calculator
Fuliza for Business Calculator
B2B Fuliza fees for merchants who use Fuliza for Business.
mpesa.or.ke · calculator
M-Pesa Bulk Payments Calculator
B2C bulk-disbursement fees for businesses paying many recipients.
mpesa.or.ke · calculator