Planning a WhatsApp Business Bot with M-Pesa in Kenya

B
Bob Mwenda
Published • 6 min read
Planning a WhatsApp Business Bot with M-Pesa in Kenya

Version and provider scope: This guide assumes the direct WhatsApp Business Platform Cloud API and Meta Graph API webhooks; a WhatsApp Business app inbox or third-party provider can have a different setup and contract. No Graph API version is prescribed here. Choose and test the version used by your Meta app, and verify webhook fields, permissions, delivery behavior, and version changes against Meta's current WhatsApp webhooks documentation before release.

This article is a planning guide for a WhatsApp Business bot that can support an M-Pesa checkout. It explains the system boundaries and failure paths to agree before implementation; it is not a copy-and-run tutorial. The exact WhatsApp account setup, message rules, webhook fields, and Daraja product requirements must be confirmed for the business that will operate the service.

Last updated: September 19, 2026.

Plan one end-to-end customer journey

Consider this hypothetical order journey. A customer asks for two items. The bot identifies the product from an approved catalogue, asks for any required option and delivery details, then shows the items, calculated total, delivery information, and order summary for confirmation. The server creates one order with a reference and a payment attempt; the customer confirms that the displayed amount is correct before the server initiates the configured M-Pesa request.

While the payment is pending, the bot says the request is awaiting confirmation. It does not call the order paid because a prompt was sent, because a customer says “done,” or because a browser returned to a success page. The application confirms only after it has validated a result for that attempt, checked the reference and expected amount, and applied the payment state once. It then updates the order and sends a confirmation.

If the customer cancels or a failure is confirmed, the order remains unpaid and the bot offers the agreed retry or a person. If the result is uncertain or delayed, it explains that payment is still being checked; staff can query or reconcile using the enabled Daraja product where available. A human handoff carries the conversation, order reference, payment attempt, and outstanding question. Once a person takes over, the bot should not continue changing that order behind them.

This is a design example, not a claim about a live Statum deployment or a guaranteed Safaricom flow. Confirm the selected account and product in the Daraja API catalogue. The M-Pesa callback and reconciliation guide explains how to handle payment results and exceptions.

Separate inbound messages from delivery statuses

A WhatsApp webhook can describe different events. An incoming customer message is an instruction or new information for the conversation. An outbound status event reports what happened to a message the business sent. Keep those paths separate in your event handling and data model.

Meta's WhatsApp webhook payload reference shows incoming message payloads and message status notifications. An inbound message can arrive in the messages collection; an outbound delivery notification appears in statuses and includes the sent message identifier and status. Status values can include sent, delivered, read, or failed. Meta notes that status notifications can arrive in an order that does not match the actual timing, so use the event timestamp and keep the status history rather than regressing an outbound message because an older event arrived later. A delivery receipt is not customer intent, an M-Pesa result, or permission to fulfil an order. See Meta's message status update documentation.

Verify and process webhooks

Set up the WhatsApp Webhooks product, subscribe the app to the required webhook fields, and make the callback endpoint reachable over HTTPS. Separately, subscribe the app to the relevant WhatsApp Business Account (WABA). Meta's solution-provider webhook management guide documents the POST /<WABA_ID>/subscribed_apps step.

For the standard Meta Graph API handshake, validate the configured verify token on the GET verification request and return the supplied challenge only when it matches. For incoming POST notifications, verify Meta's X-Hub-Signature-256 against the raw request body using the app secret before trusting or acting on the parsed event. Follow the current Meta Webhooks setup documentation for the exact verification and signature procedure. Keep app secrets, access tokens, and the verification token on the server, outside source control and client code.

After verification, store the event durably, deduplicate it by its stable message or event identity, and queue slower work. Separate the handler for new inbound messages from the handler for outbound statuses. If the same inbound event is delivered again, it should not create two orders or payment attempts. If a sent message status changes, update the corresponding outbound-message record; do not start a new checkout. Acknowledge each Event Notification with HTTP 200 after it has been accepted durably; run slower work asynchronously and monitor internal processing failures. Meta retries failed deliveries, so the handler must deduplicate repeated notifications.

Keep payment and AI decisions in application rules

The application should calculate the price from the approved catalogue, check the order and customer permissions, and create the payment attempt. Give an AI model a limited task such as finding an answer in approved material or classifying a message for a staff member. Do not let model text choose an arbitrary amount, expose another customer's record, approve a refund, or mark a payment complete. Validate every tool request against current order state and route uncertain or consequential cases to a person.

Store a conversation reference, inbound message identifiers, order reference, payment attempt, current workflow state, handoff owner, and the timestamps needed to investigate. Define access and retention for phone numbers and message content. Record enough to support the conversation without copying unnecessary personal data into logs.

Test the full and failure journeys

Before launch, walk through the whole order with the support team, then test topic changes, missing details, unknown questions, repeated inbound events, and an agent taking over. For payments, test confirmation, cancellation, timeout with no immediate result, delayed confirmation, mismatched amount or reference, duplicate delivery, and a later reversal. Assert the order state, payment ledger, customer message, outbound message status, audit history, and handoff for each case. Reconcile the provider-side record with the internal attempt before resolving an uncertain payment.

For a first release, choose one defined customer job, one approved product catalogue or enquiry source, one configured payment product, a clear human handoff, event monitoring, and a documented reconciliation owner. Expand only after the team can review errors and support exceptions. The companion pre-production M-Pesa checklist helps turn payment tests and operational responsibilities into launch sign-off.

A practical next step

Need help applying this to a real system?

Statum can help turn the idea into a scoped piece of work. See our software services, browse completed projects, read the developer documentation, or start a project conversation.

B

Bob Mwenda

Article author

Bob Mwenda is a software engineer at Statum with over ten years of experience building business applications and integrating enterprise systems. His work spans Java, Spring Boot, PHP, Laravel and Vue.js, including API integrations, payment and messaging systems, and application deployment. On the Statum blog, Bob writes about software development, business automation and the practical decisions behind building and maintaining software. His articles help business owners and developers understand implementation options, technical trade-offs and common pitfalls.

More Articles

View All →