WhatsApp Customer Service Bots in Practice: Human Handoff and Model Fallback Design

Production-grade WhatsApp bots live or die on boundary control, fallback, and data governance — not the LLM.
This article uses a WhatsApp lead bot running in Dubai to show the production elements tutorials usually skip: connecting via Baileys, calling models through OpenRouter, local JSON storage, and the ban risk of the unofficial protocol. Core design includes limiting reply length, a six-model fallback with timeouts and an emergency reply, persistent human-handoff state, an operator-controlled ignore list, and a strictly conditioned single follow-up. The author reflects on migrating to the Cloud API and a database, logging fallback and handoff events, and complying with the UAE PDPL.
Most WhatsApp bot tutorials stop at "receive a message, call an LLM, send a reply." But in a real production environment, what actually determines success or failure is everything outside that flow — when the bot should shut up, what to do when the model API goes down, and how to avoid harassing users. A WhatsApp lead bot that ApexFlow Digital runs for clients in Dubai demonstrates how these pieces are implemented in practice.

Tech Stack and Prerequisites
This system uses Node.js with the @whiskeysockets/baileys library to establish a WhatsApp connection, calls large language models through OpenRouter, persists sessions, leads, and follow-up state as JSON files on disk, and runs a lightweight HTTP service for health checks.
One prerequisite must be made clear: Baileys uses the WhatsApp Web protocol, not the official Business Cloud API. It deploys quickly and doesn't require template approval, but it's an unofficial approach, and WhatsApp has the right to restrict numbers that behave like spam. If your business needs guaranteed availability or high concurrency, you should switch to the Cloud API. That said, the design patterns discussed below apply to both.
What is Baileys? Baileys (@whiskeysockets/baileys) is an open-source library written in TypeScript/JavaScript that directly reproduces the WhatsApp Web communication protocol over WebSocket, letting developers send and receive messages, read contacts, and handle groups and media files without official approval. Compared with the official Business Cloud API, Baileys' advantages are its fast onboarding, no template review, and support for personal numbers — but its biggest risk is the unofficial protocol: WhatsApp's Business Conduct Guidelines prohibit automation or bulk sending of spam-like messages, and once a number is flagged as violating them, it may be temporarily banned or even permanently suspended with no appeals channel. Baileys is therefore suited to low-risk scenarios like prototyping and small-scale lead collection; for customer-facing production services, guaranteed deliverability, or systems with meaningful concurrency, you should migrate to the Cloud API and submit message templates as required.
The role of OpenRouter: OpenRouter is a unified multi-model gateway that, through a single OpenAI-compatible API, lets you call GPT, Claude, Gemini, Llama, and other models, with support for per-model switching, retry on failure, and cost comparison. This pairs perfectly with the "six-model fallback list" design below — no need to maintain a separate SDK and auth setup for each model; a single wrapper enables horizontal switching.
Short Replies Are by Design
The system prompt explicitly requires replies to be kept within one to three sentences, and only sends a booking link when a prospect shows clear intent — for example, asking about pricing, service scope, scheduling, or requesting a call.
There's a product logic behind this constraint: long, enthusiastic bot messages are a leading cause of user churn. When users message a business on WhatsApp, they expect quick, useful information — not a sales pitch. Writing reply length into the system prompt, rather than hoping the model "behaves," is the key to keeping the style consistent.
Model Fallback: Don't Let an API Outage Become Silence
A single model API will eventually have problems. This bot maintains an ordered list of six models, tries them one by one, and sets a timeout for each call. If all models fail, it doesn't go silent — it sends a fixed, short reply.
for (const model of FALLBACK_MODELS) {
try {
const res = await callOpenRouter(model, history, { timeoutMs: 12000 });
if (res.ok) return res.text;
} catch (_) { /* try the next model */ }
}
return EMERGENCY_REPLY;
The practical value of this snippet is that customers never perceive a backend failure, and the conversation isn't interrupted by an API timeout. Compared with "silent failure," a preset emergency reply at least maintains the appearance of continuity and buys time for human intervention.
The engineering significance of timeouts and fallback: When calling external LLMs, there are three common failure modes — network timeouts, rate limiting (429), and server errors (5xx). Without timeout control, a single request can hang for tens of seconds, destroying the user's wait experience; relying on a single model means one regional outage can leave the entire bot "mute." The combination of a fallback list plus timeouts narrows uncertainty into predictable behavior: either some model returns a result within the time limit, or the emergency reply is used. Two details matter: first, the timeout threshold should be set according to business tolerance (12 seconds in this case) — too short and you'll wrongly kill slow but valid inferences; second, every fallback should be logged, otherwise you have no idea what the primary model's actual availability rate is — which is exactly why the author, in "What I'd change if rebuilding," proposes logging fallback events.
Human Handoff: Persistence Is the Key
The bot checks every incoming message for human-handoff request phrases, supporting both English and Arabic (such as "speak to a person" and "call me"). On a match, it performs three steps:
- Adds that sender to a paused set, so the bot no longer replies in that conversation
- Writes the pause flag to disk, ensuring it won't be woken up mid-conversation after a restart
- Sends an alert to the person responsible via WhatsApp, with a link to the chat
The persistence in step three is what most tutorials skip. Without it, a poorly timed deployment can shove the bot back into a conversation that a human has already taken over — a very awkward failure in production.
Why in-memory flags aren't enough: Many tutorials use an in-memory Set or Map to record that "this user has been taken over by a human," which works in a single-process environment that never restarts. But production deployments commonly involve rolling updates, crash restarts, and horizontal scaling. Once the process is rebuilt, in-memory state is wiped, and the bot starts auto-replying again — just as an agent may be discussing a quote or a complaint with the user, a sudden automated reply from the bot causes serious confusion. Writing the pause flag to disk (or a database) essentially decouples "conversation state" from the process lifecycle, so restarts and scaling don't change business semantics. Once you have more than one instance, local JSON runs into multi-process concurrent writes and state inconsistency, so you need to upgrade to shared storage like Redis or Postgres.
Ignore List: Put Control in the Operator's Hands
Some contacts are friends, suppliers, or long-time customers who don't need bot interruptions. The person responsible can send /ignore or ignore <number> to the bot's number to exclude a contact, and /unignore to restore it. This list is stored in a JSON file and checked before all logic, including voice message transcription.
Letting operators adjust the bot's behavioral boundaries at any time is far more flexible than hardcoding exceptions in code.
Follow Up Only Once, and Under Strict Conditions
A scheduler periodically checks lead status and sends at most one follow-up message, which must satisfy three conditions simultaneously:
- The lead has been silent for 24 to 72 hours
- The lead is not paused
- It's during Dubai business hours (10:00 to 19:00)
After one send, the system no longer proactively contacts that lead, and every send notifies the person responsible. In the retrospective, the author notes two areas for improvement: the follow-up copy should live in configuration rather than in code, and an explicit opt-out line should be added.
Data Storage and Compliance Considerations
Chat history and lead profiles are stored locally as JSON. If users are in the UAE, you need to pay attention to Federal Decree-Law No. 45 of 2021, the personal data protection law, clarifying where data is stored and which processors (including LLM providers) can access it. The original article specifically notes that this is not legal advice and that a qualified lawyer should be consulted.
Basic requirements of the UAE PDPL: Federal Decree-Law No. 45 of 2021 (commonly known as the UAE Personal Data Protection Law) was issued in 2021 and took effect in 2022, following the spirit of the EU GDPR. It requires a lawful basis for processing personal data, adherence to purpose limitation and data minimization, and guarantees data subjects' rights to access, correct, and delete their data. For this project, the key points are: first, being clear about where chat logs and lead profiles are stored (local disk / cloud region); second, mapping out the processor chain, including WhatsApp, OpenRouter, and the specific LLM providers being called — user messages may be accessed by these third parties or even used for training, and this must be disclosed in the privacy policy. If cross-border transfers are involved, you also need to assess the recipient's compliance level. This is background only and does not constitute legal advice.
What I'd Change If Rebuilding
The author offers three reflections: customer-facing critical services should use the Cloud API and approved templates; once there's more than one instance, state management should move from JSON files to a database; and every human handoff and model fallback event should be logged so you can understand the actual frequency of model failures.
These lessons point to a common theme: the hard part of a production-grade WhatsApp bot isn't the AI capability itself, but the boundary control, failure recovery, and data governance built around the AI. Only by designing the bot as a system that needs operations — rather than a script that's done once you hook up the API — can it truly run in a business context.
One-line Summary
Production-grade WhatsApp bots succeed or fail on boundary control, failure fallback, and data governance — not the LLM itself.
Paragraph Summary
Using a WhatsApp lead bot running in Dubai as an example, this article shows the production elements tutorials usually skip: connecting via Baileys, calling models through OpenRouter, storing state locally as JSON, and highlighting the ban risk of the unofficial protocol. The core design includes hard-limiting reply length in the system prompt to reduce churn, implementing model fallback through an ordered six-model list with timeouts and returning an emergency reply when all fail, persisting human-handoff state to disk to prevent the bot from re-intervening after a restart, putting behavioral boundaries in the operator's hands via an ignore list, and following up at most once only when silence duration, pause status, and business hours all align. The author concludes by reflecting that the system should migrate to the Cloud API and a database, log fallback and handoff events, and comply with the UAE Personal Data Protection Law.
Related articles

Chain of Thought Isn't Just for AI: How Humans Can Use CoT to Improve Thinking Quality
Chain of Thought isn't just a prompt trick for large models. Starting from a Hacker News discussion, this article analyzes why CoT works for human thinking too, breaks down actionable ways to transfer it, and highlights the key differences between human CoT and machine CoT.
Cloudflare Teams Up with OpenAI: Closi…
Cloudflare Teams Up with OpenAI: Closing the Loop from Vulnerability Discovery to Defense with AI
Cloudflare uses OpenAI Daybreak to investigate security vulnerabilities and generate reviewable remediation plans, while developers use Codex to boost coding efficiency and quality.

Orca Multi-Agent Orchestration in Practice: A Guide to Parallel Collaboration with Claude and Codex
Orca is Stable AI's free open-source agent workbench supporting 34 agents like Claude Code and Codex in parallel. Learn its Git worktree isolation, multi-model orchestration, and mobile management.