A customer writes "bhai mera order kahan hai, 5 din ho gaye" at 9 pm. A support bot that answers well in Hinglish saves someone a night shift. A bot that invents a delivery date, promises a refund or asks for a card number creates a much worse problem than silence.
The short answer: a WhatsApp customer support bot should answer only from your order record and FAQ, stay inside Meta's 24-hour window rules, hand off to a human on defined triggers, and have every reply checked by code before it is sent. The prompt is the smallest part of that. This post gives you the rules from Meta's own pages (read 2026-10-09), a guardrail script I ran with its real output, and untested prompt templates for Hinglish.
It covers the inbound support side. For outbound order updates and template approval, read WhatsApp order updates for Indian D2C stores. For wiring up a basic bot, see the Claude and Twilio WhatsApp tutorial.
What do Meta's rules say about a WhatsApp support bot?
I read the WhatsApp Business Messaging Policy directly on 2026-10-09 (it showed "Last updated: September 23, 2026") and the Cloud API send-messages guide. The business terms page was read only through a summarising fetch, so check its exact wording.
- Replies are free-form only inside the window. The policy says you may reply to a user message without a template within the 24-hour customer service window, which opens and resets with each user message. Outside it, approved templates only.
- Automation is allowed, with an exit. The policy says "You may use automation when responding during the 24-hour window, but must also have available prompt, clear, and direct escalation paths." Its list: in-chat human agent transfer, phone number, email, web support, in-store visits, or a support form.
- Opt-out must be respected. You must respect requests, on or off WhatsApp, to block, discontinue or opt out, including removing the person from your contacts list.
- No sensitive identifiers. Do not share or ask people to share full-length individual payment card numbers, financial account numbers, personal ID card numbers or other sensitive identifiers.
- Health data. The policy says not to use WhatsApp to send or request health information if applicable regulations prohibit sending it to systems that don't meet heightened requirements.
- Data use. Don't use data obtained from WhatsApp about a person, other than thread content, for anything beyond supporting messaging with that person. You also need a published privacy policy.
- Interactive replies. The Cloud API guide says you can offer up to three predefined reply buttons, plus list messages. It gave no length limits on that page.
- Typing indicator. The guide recommends showing a typing indicator and read receipt when a reply may take a few seconds. It gave no timeout.
One clause deserves a separate look. Meta's terms for the WhatsApp Business Platform (summarised fetch, last modified September 23, 2026) have a section 4.7 on "AI Providers". As summarised, it prohibits AI Providers, defined to include developers of large language models, generative AI platforms and general-purpose AI assistants, from using the platform where such technology is the primary functionality being made available. It also says a business may retain an AI Provider as its Solution Provider, and it restricts using platform data to train AI models, with an exception for fine-tuning a model for your exclusive use. A company answering its own customers' order questions is a different situation from a general-purpose assistant on WhatsApp. But I can't give you a ruling, and Meta decides coverage in its sole discretion per the summary. Read the clause and ask a professional before you build a product on it.
What should the bot be allowed to do?
Decide this before you write a prompt. A narrow bot fails in narrow ways.
| Task | Bot alone? | Why |
|---|---|---|
| Order status from your OMS or courier API | Yes | Fact comes from a system, not the model |
| Shipping, return and COD policy questions | Yes | Answer from a short FAQ you wrote |
| Collect details for a return request | Yes, then human approves | Bot gathers, human decides |
| Promise a refund, amount or date | No | Money commitments need a person or a system record |
| Complaints, legal threats, fraud claims | No | Escalate immediately |
| Anything with card, Aadhaar or PAN numbers | No | Don't store or echo; offer a human |
| Medical or legal advice | No | Out of scope; say so and route |
How do you code the guardrails around the model?
Four gates, none of which need a model: a window check, an inbound router, a sensitive-data detector and an outbound reply checker. I wrote this as plain Python and ran it on 2026-10-09 (Python 3, standard library only, no network). The model call is stubbed, because the point is to test the gates. The keyword lists are mine and deliberately small; you would extend them from your own tickets.
import re
from datetime import datetime, timedelta
WINDOW = timedelta(hours=24)
ESCALATE_WORDS = [
"human", "agent", "manager", "insaan", "kisi se baat", "baat karao",
"refund nahi", "paisa wapas", "paise wapas", "consumer court", "complaint",
"fraud", "scam", "dhokha", "chargeback", "police", "legal", "vakeel",
]
OPT_OUT = ["stop", "unsubscribe", "band karo", "mat bhejo", "no more messages"]
CARD = re.compile(r"\b(?:\d[ -]?){13,19}\b")
AADHAAR = re.compile(r"\b\d{4}\s?\d{4}\s?\d{4}\b")
PAN = re.compile(r"\b[A-Z]{5}\d{4}[A-Z]\b")
PROMISE = re.compile(r"(?i)\b(guarantee|definitely will|100%|refund (?:is )?(?:approved|processed)|we will refund|pakka)\b")
MAX_WORDS = 80
def window_open(last_user_msg: datetime, now: datetime) -> bool:
return now - last_user_msg < WINDOW
def classify_inbound(text: str) -> str:
low = text.lower()
if any(w in low for w in OPT_OUT):
return "opt_out"
if CARD.search(text) or AADHAAR.search(text) or PAN.search(text):
return "sensitive_data"
if any(w in low for w in ESCALATE_WORDS):
return "escalate"
return "bot"
def check_reply(reply: str, allowed_facts: set) -> list:
problems = []
if len(reply.split()) > MAX_WORDS:
problems.append("too long (%d words)" % len(reply.split()))
m = PROMISE.search(reply)
if m:
problems.append("commitment language: %r" % m.group(0))
for num in re.findall(r"(?:Rs\.?|INR|₹)\s?[\d,]+", reply):
if num not in allowed_facts:
problems.append("amount not in order record: %r" % num)
for d in re.findall(r"\b\d{1,2}\s(?:Oct|Nov|Dec)\b", reply):
if d not in allowed_facts:
problems.append("date not in order record: %r" % d)
return problems
def route(text, last_user_msg, now):
if not window_open(last_user_msg, now):
return "OUTSIDE_WINDOW: send approved template only, no free-form"
kind = classify_inbound(text)
return {
"opt_out": "OPT_OUT: record, confirm once, stop all non-service sends",
"sensitive_data": "SENSITIVE: do not store or echo, ask user to delete, offer human",
"escalate": "ESCALATE: hand to human with transcript",
"bot": "BOT: answer from order record and FAQ only",
}[kind]
The test driver (omitted here for length) fed it six invented inbound messages with a fixed clock of 2026-10-09 12:00, and three stubbed replies against an order record containing only Rs 1,499 and 12 Oct. Real output:
Mera order kab aayega? -> BOT: answer from order record and FAQ only
refund nahi mila, paisa wapas chahiye -> ESCALATE: hand to human with transcript
card 4111 1111 1111 1111 se pay kiya tha -> SENSITIVE: do not store or echo, ask user to delete, offer human
please stop sending messages -> OPT_OUT: record, confirm once, stop all non-service sends
order status? -> OUTSIDE_WINDOW: send approved template only, no free-form
I want to talk to a human -> ESCALATE: hand to human with transcript
ok -> PASS
promise -> ["commitment language: 'refund is approved'", "date not in order record: '11 Oct'"]
wrong_amount -> ["amount not in order record: 'Rs 1,299'"]
Read the output critically. The promise reply contained Rs 1,499 (in the record, so allowed) and still failed twice, on the commitment phrase and on the invented date. The wrong_amount reply is the case a prompt alone tends to miss: the sentence is polite and plausible, and wrong.
Known weaknesses, which I'd rather you hear now:
- Substring matching is crude. "stop" matches "bus stop" and "agent" matches "reagent". Use word boundaries and a reviewed list in production.
- The card regex also matches any 13 to 19 digit run, such as a long tracking number. A false positive here only means a human sees the message, which is the safe direction.
- It only knows Latin-script Hinglish. Devanagari messages need their own lists.
- The rupee and date checks are formats I picked. Your order system's formats will differ.
When check_reply returns problems, never send the draft. Either regenerate once with the problems fed back, or hand the chat to a human. Two failures in a row should always mean a human.
How do you prompt for Hinglish without sounding robotic?
The prompts below are untested templates. I did not run them against a live model for this post, so treat the reply style as something you verify with your own sample chats. Replace every bracketed item with your real facts.
System prompt.
You are the WhatsApp support assistant for [BRAND], an online store in India.
You answer ONLY from the ORDER RECORD and FAQ below. If the answer is not
there, say you will check with the team and set needs_human to true.
Language: reply in the language the customer used. If they write Hinglish
(Hindi in Roman script mixed with English), reply in simple Hinglish. Keep
sentences short. No slang you would not use with a stranger. No emoji
unless the customer used one first.
Rules:
- Never state an amount, date, tracking ID or policy that is not in the
ORDER RECORD or FAQ. Copy values exactly.
- Never promise a refund, replacement, compensation or deadline. You may
say a request has been noted and who handles it.
- Never ask for card numbers, bank details, OTPs, Aadhaar or PAN. If the
customer sends one, tell them not to share it here and set needs_human.
- If the customer is angry, mentions a complaint, legal action, fraud or
asks for a person, set needs_human and say a team member will reply.
- Maximum 60 words. End with one clear next step.
Return JSON: {"reply": "...", "needs_human": true or false, "reason": "..."}
ORDER RECORD: [PASTE FROM YOUR SYSTEM FOR THIS CUSTOMER]
FAQ: [PASTE 10 TO 20 SHORT POLICY LINES]
Few-shot examples (add two or three of these to the prompt; the replies are hand-written by me and illustrative, not model output):
Customer: bhai order kahan hai, 5 din ho gaye
ORDER RECORD: status=shipped, courier=[COURIER], tracking=[ID], eta=[DATE]
Reply: Aapka order shipped hai. Courier [COURIER], tracking ID [ID]. Expected delivery [DATE]. Agar tab tak na aaye to yahan likhiye, team check karegi.
Customer: refund nahi aaya abhi tak, ye fraud hai
Reply: Aapko jo pareshani hui uske liye sorry. Main ye team ko de raha hoon, ek team member aapko yahin reply karega.
(needs_human: true, reason: fraud claim and refund dispute)
Hand-off summary prompt, so the human does not have to reread the whole chat:
Summarise this WhatsApp chat for a support agent in five lines: customer
issue, order ID, what the bot already said, what the customer wants, and
sentiment (calm, annoyed, angry). Do not add facts not in the chat.
CHAT: [TRANSCRIPT]
How do you test it before real customers see it?
Build a test file of 30 to 50 messages from your own past tickets, with personal details removed, and run it through the router and checker offline. Include messages in Roman Hinglish, in English, with typos, in Devanagari, and in all caps. For each one, write down what should happen: bot, escalate, opt out or template-only. A message set where you know the right answer is worth more than any amount of prompt tweaking. The LLM regression tests in CI with promptfoo post shows how to rerun such a set after every prompt change.
Add these checks to the list:
- A customer sends a card number: nothing is logged in full, and the reply tells them not to share it.
- A customer writes "STOP" at 23 hours 59 minutes: opt-out is recorded.
- A message arrives at hour 25: the bot does not send free-form text.
- The order system is down: the bot says it can't see the order and escalates, rather than guessing.
- A customer asks something out of scope, such as medical advice: polite refusal and routing.
For deeper patterns, see building a customer support agent that doesn't hallucinate and PII redaction before LLM calls.
What does a human hand-off need?
Meta's policy requires the escalation path to be prompt, clear and direct. In practice that means:
- The bot tells the customer, in plain words, when a person will be involved, without inventing a response time you can't keep.
- Your business profile lists support contact information (the policy page states this).
- The human sees the transcript and the summary, so the customer never repeats themselves.
- Someone owns the queue. A hand-off to an unmonitored inbox is worse than no bot.
Meta's Terms state that you are responsible for opt-in and notices under applicable law. For Indian consent and data rules, start with the DPDP checklist for AI developers and ask a lawyer about your own situation. This post is not legal advice.
What to do this week
- Write the table of what your bot may and may not do, and have your support lead sign it.
- Copy the guardrail script, extend the word lists from 50 real tickets, and run it.
- Paste the system prompt, fill in your facts, and try it on 20 old chats. Count how often the post-check catches something.
- Decide your hand-off channel and who watches it.
- Read Meta's policy and business terms yourself. They changed on September 23, 2026 according to the pages I read.
When to skip the bot: if you get fewer than a few support chats a day, a shared inbox with saved replies is simpler and safer. And if you can't staff the hand-off queue, don't launch.



