Skip to content
M-PESA for Business

M-PESA Daraja API Complete Guide (2026): endpoints, auth, errors

Complete Daraja reference for 2026. OAuth, endpoints, rate limits, IP whitelisting, and the errors you hit in production.

DW
by Reviewed by Michael Mwangi
14 min read Updated 1 September 2026Verified 01 Sept 2026

Daraja is Safaricom's official REST API for M-PESA. You register at developer.safaricom.co.ke, get a Consumer Key and Consumer Secret, exchange them for an OAuth token, and then call the endpoint catalogue: STK Push (checkout), C2B (paybill / till receipts), B2C (payouts), Account Balance, and Transaction Status. Safaricom processed KShs 41.68 trillion in M-PESA volume in FY26 across 40.99 million customers (Source: Safaricom PLC Annual Report FY2026), so Daraja is the plumbing under every modern Kenyan payment integration.

This is the complete reference. For the shorter integration walkthrough that predates this guide, see the original Daraja API integration guide (still current for the Shopify / WooCommerce plugin path).

What Daraja actually is

Daraja (Swahili for "bridge") is a set of REST endpoints hosted by Safaricom that expose M-PESA operations to developers. Daraja 2.0 launched in 2018 as the modern replacement for the older SOAP-based G2 gateway. Every endpoint returns JSON, uses OAuth 2.0 bearer tokens, and follows an asynchronous callback pattern: you POST a request, Safaricom returns a synchronous acknowledgement, then the customer-facing action completes and Safaricom POSTs the final result to a callback URL you own.

Sandbox versus production

AspectSandboxProduction
Base URLsandbox.safaricom.co.keapi.safaricom.co.ke
CredentialsIssued instantly on app creationIssued after Go-Live approval (1 to 3 business days)
Test short code174379 (STK Push), 600xxx (C2B)Your assigned paybill or till
Test PIN174379 uses PIN 1234 on test numbers 254708374149Real customer PIN
Money movesNo, simulated onlyYes, real KES
Callback URL rulesHTTP or HTTPS, any hostHTTPS only, valid certificate, publicly reachable

Authentication: OAuth token exchange

Every Daraja call needs a Bearer token in the Authorization header. You get that token by making a Basic-Auth GET against the OAuth endpoint with your Consumer Key and Consumer Secret as the username and password. The token is valid for 3599 seconds (about 1 hour). Cache it.

Sandbox: https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials

Production: https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials

Node.js OAuth token exchange

// Node.js 20+, native fetch
const consumerKey = process.env.MPESA_CONSUMER_KEY;
const consumerSecret = process.env.MPESA_CONSUMER_SECRET;
const auth = Buffer.from(`${consumerKey}:${consumerSecret}`).toString('base64');

const res = await fetch(
  'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
  { headers: { Authorization: `Basic ${auth}` } }
);
const { access_token, expires_in } = await res.json();
// Cache access_token for (expires_in - 60) seconds.

Python OAuth token exchange

import base64, requests, os
key = os.environ['MPESA_CONSUMER_KEY']
secret = os.environ['MPESA_CONSUMER_SECRET']
auth = base64.b64encode(f"{key}:{secret}".encode()).decode()

r = requests.get(
    'https://sandbox.safaricom.co.ke/oauth/v1/generate',
    params={'grant_type': 'client_credentials'},
    headers={'Authorization': f'Basic {auth}'},
    timeout=10,
)
token = r.json()['access_token']

PHP OAuth token exchange

<?php
$auth = base64_encode(getenv('MPESA_CONSUMER_KEY') . ':' . getenv('MPESA_CONSUMER_SECRET'));
$ch = curl_init('https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Basic ' . $auth]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch), true);
$token = $response['access_token'];

The endpoint catalogue

EndpointPathPurpose
OAuth/oauth/v1/generateExchange Consumer Key + Secret for a Bearer token
STK Push/mpesa/stkpush/v1/processrequestTrigger a payment prompt on the customer's phone
STK Query/mpesa/stkpushquery/v1/queryQuery the status of an STK Push request
C2B Register URL/mpesa/c2b/v1/registerurlRegister Confirmation and Validation URLs for a paybill or till
C2B Simulate/mpesa/c2b/v1/simulateSandbox-only: simulate a customer payment
B2C/mpesa/b2c/v1/paymentrequestPay money out to a customer M-PESA number
Account Balance/mpesa/accountbalance/v1/queryQuery the balance on a paybill, till or B2C float
Transaction Status/mpesa/transactionstatus/v1/queryLook up the status of any M-PESA transaction by ID
Reversal/mpesa/reversal/v1/requestReverse a completed C2B or B2C transaction
Tax Remittance/mpesa/b2b/v1/remittaxRemit taxes (KRA) from a business account

For per-endpoint walkthroughs see the sibling guides in this cluster:

Rate limits

