How to Automate M-Pesa Payments (STK Push) in Your Platform in Under 5 Minutes
Step-by-step guide to adding M-Pesa STK Push to your app in under 5 minutes with PalPluss — no Daraja setup. cURL, Node.js and webhook code included.
- By
- PalPluss Engineering
- Published
- Reading time
- 5 min
The short answer
- STK Push (Lipa na M-Pesa Online / M-Pesa Express) sends a PIN prompt to the customer's phone so they can pay without typing a paybill or till number.
- With PalPluss, automating STK Push is one authenticated POST to /v1/payments/stk plus a webhook handler — typically under 5 minutes once your account is set up.
- STK Push on PalPluss costs a flat KES 3 for any amount of KES 10 or more; KES 1–9 is free.
STK Push — also called Lipa na M-Pesa Online or M-Pesa Express — is how most Kenyan apps collect money. Your server asks M-Pesa to show a payment prompt on the customer's phone; the customer enters their PIN; you receive the result. No paybill number to copy, no typos in the account number, no screenshots of confirmation messages.
Wiring STK Push directly to Safaricom Daraja involves OAuth tokens, a Base64 password built from your shortcode, passkey and timestamp, a public callback URL and status polling. This guide skips all of that and gets a working STK Push into your platform with PalPluss in five steps.
What you need
- A PalPluss account — register free. New accounts get KES 15 in free tokens.
- A Paybill or Till added as a payment channel in the console, set as default.
- A server that can make HTTPS requests and receive one webhook.
Step 1: Create an API key (30 seconds)
In the console open API Keys and create a key. Copy it immediately — it is shown once. Store it as an environment variable; never ship it to a browser or mobile app.
PALPLUSS_API_KEY=pk_live_xxxxxxxxxxxxxxxxxxxxxxxxStep 2: Fund your service wallet (1 minute)
PalPluss fees are paid from a pre-funded service wallet, deducted when each request is accepted. Top it up by STK Push from the console. At KES 3 per STK Push, KES 300 covers 100 payment requests.
Step 3: Send your first STK Push (1 minute)
curl -X POST https://api.palpluss.com/v1/payments/stk \
-u "$PALPLUSS_API_KEY:" \
-H "Content-Type: application/json" \
-d '{
"amount": 500,
"phone": "0712345678",
"accountReference": "ORDER-1042",
"transactionDesc": "Order 1042",
"callbackUrl": "https://yourapp.com/webhooks/palpluss"
}'The phone receives the M-Pesa prompt within seconds. The API answers immediately with a PENDING transaction — save its transactionId against your order:
{
"success": true,
"data": {
"transactionId": "fa98a577-95ea-4a8f-8467-1fbe74f5d6f4",
"type": "STK",
"status": "PENDING",
"amount": 500,
"currency": "KES",
"phone": "254712345678",
"accountReference": "ORDER-1042",
"transactionFee": 3
}
}Phone numbers are accepted as 07XXXXXXXX, 01XXXXXXXX, +254XXXXXXXXX or 254XXXXXXXXX. Keep accountReference to 12 characters and transactionDesc to 13 — M-Pesa shows them on the statement and the PIN prompt.
Step 4: Do it from your code (1 minute)
Install the official SDK, or call the REST endpoint from any language — it is plain HTTPS with Basic auth.
import { PalPluss } from "@palpluss/sdk";
const palpluss = new PalPluss({ apiKey: process.env.PALPLUSS_API_KEY });
export async function collect(orderId: string, phone: string, amount: number) {
const stk = await palpluss.stkPush({
amount,
phone,
accountReference: orderId,
transactionDesc: "Checkout",
callbackUrl: "https://yourapp.com/webhooks/palpluss",
});
await saveTransactionId(orderId, stk.transactionId);
return stk.status; // "PENDING"
}import os, requests
resp = requests.post(
"https://api.palpluss.com/v1/payments/stk",
auth=(os.environ["PALPLUSS_API_KEY"], ""),
json={"amount": 500, "phone": "0712345678",
"accountReference": "ORDER-1042", "transactionDesc": "Order 1042",
"callbackUrl": "https://yourapp.com/webhooks/palpluss"},
timeout=30,
)
resp.raise_for_status()
print(resp.json()["data"]["transactionId"])Step 5: Confirm payment with a webhook (1 minute)
When the customer pays, cancels or the prompt times out, PalPluss sends a POST to your callbackUrl. Fulfil the order only when status is SUCCESS, and store the mpesa_receipt for reconciliation.
app.post("/webhooks/palpluss", async (req, res) => {
const { transaction } = req.body;
if (transaction.status === "SUCCESS") {
// Idempotent: safe if the same callback arrives twice.
await fulfilOrderOnce(transaction.external_reference, transaction.mpesa_receipt);
}
res.sendStatus(200); // acknowledge quickly
});Production checklist
- Never trust the client for the amount — compute it on your server from the order.
- Make the webhook idempotent — key fulfilment on the transaction ID.
- Handle rate limits — the API allows up to 2 STK requests per phone number per minute (
429 STK_RATE_LIMITED) and 60 requests per minute per API key. Show the customer a friendly “try again in a moment” message. - Watch your success rate — accounts whose recent STK success rate drops below 30% are paused for 30 minutes (
429 TRANSACTION_HEALTH_BLOCKED). Validate phone numbers and avoid sending prompts nobody asked for. - Keep the service wallet funded — requests fail with
402 INSUFFICIENT_SERVICE_BALANCEwhen it runs dry.
PalPluss vs wiring Daraja STK Push yourself
| Task | Daraja direct | PalPluss |
|---|---|---|
| OAuth token fetch and refresh | You | Handled |
| Password = Base64(shortcode + passkey + timestamp) | You | Handled |
| Public callback endpoint for Safaricom | You | Handled — you get a clean webhook |
| Normalising phone formats | You | Handled |
| Transaction records and dashboard | You | Included |
| Abuse and duplicate-prompt protection | You | Included |
Frequently asked questions
What is M-Pesa STK Push?
STK Push (Lipa na M-Pesa Online or M-Pesa Express) is a Safaricom feature that sends a payment prompt to a customer's phone. The customer enters their M-Pesa PIN to approve, and the merchant receives the result automatically.
How fast can I integrate STK Push?
With PalPluss, once your account and payment channel are set up, the integration is one POST request to /v1/payments/stk and a webhook handler — typically under 5 minutes.
How much does STK Push cost on PalPluss?
A flat KES 3 per STK Push for amounts of KES 10 and above, regardless of size. Amounts of KES 1–9 are free. There are no monthly or setup fees.
Do I need a Paybill or Till number?
Yes. Each STK Push is routed through a payment channel — a Paybill or Till — that you add in the PalPluss console. That is the number the customer pays to.
How do I know an STK Push payment succeeded?
PalPluss sends a webhook to your callbackUrl with status SUCCESS and the M-Pesa receipt. You can also fetch GET /v1/transactions/{id}.
Build on PalPluss
M-Pesa collections and payouts in one API. KES 15 in free tokens to start.