paylod
Authentication

Get started

Authenticating with the paylod M-Pesa API

.md

API keys, environments, the base URL, idempotency and rate limits — everything every paylod request has in common.

Base URL

Every endpoint is under /functions/v1.

Base URL
https://paylod.dev/functions/v1

API keys

Authenticate every request with a paylod API key as a bearer token.

Header
Authorization: Bearer mp_live_YOUR_API_KEY

Create API keys on the application's API Keys tab. paylod shows an API key once. The API key encodes two things:

  • The application that the request runs against. You therefore never send a shortcode.
  • The environment that the request runs in. You therefore never send a ?sandbox=true flag.
PrefixEnvironmentMoney
mp_test_…SandboxSimulated. Nothing settles.
mp_live_…ProductionReal. The money settles to your till.

Your Daraja consumer key, secret and passkey stay in encrypted storage on the server. They never travel over the network. No endpoint reads them back.

Keep every API key on the server. An API key in a browser or in a mobile app is fully compromised. Treat that API key as public and rotate it. See Secure integration.

Idempotency

POST /collect accepts an Idempotency-Key header. It also accepts an idempotencyKey field in the body. The idempotency key names one payment attempt. Send the idempotency key, and duplicate deliveries of that attempt collapse into a single payment and a single STK Push. A double-click, a refreshed tab, a redelivered job and an internal network retry are all duplicate deliveries.

// The SDK sends an Idempotency-Key on every collect() — pass one per attempt.
const ack = await paylod.collect({
  amount: 10,
  phone: "254712345678",
  idempotencyKey: attempt.id,
});

Make one idempotency key for each attempt, not for each order and not for each product. paylod reserves the idempotency key before it calls Daraja. Ten simultaneous requests with the same key therefore produce exactly one payment and one push. All ten requests return the same paymentId. A key is also spent once you use it. If you key on an order id, a retry of that order replays the failed first attempt. If you key on a product id, every later customer replays the first payment for that product. A retry after a wrong PIN is a new charge and needs a new key.

paylod rejects a reused idempotency key in three cases. All three cases return 409:

ReuseResponse
Same key, different body409. Two different charges collided on one idempotency key. This case is a bug in your code.
Same key, first request still in flight409 with Retry-After. The first request is still in contact with Daraja. Wait, then read the result.
Same key, a previous attempt was interrupted mid-flight against Daraja409 indeterminate. paylod cannot prove that no debit occurred, and paylod does not repeat the call.

Do not retry the indeterminate `409` with the same idempotency key. A timeout is not evidence that the money did not move. paylod therefore does not send the call again. For money, at-most-once is better than at-least-once. Read the payment status first, with GET /status/:id or with your webhook. Then decide. If the payment settled, you are done. If nothing happened, start a new attempt with a new key.

Rate limits

paylod limits the rate of POST /collect for each API key and for each phone number. A burst returns 429 Too Many Requests. Back off when you receive a 429. paylod refuses a 429 before the request reaches Daraja. A rate-limited request does not spend the idempotency key. You can therefore retry with the same Idempotency-Key after a short delay.

Errors

paylod returns conventional HTTP status codes.

StatusMeaning
400The JSON is malformed, or you did not set Daraja credentials for this application and environment.
401The API key is missing or invalid.
404The resource does not exist, or it belongs to another application.
409You reused the idempotency key with a different body. Or the first request is still in flight. Or an interrupted provider call spent the key. The third case is indeterminate: read the status, then retry with a new key.
422The body failed validation. For example, amount ≤ 0, or paylod cannot parse the phone number.
429You reached the rate limit. Back off, then retry.
502Daraja rejected the request. paylod passes the upstream error through.

M-Pesa also has its own result codes: 1032 customer cancelled, 1037 timeout, 2001 wrong PIN. The error reference decodes every one of these codes.