I'm writing a status mapping for Safaricom's Daraja STK Push (C2B collections), and I have to decide what my code treats as a completed payment. I can only test against the sandbox, where the test MSISDN never answers the prompt, so I have observed the timeout path in detail and the success path not at all.
What I have observed (sandbox, shortcode 174379, September 2026):
- A status query against a pending
CheckoutRequestIDanswersHTTP 200withResultCode 1037,ResultDesc "No response from user."— the payer never answered. - While genuinely in flight, the same query answers
HTTP 200withResultCode 4999, "The transaction is still under processing". ResultCodehas been stable across channels (callback and status query) whileResultDescwording has not, so I branch on the code only.- The callback for the timeout case carries
ResultCodeandResultDescand noCallbackMetadataat all.
My question is about the success case, which I cannot produce:
- Is
ResultCode 0the only value that means the money moved? I treat anything I do not recognise as "unknown, resolve later" rather than as a failure, so I need to know whether a second success code exists that I would be classifying as unknown. - On success, which
CallbackMetadata.Itementries are guaranteed present? SpecificallyMpesaReceiptNumber,Amount,PhoneNumberandTransactionDate— are all four always there, and are they always all present together, or can a success arrive with a subset?
I am asking about what production actually sends, not what the portal documents, because the documentation I have read states the fields without stating which are guaranteed, and the sandbox cannot show me.
If you answer with an example body, please redact it — and note that you should never paste a Daraja
request body anywhere: Password = base64(shortcode + passkey + timestamp), and base64 is not a hash, so
a request body is enough for a reader to recover your passkey. Responses and callbacks are safe once the
receipt number and MSISDN are replaced.