Bonaventure OgetoBy Bonaventure Ogeto|

Going Live on Daraja: The Production Checklist

Going live on Daraja requires a registered Kenyan business, KRA compliance, production API credentials from Safaricom, a valid SSL certificate on your callback URLs, proper error handling, and a reconciliation strategy. Most applications get rejected for incomplete business documentation or invalid callback URLs. Budget 2 to 10 business days for the full approval process.

Before You Apply: Business Requirements

Safaricom does not issue production Daraja credentials to individuals. You need a registered business entity. This catches a lot of solo developers off guard, especially those who built something cool in sandbox and want to launch immediately.

What you need before applying:

  • Business registration certificate from the Registrar of Companies (or eCitizen for sole proprietorships). The business name on the certificate must match what you submit to Safaricom.
  • KRA PIN certificate for the business (not your personal KRA PIN, though you will need that too).
  • National ID or passport of the authorized signatory (the person applying on behalf of the business).
  • A letter of authorization if the person applying is not the business owner or director.
  • An active M-Pesa business account (Paybill or Till Number). You need this before applying for API access. If you do not have one yet, apply through Safaricom Business first.

For sole proprietorships, the process is relatively straightforward. For limited companies, you may also need board resolutions authorizing the API integration. The more organized your paperwork is before you start, the faster the approval process goes.

One important note: if you are building an integration for a client's business, the application must be in the client's name using their business documents. You cannot use your own business credentials to process payments on behalf of another business. This is a compliance requirement from the Central Bank of Kenya.

Getting Your Production Credentials

Once your business documentation is in order, you apply for production credentials through the Daraja developer portal.

Step 1: Log in to the Daraja portal at developer.safaricom.co.ke with the same account you used for sandbox development.

Step 2: Navigate to "Go Live" (or "Production" depending on the current portal UI). Fill in your business details and upload the required documents.

Step 3: Specify which APIs you need. Select only the ones your application actually uses. Requesting APIs you do not need can slow down the review. For most applications, you need Lipa Na M-Pesa (STK Push) at minimum. If you also need C2B, B2C, or B2B, select those as well.

Step 4: Submit and wait. Safaricom reviews your application manually. Typical turnaround is 2 to 5 business days, but it can stretch to 10 during busy periods or if your documentation is incomplete. You will receive an email when approved.

Step 5: Receive your production credentials. After approval, you will get:

  • Production Consumer Key and Consumer Secret
  • Production Shortcode (your actual Paybill or Till number)
  • Production Passkey (for STK Push)
  • Initiator name and security credential (for B2C and Transaction Status APIs)

These are completely different from your sandbox credentials. Do not mix them up. Store them securely in environment variables, never in source code or version control.

The Production Checklist: 15 Items

Print this out and check each item off. Seriously. Missing any one of these can cause silent failures in production that cost you real money and real customer trust.

Infrastructure

  • All API URLs updated. Every instance of sandbox.safaricom.co.ke must be replaced with api.safaricom.co.ke. Search your entire codebase. Check environment variables, config files, and hardcoded strings.
  • Production credentials configured. Consumer Key, Consumer Secret, Shortcode, and Passkey are all set to production values. Double-check by logging the shortcode at startup (but never log the secret or passkey).
  • SSL certificate is valid. Your callback URLs use HTTPS with a certificate from a trusted CA. Certificate is not expired. Full chain is served (including intermediate certificates). Test with openssl s_client or ssllabs.com.
  • Callback URLs are publicly accessible. Hit your callback URL from an external machine. You should get a response (even a 405 Method Not Allowed is fine, it proves the server is reachable). No ngrok, no localhost, no internal IPs.
  • Server has adequate uptime. Your callback endpoint needs to be available whenever a customer might pay. If your server goes down, callbacks are lost. Use a reliable hosting provider with monitoring.

Application Logic

  • Callback handler responds with HTTP 200 immediately. Do not process the payment before responding. Acknowledge first, process in the background.
  • Idempotent callback processing. If Safaricom sends the same callback twice (it happens), your system should not process the payment twice. Use the CheckoutRequestID as a unique key.
  • Raw callback payloads are stored. Before any processing, save the entire JSON payload to your database. You will need this for debugging and reconciliation.
  • Error handling covers all result codes. Handle not just success (ResultCode 0) but also user cancellation (1032), timeout (1037), wrong PIN (2001), and insufficient funds. Each needs a different user-facing message.
  • Phone number normalization. Your code handles all common input formats: 0712345678, +254712345678, 254712345678, and converts them to the required 254XXXXXXXXX format.

