STK Push
Initiate secure M-Pesa payments using STK Push (Lipa Na M-Pesa Online). This triggers a payment prompt on the user's phone to enter their M-Pesa PIN.
User Story
As an eβcommerce merchant, I want to prompt customers to approve payments on their phones so they can complete purchases quickly and securely using MβPesa STK Push. When a customer checks out, my backend triggers an STK Push request; the customer receives a prompt to enter their MβPesa PIN; once the payment is confirmed via the webhook callback, the order is processed.
- Actors: Merchant, Customer, Developer (integrator)
- When: At checkout or when accepting a customer-initiated payment
- Why: Fast, secure, and familiar payment flow for users with MβPesa
- Outcome: Customer authorizes payment on their phone; merchant receives confirmation through the callback and completes the order.
Parameters Definition
Parameter | Type | Description |
---|---|---|
business_short_coderequired int | Integer | Your PayBill or BuyGoods number. Use 174379 in sandbox environment. |
amountrequired int | Integer | Transaction amount in KES. Minimum: 1. |
phone_numberrequired str | String | Customer's phone number that receives the STK PIN prompt (usually same as party_a). |
callback_urlrequired str | String | HTTPS endpoint to receive payment results. Must be publicly accessible. |
account_referencerequired str | String | Transaction identifier like order ID. Maximum 12 characters. |
transaction_descrequired str | String | Description displayed to user. Maximum 13 characters. |
transaction_typerequired str | String | Type of transaction. Use 'CustomerPayBillOnline' or 'CustomerBuyGoodsOnline'. |
party_arequired int | Integer | Phone number of the customer initiating the payment (payer). |
party_brequired int | Integer | Receiving shortcode (merchant/organization). Usually same as business_short_code. |
passkey str | String | Passkey used in STK Push / password generation. Optional if Password and Timestamp are provided. |
password str | String | Base64-encoded password (shortcode+passkey+timestamp). Optional if Passkey is provided. |
timestamp str | String | Timestamp used when generating the password. Format: YYYYMMDDHHMMSS. |
M-Pesa STK Push Integration
Easily integrate M-Pesa STK Push (Lipa Na M-Pesa Online) into your Python applications using mpesakit. This guide covers both the recommended MpesaClient approach and direct API usage for advanced control.
-
You can choose MpesaClient for a simple facade that handles
token management
,defaults
anderror handling
for you, or use the Direct API (StkPush
,TokenManager
,MpesaHttpClient
) when you need full control overrequest construction
,middleware
, andcustom workflows
. -
Use
MpesaClient
for fast integration and theDirect API
for advanced customization.
For quick and easy integration, use the MpesaClient
which abstracts away token management
and error handling
.
Quick Setup
import osfrom dotenv import load_dotenvfrom mpesakit import MpesaClientfrom mpesakit.mpesa_express import TransactionType # Enum for transaction types (eg. CUSTOMER_PAYBILL_ONLINE, CUSTOMER_BUYGOODS_ONLINE)
load_dotenv()
client = MpesaClient( consumer_key=os.getenv("MPESA_CONSUMER_KEY"), consumer_secret=os.getenv("MPESA_CONSUMER_SECRET"), environment="sandbox",)
# Send STK Pushresponse = client.stk_push( business_short_code=int(os.getenv("MPESA_SHORTCODE")), passkey=os.getenv("MPESA_PASSKEY"), # It can be used instead of Password and Timestamp fields (optional) transaction_type=TransactionType.CUSTOMER_PAYBILL_ONLINE, amount=1, party_a=os.getenv("MPESA_PHONE_NUMBER"), party_b=os.getenv("MPESA_SHORTCODE"), phone_number=os.getenv("MPESA_PHONE_NUMBER"), callback_url="https://example.com/callback", account_reference="Test123", transaction_desc="Test Payment", timestamp="20231201120000", # it exists together with the Password field (optional) password="custom_generated_password" # it exists together with the Timestamp field (optional))
- You can provide either the
Passkey
or bothPassword
andTimestamp
. If you provide thePasskey
, the SDK will generate thePassword
andTimestamp
for you. - The
Password
andTimestamp
fields must coexist since thePassword
is derived from theTimestamp
(Password = shortcode + "your_passkey" + Timestamp
).
Response
Response is an StkPushSimulateResponse
Pydantic object. If you prefer it as a dictionary, you can convert it using:
response_dict = response.model_dump(mode="json") # Convert to dictionary
From here on we are going to use it as an object due to the rich methods it provides. We can check if the request was successful by:
if response.is_successful(): print("Request accepted")else: print(f"Error: {response.error_message()}") # Get error message
Any error in the request will raise an MpesaError
exception, which we can catch and handle appropriately. We will see how to utilize this later on.
Success Response
{"MerchantRequestID": "29115-34620561-1","CheckoutRequestID": "ws_CO_191220191020363925","ResponseCode": "0","ResponseDescription": "Success. Request accepted for processing","CustomerMessage": "Enter your PIN to complete payment"}
- While using the
StkPushSimulateResponse
object, we can access the fields with ease:
print(response.MerchantRequestID) # e.g 29115-34620561-1print(response.CheckoutRequestID) # e.g ws_CO_191220191020363925print(response.ResponseCode) # e.g 0print(response.ResponseDescription) # e.g Success. Request accepted for processingprint(response.CustomerMessage) # e.g Enter your PIN to complete payment
- This is a much cleaner way of accessing the response fields, since we avoid dealing with raw dictionaries that may lead to typos when accessing keys.
A successful response doesn't guarantee payment completion. Monitor your callback URL for the final payment status.
Error Handling
from mpesakit.errors import MpesaApiException
try: response = client.stk_push( business_short_code=int(os.getenv("MPESA_SHORTCODE")), passkey=os.getenv("MPESA_PASSKEY"), transaction_type=TransactionType.CUSTOMER_PAYBILL_ONLINE, amount=1, party_a=os.getenv("MPESA_PHONE_NUMBER"), party_b=os.getenv("MPESA_SHORTCODE"), phone_number=os.getenv("MPESA_PHONE_NUMBER"), callback_url="https://example.com/callback", account_reference="Test123", transaction_desc="Test Payment", ) data = response.model_dump(mode="json")except MpesaApiException as e: err = e.error print("M-Pesa API error:") print(f" Code: {err.error_code}") # e.g AUTH_INVALID_CREDENTIALS print(f" Message: {err.error_message}") # e.g Invalid credentials provided. Please check your consumer key and secret. print(f" HTTP status: {err.status_code}") # e.g 400 print(f" Request ID: {err.request_id}")except Exception as exc: print(f"Unexpected error: {exc}")
- The
MpesaApiException
provides detailed error information including error code, message, HTTP status, and raw response for effective debugging. - Use what you need from the error object to log or handle errors appropriately.
Easier Error Handling with MpesaClientβ
- We can do this to simplify and have efficient error handling and logging with
MpesaClient
:
from mpesakit.errors import MpesaApiException
try: response = client.stk_push( YOUR_PARAMETERS=HERE ) data = response.model_dump(mode="json")except MpesaApiException as e: print(f"M-Pesa API error: {str(e)}")except Exception as exc: print(f"Unexpected error: {exc}")
Next Steps
After initiating STK Push, you'll need to handle the callback response. Learn how to set up webhook endpoints and process payment confirmations.
Related Documentationβ
- π‘ Webhook Setup Guide - Handle payment callbacks
- ποΈ Production Setup - Go live checklist