paylod
Payments

API reference

Payments

.md

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.

Endpoint
POST https://paylod.dev/functions/v1/collect

Headers

NameTypeRequiredDescription
AuthorizationstringRequiredBearer API key (mp_live_… / mp_test_…).
Content-TypestringRequiredapplication/json.
Idempotency-KeystringOptionalReplay guard. A repeat with the same key and body returns the first response.

Body

FieldTypeRequiredDescription
amountintegerRequiredWhole KES, 1–150000. M-Pesa rejects decimals.
phonestringRequiredKenyan MSISDN in any common form (0712…, 254712…, +254712…). Normalised for you.
accountReferencestringOptionalShown on the handset and the statement. 1–12 chars. Defaults to collect.
descriptionstringOptionalFree-text label, 1–64 chars. Defaults to Payment.
metadataobjectOptionalOpaque key/values stored with the payment. Never inspected, and not returned on /status or the webhook — key your records on paymentId.

Example

Request
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" }
  }'
Response · 202 Accepted
{
  "paymentId": "e69e5c00-8a01-44ed-b003-48e2e86a7c9e",
  "status": "pending",
  "checkoutRequestId": "ws_CO_010720261905029287161380"
}

Errors

StatusWhen
401Missing or invalid API key.
400Malformed JSON, or Daraja credentials not configured for this app / environment.
409Idempotency key reused with a different body.
422Body failed validation (e.g. amount ≤ 0, bad phone).
429Rate limited — per key and per phone number.
502Daraja 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.

Endpoint
GET https://paylod.dev/functions/v1/status/:id

Path

FieldTypeRequiredDescription
idstringRequiredThe paymentId returned by POST /collect.

Example

Request
curl https://paylod.dev/functions/v1/status/e69e5c00-8a01-44ed-b003-48e2e86a7c9e \
  -H "Authorization: Bearer mp_live_YOUR_API_KEY"
Response · 200 OK
{
  "id": "e69e5c00-8a01-44ed-b003-48e2e86a7c9e",
  "status": "success",
  "mpesaReceipt": "UG1F3A1U7J",
  "resultCode": 0,
  "resultDesc": "The service request is processed successfully."
}

Status values

ValueMeaning
pendingThe prompt is out; the customer has not resolved it yet.
successSettled. mpesaReceipt is the M-Pesa receipt number.
failedresultCode / 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.