Reliability

  • Transaction Status polling is implemented. A background job checks pending transactions after 3 minutes using the Transaction Status API. This catches lost callbacks.
  • Reconciliation process exists. You have a way to compare your transaction records against M-Pesa statements, either daily or weekly.
  • Monitoring and alerting. You are alerted when callback error rates spike, when the API returns errors, or when your callback endpoint goes down.
  • OAuth token caching. You are not requesting a new token for every API call. Tokens are cached and refreshed before expiry.
  • Environment variables, not hardcoded credentials. No secrets in source code. No credentials committed to git. Your .env file is in .gitignore.

Why Applications Get Rejected (and How to Avoid It)

Safaricom reviews production applications manually, and a significant number get rejected on the first attempt. Knowing the common rejection reasons saves you days of back-and-forth.

Incomplete or mismatched business documents. The business name on your registration certificate must match what you entered in the application. The KRA PIN must belong to the business, not to you personally. If you are a sole proprietor, these might be the same, but for a limited company, they are different documents. Upload clear, legible scans (not blurry phone photos).

No active M-Pesa business account. You need an existing Paybill or Till Number before applying for API access. Some developers assume the API application creates one. It does not. Apply for the business M-Pesa account first through Safaricom Business, wait for it to be activated, then apply for Daraja production access.

Invalid callback URLs. If you submit callback URLs that are not reachable via HTTPS at the time of review, your application may be flagged. Make sure your production server and SSL certificate are set up before applying, or at least before the review.

Requesting unnecessary APIs. If you request access to B2C (sending money to customers) but your application is an e-commerce store that only receives payments, the reviewer may ask for clarification, which delays the process. Only request what you actually need.

How to speed up the process: Submit everything correctly the first time. Include a brief description of your application and how it will use M-Pesa. If your documents are complete and clear, approval typically comes within 2 to 3 business days. If you need to follow up, email the Daraja support team with your application reference number rather than resubmitting.

Switching from Sandbox to Production in Your Code

The cleanest approach is to use environment variables for everything that changes between sandbox and production. This way, switching environments is a matter of changing your .env file, not your code.

# .env.sandbox
MPESA_ENV=sandbox
MPESA_BASE_URL=https://sandbox.safaricom.co.ke
MPESA_CONSUMER_KEY=your_sandbox_consumer_key
MPESA_CONSUMER_SECRET=your_sandbox_consumer_secret
MPESA_SHORTCODE=174379
MPESA_PASSKEY=your_sandbox_passkey
MPESA_CALLBACK_URL=https://your-ngrok-url.ngrok-free.app/api/mpesa/callback

# .env.production
MPESA_ENV=production
MPESA_BASE_URL=https://api.safaricom.co.ke
MPESA_CONSUMER_KEY=your_production_consumer_key
MPESA_CONSUMER_SECRET=your_production_consumer_secret
MPESA_SHORTCODE=your_real_shortcode
MPESA_PASSKEY=your_production_passkey
MPESA_CALLBACK_URL=https://yourdomain.com/api/mpesa/callback

In your code, reference the environment variables rather than hardcoding any URLs or credentials:

// mpesa-config.js
const config = {
  baseUrl: process.env.MPESA_BASE_URL,
  consumerKey: process.env.MPESA_CONSUMER_KEY,
  consumerSecret: process.env.MPESA_CONSUMER_SECRET,
  shortcode: process.env.MPESA_SHORTCODE,
  passkey: process.env.MPESA_PASSKEY,
  callbackUrl: process.env.MPESA_CALLBACK_URL,
};

// Sanity check at startup
if (process.env.MPESA_ENV === 'production') {
  if (config.baseUrl.includes('sandbox')) {
    throw new Error('Production env but sandbox URL detected!');
  }
  if (config.shortcode === '174379') {
    throw new Error('Production env but sandbox shortcode detected!');
  }
  console.log('M-Pesa: Running in PRODUCTION mode');
} else {
  console.log('M-Pesa: Running in SANDBOX mode');
}

module.exports = config;

That sanity check at startup has saved us (and our students at McTaba Labs) from accidentally hitting production with sandbox credentials, or worse, hitting sandbox with production credentials and wondering why real money is not moving. Spend five minutes adding validation. It will save you hours of confusion later.

Your First Production Transactions

You have production credentials. Your code is configured. Your callback URL is live. Do not announce the launch yet. Test with real money first, in small amounts.

Step 1: Make a KES 1 payment to yourself. Initiate an STK Push for KES 1 using your own phone number. Enter your PIN. Verify that the callback arrives, your database updates, and the customer (you) sees the correct confirmation. Check your M-Pesa statement to confirm the money actually moved.

Step 2: Test failure scenarios.

  • Initiate an STK Push and cancel it on your phone. Verify your app correctly marks the transaction as cancelled.
  • Initiate an STK Push and do not respond (let it timeout). Verify your Transaction Status polling picks up the timeout after a few minutes.
  • If possible, test with an amount slightly above your M-Pesa balance to trigger an insufficient funds error.

