Reference
Use one stable reference per customer order, invoice, or withdrawal for reconciliation.
Start here
Connect your backend to Paylor using API keys, stable references, and signed webhooks.
Pass your secret key in the Authorization header for every server-to-server request. All requests must use HTTPS.
1Authorization: Bearer YOUR_API_KEY2Content-Type: application/json1import axios from 'axios';2 3const PAYLOR_API_KEY = process.env.PAYLOR_API_KEY;4const PAYLOR_BASE_URL = 'https://api.paylorke.com/api/v1';5 6const response = await axios.post(7 `${PAYLOR_BASE_URL}/merchants/payments/stk-push`,8 {9 phone: '254712345678',10 amount: 1000,11 reference: 'ORDER-12345',12 channelId: 'PAYL-XXXXXX',13 description: 'Payment for Service',14 },15 {16 headers: {17 'Authorization': `Bearer ${PAYLOR_API_KEY}`,18 'Content-Type': 'application/json',19 },20 }21);All credentials are available in your merchant dashboard under Developers > API Keys.
| Field | Usage | Example |
|---|---|---|
| Merchant ID | Your unique account identifier used for internal reference. | MERCH-A9X2Z... |
| API Key | Your active secret key (Bearer token). Keep this on your backend only. | pk_xxxxxxxxxxxxxxxx |
| Webhook ID (Secret) | A dedicated secret attached to your API key, shown as “Webhook ID (Secret)” in Developers > API Keys. Used to verify HMAC signatures on callbacks. | 6995fe04a1b2c3d4... |
| Channel ID / Alias | The unique alias of your payment channel (found in Settings). | PAYL-XJ7K2P |
Each API key carries scopes that control what it can do. Grant only what an integration needs. A key with global:* or crypto:* covers all actions in that product.
| Scope | Grants |
|---|---|
payments:create | Initiate STK Push, B2B Express, and (fallback) crypto payments. |
b2c:payout | Send M-Pesa B2C payouts. |
transactions:read | Query and list transactions. |
wallet:read / b2c:read | Read wallet balance and B2C metrics. |
channels:read|create|update|delete | Manage payment channels. |
crypto:create / crypto:read | Create and read USDT (TRC20) payments. |
global:collect | Create Global collections, payment links, webhooks, and settings. |
global:disburse | Create Global withdrawals (disbursements). |
global:read | Read Global wallet, ledger, providers, and listings. |
403 with “Missing API key scope” means the key needs that scope.Use the production API URL for live transactions. A sandbox environment is coming soon.
| Production API | https://api.paylorke.com/api/v1 |
|---|---|
| Sandbox | https://api.paylorke.com/api/v1/sandbox (coming soon) |
Payment creation endpoints support idempotency keys. Sending the same key twice returns the original result instead of creating a duplicate transaction.
1Idempotency-Key: order-12345-attempt-12# also accepted:3X-Idempotency-Key: order-12345-attempt-1Use one stable reference per customer order, invoice, or withdrawal for reconciliation.
Send a unique key per payment attempt and reuse it on network retries. Keys are capped at 180 characters.
Pass a callbackUrl per request or register a webhook endpoint in the dashboard.
429 RATE_LIMIT_EXCEEDED, back off and retry with the same Idempotency-Key.Paylor uses conventional HTTP status codes. Every error response carries the same envelope with a machine-readable code, and validation errors include a per-field details array.
1{2 "message": "Invalid request payload",3 "error": {4 "code": "VALIDATION_ERROR",5 "message": "Invalid request payload",6 "details": [7 {8 "path": "phone",9 "message": "phone is required",10 "code": "custom"11 }12 ]13 }14}| Code | Description |
|---|---|
400 VALIDATION_ERROR | The request body failed validation. The details array lists each invalid field. |
400 INVALID_PHONE_NUMBER | The phone number is not a valid M-Pesa MSISDN. Use international format, e.g. 254712345678. |
400 INVALID_AMOUNT | The amount is outside the allowed range for the endpoint. |
401 UNAUTHORIZED / INVALID_API_KEY | Missing or invalid Bearer token, or the key was revoked. |
402 PAYMENT_REQUIRED | Insufficient wallet balance to process the transaction or fee. |
403 UNAUTHORIZED | The API key is valid but is not authorized for this project or scope. |
404 RESOURCE_NOT_FOUND | The requested transaction, channel, or resource does not exist. |
429 RATE_LIMIT_EXCEEDED | Payment endpoints allow 60 requests/minute; channel management allows 120. |
500 INTERNAL_ERROR | Something failed on the Paylor side. Retry with the same reference and Idempotency-Key. |
Follow these rules to keep your integration reliable in production.
Update orders only from signed webhooks, and always recompute the HMAC signature before trusting a payload.
If a webhook is missed, reconcile with the transaction query endpoint instead of assuming failure.
Rotate API keys periodically and immediately if a key may have been exposed. Old keys are revoked on rotation.