API reference
Payments
POST /collect to trigger an STK Push and GET /status/:id to read the outcome — the two endpoints that move and read money in.
POST /collect
Initiate an STK Push. The customer gets an M-Pesa prompt on their handset; when they enter their PIN, funds settle directly to your till. Returns immediately with a paymentId — the final result arrives via the hosted callback, which you read back with GET /status/:id or a webhook.
POST https://paylod.dev/functions/v1/collectHeaders
| Name | Type | Required | Description |
|---|---|---|---|
Authorization | string | Required | Bearer API key (mp_live_… / mp_test_…). |
Content-Type | string | Required | application/json. |
Idempotency-Key | string | Optional | Replay guard. A repeat with the same key and body returns the first response. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
amount | integer | Required | Whole KES, 1–150000. M-Pesa rejects decimals. |
phone | string | Required | Kenyan MSISDN in any common form (0712…, 254712…, +254712…). Normalised for you. |
accountReference | string | Optional | Shown on the handset and the statement. 1–12 chars. Defaults to collect. |
description | string | Optional | Free-text label, 1–64 chars. Defaults to Payment. |
metadata | object | Optional | Opaque key/values stored with the payment. Never inspected, and not returned on /status or the webhook — key your records on paymentId. |
Example
curl -X POST https://paylod.dev/functions/v1/collect \
-H "Authorization: Bearer mp_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order_2041" \
-d '{
"amount": 10,
"phone": "254712345678",
"accountReference": "INV-2041",
"description": "Order #2041",
"metadata": { "orderId": "2041" }
}'{
"paymentId": "e69e5c00-8a01-44ed-b003-48e2e86a7c9e",
"status": "pending",
"checkoutRequestId": "ws_CO_010720261905029287161380"
}Errors
| Status | When |
|---|---|
401 | Missing or invalid API key. |
400 | Malformed JSON, or Daraja credentials not configured for this app / environment. |
409 | Idempotency key reused with a different body. |
422 | Body failed validation (e.g. amount ≤ 0, bad phone). |
429 | Rate limited — per key and per phone number. |
502 | Daraja rejected the STK Push (upstream error passed through). |
GET /status/:id
Read a payment's current state — the zero-infrastructure way to get the result, with no webhook receiver needed. If the payment is still pending, paylod runs a live M-Pesa STK Query and settles it on the spot before responding. Scoped to the key's application: another application's payment returns 404.
GET https://paylod.dev/functions/v1/status/:idPath
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Required | The paymentId returned by POST /collect. |
Example
curl https://paylod.dev/functions/v1/status/e69e5c00-8a01-44ed-b003-48e2e86a7c9e \
-H "Authorization: Bearer mp_live_YOUR_API_KEY"{
"id": "e69e5c00-8a01-44ed-b003-48e2e86a7c9e",
"status": "success",
"mpesaReceipt": "UG1F3A1U7J",
"resultCode": 0,
"resultDesc": "The service request is processed successfully."
}Status values
| Value | Meaning |
|---|---|
pending | The prompt is out; the customer has not resolved it yet. |
success | Settled. mpesaReceipt is the M-Pesa receipt number. |
failed | resultCode / resultDesc carry the decoded M-Pesa reason. |
On failure, resultCode is the raw Safaricom code — 1032 cancelled, 1037 timeout, 2001 wrong PIN. All of them are decoded in the error reference.