Step 3: Test with 2 to 3 other people. Have team members or friends make small payments. Different phone models, different network conditions, different M-Pesa account types. The goal is to surface edge cases you will not find testing alone. One common issue: phone number formats. Your friend might type their number as "0712 345 678" with spaces, and your normalizer might not handle that.

Step 4: Verify reconciliation. After all test transactions, compare your database records against the M-Pesa business statement. Every transaction should match. If any are missing or have incorrect amounts, fix the issue before going live.

Step 5: Go live gradually. If your app has existing users, do not enable M-Pesa for everyone at once. Start with a small percentage or a beta group. Monitor callback success rates, error rates, and customer complaints. Scale up once you are confident everything works.

This testing process takes a day or two and costs less than KES 100 in test transactions. That is a tiny investment compared to the cost of discovering bugs when hundreds of customers are trying to pay.

After Launch: Ongoing Operations

Going live is not the end. It is the beginning of ongoing operational responsibility. You are handling people's money now. That demands a level of vigilance you might not be used to from other features.

Daily reconciliation. Every day, compare your transaction records against the M-Pesa statement. This catches edge cases: callbacks that were lost, transactions that were double-processed, or amounts that do not match. Automate this if your volume justifies it. For low-volume applications, a manual daily check takes 10 minutes.

Monitor callback health. Track what percentage of your STK Push requests result in a callback within 5 minutes. If this drops below 95%, something is wrong with your infrastructure. Set up alerts for sudden drops.

SSL certificate renewal. If you use Let's Encrypt, certificates expire every 90 days. Set up auto-renewal with certbot and verify it is working. An expired certificate means zero callbacks until you fix it, and Safaricom will not tell you. You will just see a sudden stop in payments.

Keep up with Daraja changes. Safaricom occasionally updates the Daraja API (new endpoints, changed response formats, deprecated fields). Follow the Daraja developer portal for announcements. Breaking changes are rare but not unheard of.

Customer support playbook. Have a clear process for when a customer says "I paid but my order was not updated." The investigation steps are: check your callback logs for their phone number, check the Transaction Status API, check the M-Pesa statement. In most cases, the payment either failed (customer thought they completed it but actually cancelled) or the callback was lost (use Transaction Status to confirm and manually update).

M-Pesa integration is one of the most career-relevant skills for developers in East Africa. If you want to go beyond the basics and build production-grade payment systems with proper architecture, our Software and AI Engineering programme at McTaba Labs covers the full payment stack in depth.

Key Takeaways

  • You cannot go live without a registered Kenyan business entity and KRA PIN. Individual developer accounts are sandbox-only.
  • Production credentials are completely separate from sandbox credentials. Every API URL, consumer key, consumer secret, and shortcode changes.
  • Your callback URLs must use HTTPS with a valid, non-expired SSL certificate from a trusted certificate authority. Self-signed certificates will not work.
  • Test your production integration with small amounts (KES 1 to 10) before opening it to real customers. Sandbox behavior does not perfectly mirror production.
  • Build reconciliation from day one. Do not wait until you lose a payment to realize you need it.

Frequently Asked Questions

How long does it take to get Daraja production credentials?
Typically 2 to 5 business days if your documentation is complete and correct. It can take up to 10 business days during peak periods or if Safaricom requests additional information. The most common delay is incomplete business documents, so get those sorted before applying.
Can I use the same Consumer Key for sandbox and production?
No. Sandbox and production credentials are completely separate. You will receive new Consumer Key, Consumer Secret, Shortcode, and Passkey for production. Your sandbox credentials will continue to work for testing, but they cannot be used for live transactions.
Do I need a different shortcode for each application?
Not necessarily. You can use the same Paybill or Till Number for multiple applications. However, if you need to distinguish payments between different products or services, you can use the AccountReference field in STK Push to identify which application the payment belongs to. Some businesses use separate till numbers for separate products, but this is a business decision, not a technical requirement.
What happens if my production callback URL goes down?
Callbacks for any transactions during the downtime will be lost. Safaricom may retry once or twice, but this is not reliable. You will need to use the Transaction Status API to manually check and reconcile any transactions that occurred while your endpoint was down. This is why uptime monitoring on your callback URL is essential.
Can I test production credentials without charging real money?
No, there is no "production sandbox." Production credentials process real money. The standard approach is to test with very small amounts (KES 1 to 10) using your own phone number. This costs almost nothing and verifies the complete end-to-end flow with real transactions.
Is there a transaction limit on production Daraja?
Yes. M-Pesa has per-transaction limits (up to KES 150,000 for Paybill) and daily limits that depend on your business account type. There are also API rate limits from Safaricom, though these are generous enough for most applications. If you expect very high volume, contact Safaricom Business to discuss your limits.

Ready to build real-world apps?

Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.

Apply to the McTaba Marathon