Skip to main content

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

ParameterTypeDescription
business_short_coderequired
int
IntegerYour PayBill or BuyGoods number. Use 174379 in sandbox environment.
amountrequired
int
IntegerTransaction amount in KES. Minimum: 1.
phone_numberrequired
str
StringCustomer's phone number that receives the STK PIN prompt (usually same as party_a).
callback_urlrequired
str
StringHTTPS endpoint to receive payment results. Must be publicly accessible.
account_referencerequired
str
StringTransaction identifier like order ID. Maximum 12 characters.
transaction_descrequired
str
StringDescription displayed to user. Maximum 13 characters.
transaction_typerequired
str
StringType of transaction. Use 'CustomerPayBillOnline' or 'CustomerBuyGoodsOnline'.
party_arequired
int
IntegerPhone number of the customer initiating the payment (payer).
party_brequired
int
IntegerReceiving shortcode (merchant/organization). Usually same as business_short_code.
passkey
str
StringPasskey used in STK Push / password generation. Optional if Password and Timestamp are provided.
password
str
StringBase64-encoded password (shortcode+passkey+timestamp). Optional if Passkey is provided.
timestamp
str
StringTimestamp 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.

Quick Setup

Python
import os
from dotenv import load_dotenv
from mpesakit import MpesaClient
from 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 Push
response = 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)
)

Response

Response is an StkPushSimulateResponse Pydantic object. If you prefer it as a dictionary, you can convert it using:

Python
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:

Python
if response.is_successful():
print("Request accepted")
else:
print(f"Error: {response.error_message()}") # Get error message

Success Response

JSON 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:
Python
print(response.MerchantRequestID) # e.g 29115-34620561-1
print(response.CheckoutRequestID) # e.g ws_CO_191220191020363925
print(response.ResponseCode) # e.g 0
print(response.ResponseDescription) # e.g Success. Request accepted for processing
print(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.

Error Handling

Python
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}")

Easier Error Handling with MpesaClient​

  • We can do this to simplify and have efficient error handling and logging with MpesaClient:
Python
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