Skip to content
M-PESA for Business

M-PESA STK Push Integration 2026 (Lipa na M-PESA Online)

Complete STK Push (Lipa na M-PESA Online) integration walkthrough for 2026. Request body, callback body, common errors and the retry patterns that survive production.

DW
by Reviewed by Arnold Ochieng
12 min read Updated 1 September 2026Verified 01 Sept 2026

STK Push (Lipa na M-PESA Online) triggers a payment prompt on a customer's phone. They enter their M-PESA PIN and the money moves; Safaricom POSTs the result to your callback URL. It is the default checkout flow for Kenyan e-commerce and the most reliable channel Daraja offers: no manual paybill entry, no wrong-account errors, no forgotten reference numbers.

This guide covers the request shape, the callback shape, the error codes you will hit in production, and the retry patterns that keep checkout success rates above 92 percent. For the full endpoint catalogue see the M-PESA Daraja API complete guide.

The STK Push flow at a glance

  1. Your server exchanges Consumer Key + Secret for a Bearer token (cache for 1 hour).
  2. Your server POSTs the STK Push request to Daraja.
  3. Daraja returns a synchronous acknowledgement with a CheckoutRequestID.
  4. Safaricom sends an M-PESA prompt to the customer's phone (approximately 90-second timeout).
  5. Customer enters PIN (or cancels or times out).
  6. Safaricom POSTs the final result to your CallBackURL.
  7. Your server reads ResultCode, updates the order, returns HTTP 200.

The STK Push request body

Every STK Push request is a POST to https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest (production: api.safaricom.co.ke) with a JSON body of these fields:

{
  "BusinessShortCode": 174379,
  "Password": "MTc0Mzc5YmZiMjc5ZjlhYTliZGJjZjE1OGU5N2RkNzFhNDY3Y2QyZTBjODkzMDU5YjEwZjc4ZTZiNzJhZGExZWQyYzkxOTIwMjYwOTAxMTIzMDAw",
  "Timestamp": "20260901123000",
  "TransactionType": "CustomerPayBillOnline",
  "Amount": 100,
  "PartyA": 254712345678,
  "PartyB": 174379,
  "PhoneNumber": 254712345678,
  "CallBackURL": "https://api.yourdomain.co.ke/mpesa/callback",
  "AccountReference": "INV-00042",
  "TransactionDesc": "Payment for invoice 42"
}
FieldPurpose
BusinessShortCodeYour paybill (5-6 digits) or till (5-7 digits)
Passwordbase64(BusinessShortCode + Passkey + Timestamp)
TimestampyyyyMMddHHmmss, same value used in the Password concatenation
TransactionTypeCustomerPayBillOnline (paybill) or CustomerBuyGoodsOnline (till)
AmountInteger KES, no decimals
PartyACustomer phone in 254 format
PartyBYour paybill or till (usually equals BusinessShortCode)
PhoneNumberCustomer phone in 254 format (same as PartyA)
CallBackURLYour HTTPS endpoint; Safaricom POSTs the result here
AccountReferenceFree text, max 12 chars, shown on the customer's STK prompt and receipt
TransactionDescFree text, max 13 chars, logged only

The STK Push callback body

Safaricom POSTs the final result to your CallBackURL. Successful callback:

{
  "Body": {
    "stkCallback": {
      "MerchantRequestID": "29115-34620561-1",
      "CheckoutRequestID": "ws_CO_191220191020363925",
      "ResultCode": 0,
      "ResultDesc": "The service request is processed successfully.",
      "CallbackMetadata": {
        "Item": [
          { "Name": "Amount", "Value": 100 },
          { "Name": "MpesaReceiptNumber", "Value": "TA57ZBCAM3" },
          { "Name": "TransactionDate", "Value": 20260901123045 },
          { "Name": "PhoneNumber", "Value": 254712345678 }
        ]
      }
    }
  }
}

Failure callback (customer cancelled):

{
  "Body": {
    "stkCallback": {
      "MerchantRequestID": "29115-34620561-1",
      "CheckoutRequestID": "ws_CO_191220191020363925",
      "ResultCode": 1032,
      "ResultDesc": "Request cancelled by user"
    }
  }
}

