This is a simple tutorial on how to use the Lipa na M-Pesa Online Payment API to make an STK push and prompt users to make payments through M-pesa (C2B payments) using python Flask and Flask-RESTful. It makes the payment process easy for customers by reducing the burden of having to remember the Paybill Number, account number and amount of the transaction in question. This is done by prompting users only to enter their M-pesa PIN. Lipa na M-Pesa Online Payment API is used to initiate a M-Pesa transaction on behalf of a customer using STK Push
Thanks to Peter Njeru for this explanation.
-
The Business sets the data in the request and sends it
-
The API receives the request and validates it internally first, then sends you an acknowledgement response.
-
The API then sends an STK Push request to the target customer's mobile phone. The customer's phone has to be online and unlocked to receive the request.
-
The customer confirms the payment amount via the message displayed on-screen, then either enters the PIN or cancels the request accordingly.
-
The API receives the customer's response. If the response is a negative, it cancels the transaction and sends a corresponding callback to the initiating 3rd party via the predefined callback URL in the initial request, with the info on why the transaction was cancelled. The possible negative responses could be due to the following scenarios:
- An invalid PIN entered by the customer
- Timeout due to customer not entering the PIN within a given time period (usually 1 min 30 secs)
- The customer's SIM card not having the STK applet on it
- A literal request cancellation by the user on their phone
- Another STK transaction is already underway on the customer's phone (no more than one request can be processed at the same time on the same phone)
-
If the PIN is correct, it means the customer accepted the request. The API forwards the transaction to M-Pesa.
-
M-Pesa automatically processes the request, then sends the response back to the API system which then forwards it to you via the callback URL specified in your initial request. Here, the callback can also either be a success or failure, just like a normal C2B transaction.
-
There are no repeat calls for failed callbacks, thus if the API is unable to send the callback to you, you have the Transaction Status Query API to confirm the status of the request, or also confirm via the M-Pesa Org. portal.
The fisrt step is to go to Safaricom Developer's Website and get an account.
Got to Creating sandbox apps.
Creating an app involves setting an app name and choosing the API products for which you will want to use. API products are a business package of the available APIs and the rules for access built around them. For this case make sure to use Lipa na Mpesa online.
Go your dashboard and select your new app. The Keys tab shows the app keys (CONSUMER_KEY & CONSUMER_SECRET), the date they were issued and their expiry period. Sandbox keys do not expire.
Before you make any request you have to get an access_token to authenticate your app. You do this by making an OAuth API request to generate an access_token for your app.
You will need a Basic Auth over HTTPS authorization token.
consumer_key = "YOUR_APP_CONSUMER_KEY"
consumer_secret = "YOUR_APP_CONSUMER_SECRET"
api_URL = "https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials"
# make a get request using python requests liblary
r = requests.get(api_URL, auth=HTTPBasicAuth(consumer_key, consumer_secret))
Make the request and get your access_token from the response body
access_token = r.json()['access_token']
Parameter | Decription | Example |
---|---|---|
BusinessShortCode | The organization shortcode used to receive the transaction. | 174379 |
Pasword | The password for encrypting the request. This is generated by base64 encoding BusinessShortcode, Passkey and Timestamp. | base64.b64encode( "<Business_shortcode> <online_passkey> " ) |
Timestamp | The timestamp of the transaction in the format yyyymmddhhiiss. | 20190617113403 |
TransactionType | The transaction type to be used for this request. Only CustomerPayBillOnline is supported. | "CustomerPayBillOnline" |
Amount | The amount to be transacted. | Integer |
PartyB | Same as businessShortCode | 174379 |
Party A | The phone number sending the funds. | 254721345678 |
PhoneNumber | The phone number sending the funds. | Same as Party A |
CallBackURL | The url to where responses from M-Pesa will be sent to. Expose an end point in your API to confirm transaction status [Completed or Failed] | POST https://myapi.com/payments/confirmation |
AccountReference | Used with M-Pesa PayBills. | Payvill Account Number |
TransactionDesc | A description of the transaction | Any String |
Parameter | Description |
---|---|
MerchantRequestID | Merchant Request ID |
CheckoutRequestID | Check out Request ID |
ResponseCode | Response Code |
ResultDesc | Result description |
ResponseDescription | Response Description message |
ResultCode | Result Code |
{
"MerchantRequestID": "25353-1377561-4",
"CheckoutRequestID": "ws_CO_26032018185226297",
"ResponseCode": "0",
"ResponseDescription": "Success. Request accepted for processing",
"CustomerMessage": "Success. Request accepted for processing"
}
All M-Pesa APIs work asynchronously. When you send a request for a transaction, it is added to a queue and after its processed, M-Pesa sends the response to the registered CallBackURL. This is where you check if the payment was successfull or not.
CheckoutRequestID is used to identify each transaction. For example if you are dealing with orders you can mark the order as pending when initializing the STK push and upon recieving a response(in the CallBackURL) showing the transaction was successfull, you the mark the order as fully paid (Each order will have a unique CheckoutRequestID)
To receive responses, either M-Pesa results or queue timeouts, an HTTP listener will be needed.
For example, if you have an endpoint on your API which you resgistered as your CallBackURL https://myapi.com/payments/confirmation
After a successfull transaction, M-Pesa will send a request to your CallBackURL with the following body.
{
"Body":
{
"stkCallback":
{
"MerchantRequestID": "21605-295434-4",
"CheckoutRequestID": "ws_CO_04112017184930742",
"ResultCode": 0,
"ResultDesc": "The service request is processed successfully.",
"CallbackMetadata":
{
"Item":
[
{
"Name": "Amount",
"Value": 1
},
{
"Name": "MpesaReceiptNumber",
"Value": "LK451H35OP"
},
{
"Name": "Balance"
},
{
"Name": "TransactionDate",
"Value": 20171104184944
},
{
"Name": "PhoneNumber",
"Value": 254727894083
}
]
}
}
}
}