The design we start from for an assistant on the WhatsApp Business Platform that answers order and booking questions, sends the updates people opted into, and passes a chat to your team without losing it. It is a reference design, not a client’s system; the rules Meta sets for webhooks and messaging windows are cited on this page with the date we checked them.
One WhatsApp conversation, webhook to CRMCompleteSample data
00:00TOOLIngressIngress › Webhook from Meta: X-Hub-Signature-256 matches the app secret
00:00OKIngressIngress › New message id: event stored, 200 returned before any model call
00:01NOTESend gateSend gate › Customer wrote just now: service window open, free-form reply allowed
00:01PLANRouterRouter › Intent order status · language Hindi · contact matched by phone number
00:02TOOLLookupLookup › Read order 4471 from the order system (read-only scope)
00:03OKAssistantAssistant › Reply in Hindi with the date and a “Talk to a person” button
00:05OKSenderSender › Status webhooks: delivered, then read
+1 dayAPPROVALSend gateSend gate › Next day, window closed: update sent only as the approved utility template
+1 dayDONECRMCRM › Summary, consent state and template sent written to the contact
The problem
What this architecture solves
A WhatsApp assistant is a webhook service with rules attached. Meta delivers every message and status update to your endpoint, may deliver the same event more than once, and decides what you may send by how recently the customer wrote to you. Duplicate replies, updates that never send and messages to people who opted out all come from ignoring one of those facts, not from the model.
Every inbound event is verified, stored and acknowledged before any slow work starts.
Inside the customer service window replies are free-form; later messages go out as approved templates, or not at all.
Consent is a record with a history, checked before every message your business starts.
Components
Components and the options for each
Webhook ingress
Checks the X-Hub-Signature-256 header against your app secret, stores the raw event and returns 200 before anything slow runs.
Cloudflare Workers
Next.js route on Vercel
Python service in Docker
Event store and dedupe
Keeps every event by message id, so a redelivery is dropped and any run can be replayed.
Cloudflare D1
Supabase Postgres
Conversation lane
One ordered lane per customer number: a burst of messages is handled in sequence, never in parallel.
Cloudflare Queues
Postgres job table
n8n in queue mode
Router and assistant
Detects intent and language and drafts a reply from approved content or a lookup.
OpenAI
Anthropic
Google Gemini
Read-only lookups
Order status, booking slots and store hours through your systems’ APIs, with scopes that cannot change data.
Your order system via its API
Your booking calendar via its API
Stripe payment status
Send gate
Checks the service window and consent before every send: inside the window the draft, outside only an approved template.
Window state per contact
Template registry with approval status
Outbound sender
Paces sends and tracks delivered or failed status for each message.
Queue with backoff
Status tracking per message
Consent store
Where each opt-in came from, its wording and time, opt-out keywords and the full history.
Supabase
Fields on your CRM contact
Team inbox and CRM
A teammate takes over in the inbox; the summary, consent state and templates sent are written to the contact.
Your CRM via its API
Shared team inbox
Data flow
How data moves, step by step
01Meta posts the message; ingress checks the signature, stores the event and answers 200.
02The message id is checked against the event store; a redelivery stops here.
03The event joins the customer’s lane, so replies never cross.
04The router reads intent and language; a lookup fetches the order if needed.
05The assistant drafts; the send gate confirms the window is open and the contact has not opted out.
06The sender posts the reply; a failed send is retried or parked.
07Later updates outside the window go out only as approved templates the contact opted into.
08A request for a person moves the chat to the inbox, and the CRM receives the summary.
How it works
Design decisions
Mechanism 01
Acknowledge first, think later
Meta retries webhooks it considers failed, and a model call can take seconds. So ingress does only cheap work: signature, store, 200. Everything else runs from a queue, and a retried webhook finds its message id already stored.
What's the alternative? Answer inside the webhook request
Simpler code, until a slow reply triggers a retry and the customer receives the same answer twice.
Mechanism 02
One lane per conversation
Customers write in bursts: a question, a photo, then the order number. Handling one number’s events in order, with a short pause for the burst to finish, lets the assistant answer the whole turn instead of each fragment.
What's the alternative? Process every event in parallel
Faster on paper; in practice replies arrive out of order and contradict each other.
Mechanism 03
The send gate owns the rules
Window and consent checks live in one place every send passes through, not in prompts. The model may draft any text; only the gate decides whether it goes out as written, becomes an approved template, or is not sent.
The customer wrote recently, so the reply goes out as drafted.
Free-form text, media or buttons
Delivery status tracked
The draft is replaced by the matching approved template, if the contact opted in to that update.
Approved utility template
Opt-in checked first
Nothing is sent; the event is logged against the contact.
Blocked by the consent record
Logged with the reason
What's the alternative? Put the rules in the prompt
Models drift from instructions; a rule about what may legally be sent belongs in code.
Reference diagram
The whole design on one diagram
Drawn to the same legend as our other reference architectures, so you can compare them box for box.
WhatsApp business bot · reference diagramReference design
consent statehandoffallowed send
SourceWhatsApp messageText, voice note or button
SourceOpt-in formConsent naming your business
ProcessingWebhook ingressSignature, store, 200
System of recordConsent storeOpt-in, opt-out, history
ProcessingConversation laneDedupe, one turn at a time
System of recordYour order systemStatus via its API
ModelRouter + modelIntent, language, draft
ProcessingRead-only lookupScoped, cannot write
ControlSend gateService window + consent
HumanTeam inboxA person takes over
ProcessingOutbound senderPaced, status tracked
HumanCustomerReply on WhatsApp
System of recordYour CRMSummary and consent state
A WhatsApp message passes webhook ingress and a per-customer lane to the router and model, which use a read-only order lookup. Drafts pass a send gate that reads the consent store, then the sender delivers them; handoffs go to the team inbox, which writes a summary to your CRM.
Diagram with 13 parts: WhatsApp message (source), Opt-in form (source), Webhook ingress (processing), Consent store (system of record), Conversation lane (processing), Your order system (system of record), Router + model (model), Read-only lookup (processing), Send gate (control), Team inbox (human), Outbound sender (processing), Customer (human), Your CRM (system of record).
Why does the webhook reply before the assistant has answered?
Meta treats a failed response as a delivery failure and sends the event again. Replying 200 once the event is verified and stored stops those retries; the assistant works from a queue, and a repeat is recognised by its message id.
What happens to a reply the assistant drafts after the window has closed?
The send gate does not send it as written. If the contact opted in and an approved template fits, the template goes out with the details filled in; otherwise the message is held and a person decides.
How does the bot cope when a customer sends five messages in a row?
Each customer number has one ordered lane, and the assistant waits briefly for a burst to finish, then answers the whole turn once instead of each fragment.
Where do WhatsApp conversations live after a person takes over?
In your team inbox while the chat is open, then as a summary on the CRM contact with the consent state and templates sent. Raw events stay in the event store for the retention period you set.
Do we need a Business Solution Provider, or can you connect to Meta directly?
We usually connect to the Cloud API on your own Meta Business account, so you own the number with no middle layer. A provider makes sense if your team already works in its inbox; the design stays the same.
Which parts of this design would we keep if we dropped the AI?
Almost all of it. Ingress, dedupe, ordering, the send gate, consent and the CRM write-back make order updates reliable on their own; the router and model sit in the middle and can be added later.
Next step
Have a workflow in mind? Let’s scope it together.
Book a free 30-minute strategy call. Bring one process you want to automate and we will talk through scope, integrations and a sensible first step.