Note that CallbackMetadata is only present on ResultCode 0. On failures, only MerchantRequestID, CheckoutRequestID, ResultCode and ResultDesc are guaranteed.

Common STK Push errors and fixes

CodeMeaningFix
0SuccessBook the payment
1Insufficient funds in customer walletPrompt customer to top up and retry
1001Wrong PIN enteredRetry allowed; STK prompt reopens
1019Transaction expiredCustomer took too long; prompt to retry
1032Request cancelled by userCustomer pressed cancel; surface a retry button
1037DS timeout, user cannot be reachedPhone off or out of coverage; ask customer to check phone and retry
2001Wrong initiator informationB2C error accidentally on STK; check request routing
500.001.1001Unable to lock subscriber, transaction in processWait 30 seconds; customer has an open prompt
500.001.1032Request cancelled by userSame as 1032, cancellation at request layer
2006Duplicate detectedYou sent the same request twice within 60 seconds; drop and use the first CheckoutRequestID

Retry patterns that work in production

  1. Idempotency-key every request. Send the same Idempotency-Key on retries so Safaricom does not queue two STK prompts.
  2. Poll STK Query at 5-second intervals. If the callback has not landed within 15 seconds, start polling /mpesa/stkpushquery/v1/query to fetch the current status. Stop when you get a definitive result or after 120 seconds.
  3. Surface a "retry" button after 60 seconds. Do not auto-retry because you cannot tell whether the customer is still deciding.
  4. On 500.001.1001, wait 30 seconds before the second attempt. Safaricom will not open a second prompt until the first clears.

FAQ

What is STK Push?

STK Push, marketed by Safaricom as Lipa na M-PESA Online (LNMO), is the Daraja endpoint that triggers a payment prompt on a customer's phone. The customer enters their M-PESA PIN and the money moves. It is the standard checkout flow for Kenyan e-commerce.

What is the STK Push password and how do I generate it?

The password is a base64 encoding of the concatenation of your BusinessShortCode + Passkey + Timestamp. Timestamp format is yyyyMMddHHmmss. The passkey is issued by Safaricom (sandbox uses a public test passkey; production uses one issued to your app). Regenerate the password on every request because the timestamp changes.

What phone number format does STK Push expect?

2547XXXXXXXX or 2541XXXXXXXX (Airtel is on Daraja for STK too since 2024). No plus sign, no leading zero, no spaces. 0712345678 must be sent as 254712345678. Normalise on your server before every request.

How long does the customer have to enter the PIN?

Safaricom's STK prompt times out after approximately 90 seconds. If the customer does not respond, the callback returns ResultCode 1037 (DS timeout) or 1032 (cancelled). Design your checkout page to poll STK Query at 5-second intervals and surface a "did not receive prompt?" retry after 60 seconds.

Why do I get 500.001.1001 "Unable to lock subscriber"?

The customer already has an open STK Push prompt from a previous request (yours or another business). Safaricom will not open a second prompt. Wait 30 seconds and retry, or show the customer a "please complete or cancel the previous M-PESA prompt on your phone" message.

What is the difference between the synchronous response and the callback?

The synchronous response confirms Safaricom received and queued your request; it returns a CheckoutRequestID. The callback (POSTed to your CallBackURL) is the final result: whether the customer actually paid, cancelled or timed out. Never mark an order paid on the synchronous response. Wait for the callback.

Can I use STK Push with a paybill?

Yes. Set TransactionType to CustomerPayBillOnline, BusinessShortCode to your paybill, PartyB to your paybill, and AccountReference to the customer account (invoice number, meter number, membership ID). For a till, set TransactionType to CustomerBuyGoodsOnline and PartyB to your till number.

How do I handle STK Push callback duplicates?

Safaricom occasionally replays callbacks on network glitches. Make your handler idempotent: index by CheckoutRequestID or MpesaReceiptNumber. If you have already processed the ID, return 200 OK and do not book the payment twice.

Verified 1 September 2026. STK Push endpoint paths and body 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.