Daraja STK Push Debugger

Paste any Daraja error code or callback JSON and get a plain-English explanation with a suggested fix.

By FyberPay Engineering: operators running Kenyan ISP infrastructure.

Reviewed

How to use this

  1. Paste your code or payload. Paste a bare error code (e.g. 1032), a Daraja STK callback JSON, or an STK request body into the field above.
  2. Read the plain-English explanation. The debugger identifies which stage of the flow failed: token, prompt delivery, user interaction, or callback receipt: and explains what likely caused it.
  3. Apply the suggested fix. Each result includes a concrete fix: whether to retry, deduplicate your triggers, fix your CallBackURL, or change the phone number format.

How it works

Daraja returns errors at three distinct layers, which is a common source of confusion. The HTTP layer returns status codes (400, 401, 404, 500) with a dotted ResponseCode (e.g. 400.002.05) when your STK Push initiation request is rejected outright. The Response layer returns a dotted code in the synchronous JSON response body (e.g. 500.001.1001 when a subscriber already has a pending prompt). The Result layer returns a numeric ResultCode inside the asynchronous callback Daraja POSTs to your CallBackURL after the customer responds (e.g. 1032 for cancel, 0 for success)1.

This debugger covers all three layers. Paste any of them and it will identify which layer it belongs to, explain what it means, and suggest a fix based on patterns seen across Kenyan ISP deployments. The error catalog is versioned and sourced directly from the Safaricom Daraja developer documentation2.

For STK request body validation, the debugger checks: PhoneNumber is 12 digits starting with 254 (no leading zero or plus sign), CallBackURL is HTTPS and present, and BusinessShortCode is provided. These cover the most common “400.002.05 Invalid request payload” failures.

In a Kenyan ISP context

At Kenyan ISP scale, the three errors operators encounter most are: 1032 (user cancelled): subscribers dismiss the prompt when they don't recognise the payment descriptor; a WhatsApp or SMS nudge with the ISP name and amount before the STK push reduces this significantly. 1019 (transaction expired) spikes in the evening when subscribers are less attentive to their phones; re-triggering after 90 seconds with a follow-up message is the standard mitigation. 500.001.1001 (unable to lock subscriber) is almost always caused by a duplicate trigger from a retry loop that fires before the first prompt resolves; adding an idempotency key keyed to the subscriber's phone and invoice ID eliminates this entirely. FyberPay's billing engine handles all three by default for ISPs using its centralized Paybill integration.

FAQ

What is the difference between a ResultCode and a ResponseCode?
ResponseCode (like 500.001.1001) comes from Daraja's HTTP response to your STK Push initiation request. ResultCode (like 1032) comes inside the callback JSON Daraja POSTs to your CallBackURL after the customer interacts with the prompt. Both can indicate failure, but at different stages of the flow.
Why am I not getting callbacks from Daraja?
The most common reasons are: CallBackURL is not publicly reachable (Safaricom cannot hit localhost or a private IP), CallBackURL uses HTTP not HTTPS, or a firewall is blocking Safaricom's IP range. Verify your endpoint returns a 200 OK to Safaricom's POST request within 30 seconds.
Sandbox vs Production: how can I tell which environment I am in?
Sandbox uses BusinessShortCode 174379 and the base URL api.sandbox.safaricom.co.ke. Production uses your live shortcode and api.safaricom.co.ke. Mixing credentials across environments is the most common cause of 404.001.03 errors.
How we calculate this

The error catalog is a versioned TypeScript object (DARAJA_ERRORS, stamped retrievedAt: '2026-05-17') sourced from the Safaricom Daraja developer portal. Each entry records the error code, its layer (HTTP, ResponseCode, or ResultCode), a plain-English title, the most likely cause, and a concrete fix recommendation.

The parseInput() function dispatches input to one of three branches: a bare code regex (/^[0-9.]{1,15}$/), a JSON path that checks forBody.stkCallback (callback), or a JSON path that checks forBusinessShortCode / PhoneNumber / CallBackURL(request body). Unknown JSON returns unrecognized.

Sources

  1. Daraja API: M-Pesa for Developers · Safaricom PLC · retrieved 2026-05-17
  2. Daraja STK Push API Reference (Lipa na M-Pesa Online) · Safaricom PLC · retrieved 2026-05-17