Safaricom does not publish exact numbers, but the following limits are consistent across production integrations in 2026:

  • OAuth token: approximately 300 requests per minute per Consumer Key.
  • STK Push: approximately 100 requests per minute per short code.
  • C2B Register URL: single-shot per short code, not rate-limited (call once at deploy).
  • B2C: throttled to your paid-out daily limit; a busy PSP hits it before rate limits bite.
  • Callback traffic (inbound to you): no explicit limit from Safaricom; size for your own peak.

IP whitelisting and callback security

Callbacks are the security-critical path in Daraja. Safaricom will POST payment results to a URL you own; a naive endpoint that accepts any POST as authoritative can be spoofed by an attacker sending fake "successful payment" JSON. Recommended controls:

  1. HTTPS with a valid certificate. Safaricom rejects HTTP callbacks in production. Let's Encrypt is fine; self-signed is not.
  2. Whitelist Safaricom source IPs. Safaricom's callback traffic comes from a small set of IPs in their AS37061 range. Restrict inbound at your firewall or your reverse-proxy layer.
  3. Validate the payload structure and correlate the CheckoutRequestID.Every callback carries a request ID you generated on the outbound POST. If the ID does not match a pending request in your database, drop the callback.
  4. Rate-limit and log every callback. Even legitimate callbacks can be replayed by Safaricom on network glitches; make your handler idempotent.

Common errors and fixes

CodeMessageFix
400.002.02Bad Request - Invalid PhoneNumberFormat as 2547XXXXXXXX or 2541XXXXXXXX (no plus, no leading zero)
401.002.01Invalid Access TokenToken expired; request a new one and retry
404.001.03Invalid Access Token / URL not foundYou are calling production with sandbox credentials, or vice versa
500.001.1001Unable to lock subscriber, a transaction is already in processWait 30 seconds; the customer has an open STK prompt
500.001.1032Request cancelled by userCustomer pressed cancel on the STK prompt; treat as failure and prompt to retry
500.002.1001Internal server errorSafaricom-side; log and retry with backoff
2001The initiator information is invalidB2C initiator name or security credential is wrong; regenerate credential

Going live checklist

  1. Build and load-test on sandbox against the test short code and test PIN.
  2. Prepare production callback URLs (HTTPS, publicly reachable, HTTP 200 in under 5 seconds).
  3. Submit the Go-Live request at developer.safaricom.co.ke with your paybill / till, callback URLs and settlement bank.
  4. Once Safaricom issues production Consumer Key and Consumer Secret, replace the sandbox environment variables.
  5. Run one KES 10 end-to-end payment on production to confirm callbacks land and settle.
  6. Roll out to real traffic; monitor callback latency and STK success rate as your first two SLOs.

FAQ

What is the difference between Daraja and the M-PESA API?

Daraja is the M-PESA API. Safaricom launched Daraja 2.0 in 2018 as the modern REST replacement for the older SOAP G2 gateway. Every current integration (STK Push, C2B, B2C, Balance, Transaction Status, B2B) is exposed through Daraja endpoints on api.safaricom.co.ke (production) and sandbox.safaricom.co.ke (sandbox).

How do I get Daraja credentials?

Register at developer.safaricom.co.ke, create an app, and Safaricom issues a Consumer Key and Consumer Secret for the sandbox instantly. For production, submit a Go-Live request with your paybill or till short code, callback URLs and settlement bank account. Production credentials typically arrive within 1 to 3 business days.

How long does the Daraja OAuth token last?

One hour (3599 seconds). Cache the token and only re-request when it is close to expiry. Requesting a fresh token on every API call will hit rate limits and slow every checkout by 300 to 500 ms.

Do I need to whitelist IP addresses for callbacks?

Safaricom does not require you to whitelist their IPs, but you should whitelist your own callback URL by only accepting POST requests from the Safaricom IP range and validating the payload structure. Callbacks that pass validation but are not HTTPS will be rejected by Safaricom on production.

What are the Daraja rate limits?

Safaricom does not publish hard numbers, but community-measured limits sit around 100 requests per minute per short code for STK Push, 300 per minute for OAuth token, and unmetered for callback traffic. B2C is throttled harder because Safaricom applies daily payout caps.

Can I use Daraja from a mobile app directly?

No. Consumer Secret and initiator credentials must never live on a client device. Every Daraja call must go through your server. The mobile app talks to your backend; your backend talks to Daraja.

What is the most common Daraja error in production?

Error 500.001.1001 ("Unable to lock subscriber"), which means the customer already has an open STK prompt. Retry after 30 seconds. The second most common is 400.002.02 ("Bad Request - Invalid PhoneNumber"), which means the number is not in the 2547XXXXXXXX or 2541XXXXXXXX format Daraja expects.

Verified 1 September 2026. Volume and customer figures from Safaricom PLC Annual Report FY2026. Endpoint paths and OAuth flow verified against the current Safaricom Daraja portal at developer.safaricom.co.ke.

Related reading

Curated external sources we cite. Open in a new tab.