Wiring an AI agent into WhatsApp: how a message actually gets from the user to the model and back
Every piece — webhooks, templates, buttons, correlation — has its own lesson already. This one is the wiring diagram, showing where the AI agent actually sits in that flow, and the two things about a messaging channel that break an agent built for a web chat widget first.
3 min read
The full round trip, as one picture
Everything to the left of "Your webhook" is the WhatsApp mechanics covered in this domain's other lessons — the handshake, signature verification, templates, the 24-hour window. Everything to the right of it is an ordinary LLM agent — a system prompt, a tool catalog, a model call. The interesting engineering is entirely in the middle: making an agent that was probably built for a web chat widget first work correctly on a channel with two very different constraints.
Constraint 1: no open connection to stream into
A web client can hold a connection open and render tokens as they arrive. A webhook has no such thing — Meta sends one HTTP request and expects a response; there's nothing to stream partial output into. This isn't a small tweak, it's a second, non-streaming code path alongside the streaming one: same system prompt logic, same tool catalog, same underlying agent loop, but a call that waits for the complete response before replying once.
Constraint 2: nothing resends the conversation for you
A typical web chat client re-sends its own accumulated message history with every request — the server barely has to think about where "the conversation so far" comes from. A messaging platform sends exactly the new message and nothing else, every time. Skip building real, server-side conversation storage for this channel and the agent will look completely fine in every manual test (a single message, a single reply) and then appear to have total amnesia the moment a real back-and-forth starts — because there genuinely is no "so far" anywhere except your own database.
The prompt itself has to know which channel it's on
The two constraints above aren't just plumbing — they change what's true for the model to reason about, which means the system prompt has to vary by channel too (the general principle is covered in this app's AI Agents domain, in the system-prompts lesson). A prompt written assuming a rich confirm card exists will instruct the model to reference UI that doesn't exist on a channel where that UI genuinely can't be shown — the fix is a channel parameter threaded into prompt assembly, not a single prompt shared everywhere and hoped to be close enough.