STK Push
By the end of this track you can charge a phone and confirm the result.
0/4 finished
Step 1
The idea
STK Push (M-Pesa Express) sends a PIN prompt to the customer's phone. You send the phone, amount, shortcode, an account reference (your order number) and a password: base64 of shortcode + passkey + timestamp, with the timestamp in East Africa Time.
Step 2
How it works
1. Build the password
The password is base64 of shortcode + passkey + timestamp. The timestamp is YYYYMMDDHHmmss in East Africa Time (UTC+3), whatever timezone your server runs in. Send the same timestamp in the request.
from datetime import datetime, timedelta, timezoneimport base64eat = timezone(timedelta(hours=3))timestamp = datetime.now(eat).strftime("%Y%m%d%H%M%S")password = base64.b64encode(f"{shortcode}{passkey}{timestamp}".encode()).decode()2. Send the request
POST to /mpesa/stkpush/v1/processrequest with your Bearer token. For a Paybill, use CustomerPayBillOnline with PartyB set to the Paybill. For a Till, use CustomerBuyGoodsOnline: BusinessShortCode is the store number the passkey belongs to and PartyB is the Till number. AccountReference is what the customer sees, so use your order number (12 characters at most); TransactionDesc is 13 at most.
{ "BusinessShortCode": "174379", "Password": "<base64 password>", "Timestamp": "20261029143012", "TransactionType": "CustomerPayBillOnline", "Amount": 10, "PartyA": "2547XXXXXXXX", "PartyB": "174379", "PhoneNumber": "2547XXXXXXXX", "CallBackURL": "https://your-domain.example/callbacks/stk", "AccountReference": "ORDER1042", "TransactionDesc": "Order 1042"}3. The customer approves
The phone shows the amount and your business name. The customer enters their PIN, cancels, or ignores it. Meanwhile you have the acknowledgement from lesson F4 with a CheckoutRequestID.
4. The success callback
On success, the callback carries CallbackMetadata: the amount, the M-Pesa receipt number, the transaction time and the phone. Check the amount matches what you asked for before you mark the order paid.
{ "Body": { "stkCallback": { "MerchantRequestID": "29115-34620561-1", "CheckoutRequestID": "ws_CO_29102026143012345678", "ResultCode": 0, "ResultDesc": "The service request is processed successfully.", "CallbackMetadata": { "Item": [ { "Name": "Amount", "Value": 10 }, { "Name": "MpesaReceiptNumber", "Value": "TJT4XXXXXX" }, { "Name": "TransactionDate", "Value": 20261029143045 }, { "Name": "PhoneNumber", "Value": 2547XXXXXXXX } ] } } }}Step 3
Try it
Use your own Safaricom number, registered on the Daraja portal, then approve the prompt on your phone.
$ mpesa pay stk 2547XXXXXXXX 10
With the MCP server, ask your agent to use mpesa_stk_push_and_wait
Step 4
Read the response
CheckoutRequestID is the handle for this payment. Then comes the final status and the receipt.
Step 5
Common mistakes
- Building the timestamp in UTC or server time. The password won't match and Daraja rejects it.
- Phone numbers as
07…or+254…. Daraja wants2547XXXXXXXX. - Sending 10.50. Amounts are whole shillings.
- A callback URL on localhost or plain HTTP. Daraja can only reach public HTTPS.
- A long
AccountReference. The prompt fails with1025. - Using the Till number as
BusinessShortCodefor Buy Goods. You get2028.
--key.Go deeper
Why whole shillings only?
Answer in your own words first.
Show the answerHide the answer
Daraja rejects fractions.