paylod
Quickstart

Get started

Quickstart: your first M-Pesa STK Push

.md

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 and approximately five minutes. The sandbox account is free and immediate. Do one npm install, or make one cURL call from any other stack. You deploy nothing: no callback server and no tunnel.

1. Create an application

In the paylod dashboard, create an application. Create one application for each till or paybill. Give the application a name. You can add a Sandbox environment and a Production environment to the same application.

2. Add your Daraja credentials

On the application's Credentials tab, put in the four values that Daraja gives you:

FieldWhere it comes from
Consumer keyDaraja portal → your app
Consumer secretDaraja portal → your app
ShortcodeYour till / paybill number (174379 in sandbox)
PasskeyDaraja portal → Lipa na M-Pesa Online

paylod encrypts the four values at rest. The four values are write-only: no API, no tool and no dashboard screen reads them back.

3. Copy the callback URL into Daraja

paylod shows you a hosted callback URL on the application's Endpoints & Webhooks tab. Copy the callback URL into the Daraja portal as your Lipa na M-Pesa Online callback URL.

This step replaces the public HTTPS endpoint that you would otherwise host. You write no callback code.

4. Create an API key

On the API Keys tab, create a key. Each key applies to one environment:

  • mp_test_… → Sandbox
  • mp_live_… → Production

paylod shows the key one time only. The key tells paylod which application and which environment to use for a request. Thus you never send a shortcode or a Daraja credential in a request.

The API key is a server-side secret. Never put the API key in a browser, in a mobile app, or in other software that a payer opens.

5. Install the SDK

On Node, add the official client. For all other languages, call the HTTP API directly with cURL. The PHP, Python, Java and Kotlin clients are still in development. The samples below on this page show the interface that these clients will have. Use the language selector in the top-left corner to change all the samples on this page together.

npm install @paylod/node

Put the API key in your environment. Each client reads the API key automatically:

.env
PAYLOD_API_KEY=mp_test_YOUR_API_KEY

6. Send your first STK push

Always pass `idempotencyKey`. Create one idempotency key for each payment attempt. A double-clicked Pay button, a refreshed tab and a retried request are duplicates of one attempt. Duplicates of one attempt then become one prompt and one charge, even when they arrive at the same moment. If you do not pass idempotencyKey, each call is a new charge: two clicks give two prompts and two debits. Do not use the order id or the product id as the idempotency key. A used key replays the old payment, and does not make a new payment. A retry after a wrong M-Pesa PIN is a new charge, and needs a new key. If you omit idempotencyKey, the SDK gives you a warning. Full rules.

import { Paylod } from "@paylod/node";

const paylod = new Paylod(process.env.PAYLOD_API_KEY!);

const outcome = await paylod.collectAndWait({
  amount: 10,
  phone: "0712345678",
  idempotencyKey: attempt.id,    // one key per payment attempt. A double-click cannot charge twice.
  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, and one call.

collectAndWait() sends the STK push. Then collectAndWait() polls until the payment settles. The customer's handset shows the prompt, the customer enters the M-Pesa PIN, and you get an answer. You write no callback server. You refresh no access token. You write no result code table.

A timeout throws PaylodTimeoutError. A timeout does not report status: "failed". An unanswered prompt is not a failed payment, because the customer can still be busy with the M-Pesa PIN. Keep the order open. See Handle the result.

The answer is a PaymentOutcome. The message field is already decoded, and you can show the message field to a customer. The retryable flag tells you if a second charge is safe. A wrong M-Pesa PIN is a business outcome and not a program fault. Thus the SDK returns a wrong M-Pesa PIN as data, and does not throw an error.

paylod puts phone numbers into a standard format for you. Thus 0712345678, +254712345678 and 254712345678 all work.

You do not need a webhook. A poll is a fully supported method, and collectAndWait() polls for you. Add a signed webhook when your server does not wait for a payment. paylod then tells your server about that payment.

If you do not use Node

The SDK is a wrapper around a plain HTTP API. Every language can call the HTTP API directly:

The same call, over HTTP
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: attempt_9f3c1a7e" \
  -d '{ "amount": 10, "phone": "254712345678" }'
Response · 202 Accepted
{
  "paymentId": "e69e5c00-8a01-44ed-b003-48e2e86a7c9e",
  "status": "pending",
  "checkoutRequestId": "ws_CO_010720261905029287161380"
}

Then poll GET /functions/v1/status/{paymentId} until the payment settles. If you call the HTTP API directly, you must write the code that the SDK usually gives you: the poll loop, the idempotency key, and the result code decoder. The API reference shows the full interface.

Next

  • Every method, option and error class: Node SDK.
  • Do you prefer the terminal? The CLI sends the same STK push in one command.
  • Do you prefer a webhook instead of a poll? Handle the result describes signed webhooks.
  • Test the failure paths first: Test in sandbox.
  • Are you ready for real money? Go live.