Get started
Quickstart
Your first M-Pesa STK Push in five minutes — create an application, add your Daraja credentials, mint a key, and collect a payment.
You need a Safaricom Daraja account (the sandbox is free and instant) and about five minutes. One npm install, and nothing to deploy — no callback server, no tunnel.
1. Create an application
In the paylod dashboard, create an application — one per till or paybill. Give it a name; you can add both a Sandbox and a Production environment to the same application.
2. Add your Daraja credentials
On the application's Credentials tab, paste the four values Daraja gives you:
| Field | Where it comes from |
|---|---|
| Consumer key | Daraja portal → your app |
| Consumer secret | Daraja portal → your app |
| Shortcode | Your till / paybill number (174379 in sandbox) |
| Passkey | Daraja portal → Lipa na M-Pesa Online |
They are encrypted at rest and write-only — no API, tool, or dashboard screen ever reads them back.
3. Paste the callback URL into Daraja
paylod shows you a hosted callback URL on the application's Endpoints & Webhooks tab. Copy it into the Daraja portal as your Lipa na M-Pesa Online callback URL.
That is the entire "host a public HTTPS endpoint" problem, solved. You never write callback-handling code.
4. Mint an API key
On the API Keys tab, create a key. Keys are environment-scoped:
mp_test_…→ Sandboxmp_live_…→ Production
The key is shown once. It identifies which application and environment a request runs against, so you never send a shortcode or a Daraja credential over the wire.
The key is a server-side secret. Never ship it in a browser, a mobile app, or anything a payer can open.
5. Install the SDK
npm install @paylod/nodePut the key in your environment. The client picks it up on its own:
PAYLOD_API_KEY=mp_test_YOUR_API_KEY6. Send your first STK Push
import { Paylod } from "@paylod/node";
const paylod = new Paylod(process.env.PAYLOD_API_KEY!);
const outcome = await paylod.collectAndWait({
amount: 10,
phone: "0712345678",
accountReference: "INV-2041",
description: "Order #2041",
});
if (outcome.paid) {
console.log("Paid:", outcome.receipt); // "UG1F3A1U7J"
} else {
console.log(outcome.message); // already decoded, safe to show a customer
}That is the whole integration. One argument to the constructor, one call.
collectAndWait() sends the STK Push, then polls until the payment settles. The customer's phone rings, they enter their PIN, and you get an answer back. No callback server, no OAuth token to refresh, no result-code table to write.
The answer is a PaymentOutcome: a message you can show a customer, already decoded, and a retryable flag that tells you whether charging again is safe. A wrong PIN is a business outcome, not a crash, so it comes back as data rather than a thrown error.
Phone numbers are normalised for you, so 0712345678, +254712345678 and 254712345678 all work.
A timeout throws PaylodTimeoutError rather than reporting status: "failed". An unanswered prompt is not a failed payment: the customer may still be typing their PIN. Leave the order open. See Handle the result.
You do not need a webhook for this to work. Polling is a first-class path, and collectAndWait() does it for you. Add a signed webhook when you want your server told about payments it is not actively waiting on.
Not on Node?
The SDK is a wrapper over a plain HTTP API — every language can call it directly:
curl -X POST https://paylod.dev/functions/v1/collect \
-H "Authorization: Bearer mp_test_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order_2041" \
-d '{ "amount": 10, "phone": "254712345678" }'{
"paymentId": "e69e5c00-8a01-44ed-b003-48e2e86a7c9e",
"status": "pending",
"checkoutRequestId": "ws_CO_010720261905029287161380"
}Then poll GET /functions/v1/status/{paymentId} until it settles. Going this route means doing yourself what the SDK does for you: the polling loop, the idempotency key, and decoding the result code. The full surface is in the API reference.
Next
- Every method, option and error class: Node SDK.
- Prefer the terminal? The CLI sends the same STK Push in one command.
- Prefer push over poll? Handle the result covers signed webhooks.
- Exercise the failure paths first: Test in sandbox.
- Ready for real money? Go live.