Daraja API in Production: Lessons From Processing STK Pushes at Scale

Integrating with M-Pesa's Daraja API is a rite of passage. But in production, network timeouts and user behavior make it messy. Here are our hard-won lessons.

Share
Daraja API in Production: Lessons From Processing STK Pushes at Scale

Integrating with Safaricom’s Daraja API is a rite of passage for every Kenyan developer. The documentation makes it look simple: call an endpoint, get a response, and wait for a webhook.

But in production, things get "interesting."

When you’re processing thousands of M-Pesa STK Pushes (Lipa na M-Pesa Online), you aren’t just dealing with code; you’re dealing with the messy reality of mobile networks, user behavior, and distributed systems.

Here are the hard-won lessons we learned while building the JengaStack payment engine.


1. Idempotency is Your Best Friend

Network timeouts happen. Safaricom might receive your request but fail to send the "Success" response before your client times out. If your system simply retries the call, the customer gets two PIN prompts on their phone. This is the fastest way to lose customer trust.

The Fix: Generate a unique MerchantRequestID in your database before calling Daraja. Use this ID to track the state of the payment. If you need to retry, check the status of that ID first.


2. The Webhook Reliability Gap

You cannot rely on the STK Push response to confirm a payment. The user might close their app or their phone might die. The Callback URL (Webhook) is the only source of truth.

However, webhooks can be delayed or lost.

Our Strategy:

  1. Passive Listen: Wait for the callback.
  2. Active Poll: If no callback arrives within 60 seconds, trigger a Transaction Status Query via Daraja.
  3. Circuit Breaker: If Daraja is reporting high latency, we pause non-essential queries to avoid hitting rate limits.

3. Handling "The User Effect"

The biggest cause of "Failed" transactions isn’t a bug—it’s the user.

  • They forgot their PIN.
  • They have insufficient funds.
  • They just ignored the prompt.

Your logs will be flooded with Request cancelled by user.

The Lesson: Don’t treat these as system errors. Categorize them as "User Events." This keeps your observability clean so you can spot actual API failures (like 503 Service Unavailable) immediately.


The Production Payment Flow

Daraja Production Flow
Daraja Production Flow

4. Security: Encrypt Everything

You are handling sensitive metadata. Even though Safaricom handles the actual PIN, your system knows the customer’s phone number, amount, and business logic.

At JengaStack, we use Zero-Trust Credential Vaults. We never store the Daraja Consumer Secret in plain text in our database. It’s encrypted at rest and only decrypted in-memory during the API handshake.


Final Thought

Fintech engineering in Kenya is about building for the 99.9% reliability case. The "happy path" is easy; it’s the network timeouts, the 2 a.m. maintenance windows, and the edge cases that define your platform’s success.

Stop building fragile flows. Start building resilient fintech.