Skip to content

Safaricom M-Pesa

Collect payments with Safaricom M-Pesa

SAFARICOM collects M-Pesa payments with your own Daraja API keys. Centipid Billing sends an STK push to the payer’s phone, the payer enters their M-Pesa PIN, and money settles into your own paybill or till.

Available to ISPs in Kenya (KE), alongside Kopo Kopo, Bank, Paybill, Till, Paystack, PesaPal, Relworx, PayPal, and DPO.

If you do not have Daraja API keys, use Paybill or Till instead — they send the same STK push using the platform’s Daraja credentials, and money still settles into your own paybill or till.

Before you start

  1. Have an active Safaricom paybill or Buy Goods till registered to your business.
  2. Create an app on the Daraja portal and collect its consumer key, consumer secret, and passkey. The passkey is normally emailed to the address registered in Daraja.
  3. Confirm your Daraja app is on production credentials, not sandbox.
  4. Confirm your workspace has a public HTTPS domain — Safaricom must be able to reach it to deliver callbacks, and callback registration is refused without one.

Configure the gateway

  1. Open Settings → Payments → M-Pesa Paybill / Till Number (API keys)

    Select the gateway from the payment marketplace to open its form.

  2. Choose the collection method

    Paybill — the payer pays your paybill and enters an account number. Till — the payer pays your till number (Buy Goods). The rest of the form changes with this choice.

  3. Enter the number and the shortcode

    In paybill mode, Paybill number and M-Pesa shortcode are the same value, so the shortcode field mirrors the paybill and is read-only. In till mode, enter your Till number and the separate Daraja M-Pesa shortcode — the shortcode must be different from the till number, or the switch is refused.

  4. Enter the Daraja credentials

    Consumer key, consumer secret, and passkey are all required and stored as secrets. They are not echoed back into the form after saving.

  5. Register the callback URLs (paybill only)

    See Callback URLs below.

  6. Run a controlled test payment

    Pay a small amount from the captive portal. Verify the STK prompt arrives, the payment lands in the ledger, and the subscriber’s package is applied.

Credentials

Field Required Notes
Collection method Yes Paybill or Till. Decides which fields below apply.
Paybill number Yes, in paybill mode Digits only, at least 4, maximum 20.
Till number Yes, in till mode Digits only, maximum 20.
M-Pesa shortcode Yes Digits only. In paybill mode it must equal the paybill (the form fills it for you). In till mode it is the separate Daraja shortcode and must differ from the till number.
Consumer key Yes Secret. From your Daraja app.
Consumer secret Yes Secret. From your Daraja app.
Passkey Yes Secret. Required for STK push; usually emailed to the address registered in Daraja.

Saving validates the form; it does not prove the credentials work at Safaricom. Only a test payment does that.

Callback URLs

Settings → Payments shows two URLs once your workspace has a domain:

Name Path
Confirmation URL https://<your-host>/api/safaricom/callback
Validation URL https://<your-host>/api/safaricom/validation

In paybill mode the form also shows a Register callbacks button, which registers both URLs with Safaricom’s C2B v2 API for you. It is enabled only when the configuration is saved and complete — while there are unsaved edits it is disabled with “Save your changes before registering callbacks.”

Till mode does not offer registration: Buy Goods STK results return on the callback URL sent with each request, so there is nothing to register.

What the payer must provide

  • A Safaricom phone number, which receives the STK prompt.
  • An account number, in paybill mode. Centipid Billing sends the subscriber’s account reference with the request, so the payer does not type it.

The payer authorizes on their handset, so no Safaricom domain has to be added to the captive walled garden.

How a payment completes

  1. Request

    Centipid Billing requests a Daraja access token and posts the STK push. Both calls run inside the payer’s checkout request and are deliberately short — a 5-second connect timeout, 10 seconds for the token, and 10 seconds for the push acknowledgement — so Safaricom degradation fails fast instead of hanging the captive page.

  2. Persistence

    The acknowledged request is written locally with its MerchantRequestID and CheckoutRequestID. If that write fails, it is retried on a durable queue rather than dropped: the push already reached the payer, so the record has to survive for the callback to be matched to a checkout.

  3. Authorization

    The payer enters their M-Pesa PIN. Money moves into your own paybill or till.

  4. Confirmation

    Safaricom calls back — /api/safaricom/paybill/callback in paybill mode, or /api/till-number/callback in till mode. The callback is processed asynchronously, then the payment is recorded and the subscriber’s package applied.

Troubleshooting

Symptom What it means What to do
“Unable to process payment. Please try again later.” at checkout The token request or the STK push failed, or Safaricom was unreachable within the timeouts above. Check the Daraja consumer key, secret, passkey, and shortcode. Confirm the credentials are production, not sandbox.
“Unable to process payment without a resolved payment user.” Safaricom accepted the push, but the checkout could not be tied to a subscriber. Raise with support with the phone number and the time — the payer may have been charged.
“Safaricom authentication failed. Check the saved consumer key and secret.” when registering callbacks Daraja refused the credentials. Re-copy both values from the Daraja app. Confirm the app is live.
“Safaricom rejected the callback registration. Reason: The saved paybill or shortcode is not recognized…” The shortcode is not one Daraja recognizes for this app. Verify the paybill in Daraja and correct it in Settings → Payments.
“…The callback URLs may already be registered…” Safaricom already holds URLs for this shortcode. Check the active URLs in Daraja, or ask Safaricom to reset them.
Callback registration reports both URLs were rejected Safaricom would not accept one or both URLs. Confirm your workspace domain is a public HTTPS address that resolves from outside your network.
“Safaricom could not be reached. Try again.” The registration request could not connect. Check outbound connectivity from the application host, then retry.
STK prompt never arrives The push was acknowledged but not delivered. Confirm the number is on Safaricom and can receive STK, and that the paybill or till is active.
Payer paid, service not applied The callback did not arrive or did not match a checkout. See Payment troubleshooting.

For every gateway’s fields in one place, see the credential reference.