paylod
CLI

Libraries & tools

CLI

.md

Send a real M-Pesa STK Push from your terminal, decode any Daraja result code offline, and forward live webhooks to localhost without ngrok.

The paylod CLI sends a real M-Pesa STK Push from your terminal, decodes Daraja result codes offline, and forwards live webhooks to localhost without ngrok. It talks to the same API documented in the API reference.

Install
npm install -g @paylod/cli

The package is @paylod/cli; the command it installs is paylod.

Or run it without installing:

npx
npx @paylod/cli errors 1032

Node 20 or newer.

Set up

Terminal
paylod init

init signs you in (it opens your browser), lets you pick an application, and mints an API key for this machine. Credentials go into your OS keychain, or a 0600 file under ~/.config/paylod if there is no keychain available.

If you only want to sign in:

Terminal
paylod login
paylod whoami       # who am I, and where is the token stored?

For CI, skip the login entirely and set PAYLOD_API_KEY in the environment. Every data-plane command (collect, status, listen) will use it.

Take a payment

Terminal
paylod collect --phone 254712345678 --amount 100

The customer's phone rings. The CLI polls until the payment settles and prints the outcome — an M-Pesa receipt on success, or a decoded reason on failure.

FlagWhat it does
-p, --phone <msisdn>Customer's number. 0712…, 254712…, +254712… all work.
-a, --amount <kes>Whole shillings. M-Pesa rejects decimals.
-r, --ref <reference>Your own correlation id (invoice/order number), returned on the result. ≤ 12 chars. Shown to the payer only on a Paybill; a Till never displays it.
-d, --description <text>Payment description on the STK prompt. ≤ 64 chars.
--idempotency-key <key>Reuse to retry safely without double-charging.
--no-waitFire the push and exit immediately, without polling.
--timeout <secs>How long to wait for settlement. Default 120.
--env <sandbox|production>Which M-Pesa environment to charge on.
--api-key <key>Use this key instead of PAYLOD_API_KEY or your stored profile.

Look a payment up later, or watch it settle:

Terminal
paylod status e69e5c00-8a01-44ed-b003-48e2e86a7c9e
paylod status e69e5c00-8a01-44ed-b003-48e2e86a7c9e --watch

status decodes the failure reason for you — you never have to look 2001 up in a PDF.

Decode a result code

Offline. No login, no network, no API key.

Terminal
paylod errors 1032          # why did that payment fail?
paylod errors --list        # the whole catalogue
paylod errors 2001 --json   # machine-readable, for your error handler

This is the fastest way to answer "what does 2001 mean" mid-incident. The same catalogue is browsable in the error reference.

4999 and 500.001.1001 decode as pending, not failed — they mean the customer has not entered their PIN yet. The payment is still live and still payable. Do not show a customer a failure on those codes.

Webhooks on localhost, without ngrok

Terminal
paylod listen --forward http://localhost:3000/webhook

listen streams your application's live webhook events and re-POSTs each one to your local server, with the signature intact — so the code you are writing verifies a real signature against a real payload. No tunnel, no public URL, no ngrok.

FlagWhat it does
-f, --forward <url>POST each event to this local URL.
-e, --events <types...>Only forward these types (payment.success, payment.failed).
--print-jsonPrint the full JSON payload of every event.
--secret <whsec>Signing secret. Otherwise taken from your profile, or fetched.
--tolerance <secs>Signature freshness window. Default 300; 0 disables the check.
--skip-verifyDo not verify the HMAC. Debugging only.
--port <port>Local receiver port. Default 4242.

Roll (or fetch) the signing secret with:

Terminal
paylod webhooks secret

Test without spending money

Terminal
paylod simulate --outcome user_cancelled
paylod simulate --interactive

simulate creates a payment in the paylod sandbox and forces an outcome — no Daraja call, no handset, no money. It is how you exercise your failure paths in CI.

OutcomeResult code
approve0
wrong_pin2001
insufficient_funds1
user_cancelled1032
timeout1037

Manage the integration

These commands do everything the dashboard does.

CommandWhat it manages
paylod apps list | create | use | rename | deleteApplications — one per till or paybill.
paylod credsYour Daraja consumer key, secret, shortcode and passkey. Write-only.
paylod keys mint | list | revoke | usepaylod API keys (mp_test_… / mp_live_…).
paylod webhooks list | add | toggle | delete | secretWebhook endpoints.
paylod paymentsBrowse your M-Pesa payments.
paylod orgsOrganizations.

Scripting

Every command takes a global --json flag and prints machine-readable output.

Terminal
paylod collect -p 254712345678 -a 100 --json | jq -r '.mpesaReceipt'

paylod collect exits 5 if the payment is still pending when the timeout expires — which is not a failure, just an unanswered prompt. A non-zero exit on a settled failure carries the decoded reason in the JSON.

Environment variables

VariableWhat it does
PAYLOD_API_KEYMerchant API key. Skips the config file entirely — this is how you run paylod in CI.
PAYLOD_WEBHOOK_SECRETSigning secret for paylod listen.
PAYLOD_API_BASEOverride the API base. Defaults to https://paylod.dev/functions/v1.
PAYLOD_CONFIG_DIRWhere the CLI stores config. Default ~/.config/paylod.
PAYLOD_NO_KEYCHAIN=1Never use the OS keychain; use the 0600 file instead. Useful on headless Linux and in containers.
NO_COLORDisable colour.

mp_live_… keys move real money. Keep them out of shell history and out of committed .env files.

Next

  • Building an app rather than a script? Use the Node SDK.
  • Wiring an AI agent? The MCP server exposes the same capabilities as tools.
  • The HTTP endpoints underneath: API reference.