Skip to main content
Bridge a WhatsApp number to an agent so a client’s message runs an agent turn and the answer comes back on WhatsApp. Two providers carry WhatsApp: Twilio and the Meta Cloud API. The bridge is the same for both — only the channel plugin, its env group, and the webhook wiring differ. See client conversations for the model this guide configures.

Prerequisite: mint and bind a least-privilege execution key

A conversation route runs its turn as an execution_key — an API-key identity, not the client who texted. That key’s live grants are the turn’s entire authority, so scope it to exactly what the agent needs and nothing more.
1

Mint a scoped key

Mint a key whose scopes are the least the agent’s tools require. A non-admin owner may grant only scopes it already holds; the new key is owned by you.
2

Bind it when you create the route

The route’s --execution-key binds that identity. You may bind your own identity or a key you own; an admin may bind any key (a pass-role check). The key must be evaluable by a background execution — a stored policy condition that needs a request token is rejected at bind. The turn is bounded by the key’s live grants: attenuate the key and the next turn is denied, with no revocation step on the route.
The turn can do whatever the execution key can do. Never bind an admin or a broadly scoped key to a route reachable from a messaging channel — a prompt-injected message would run as that key. Bind a purpose-built, least-privilege key.

Pick a provider and wire it

Both providers use the same bridge and the same execution-key binding above. What differs — the channel package and its env group, the webhook(s) to point at the deployment, the our_identity format, and (on the Meta Cloud API) the rich-message and 24-hour-window behaviour — lives on the plugin page:

channel-twilio

CHANNEL_TWILIO_*, the inbound and status webhooks, and the whatsapp:-prefixed sender as our_identity. Text only.

channel-whatsapp

CHANNEL_WHATSAPP_*, the single webhook with its hub.challenge handshake, the phone_number_id identity, plus interactive selects, media, and templates.
Once the channel is configured, create the route binding the texted number to the agent, with --channel naming the provider and --identity its our_identity (exact formats on the plugin pages):

Test it and add more numbers

Send a WhatsApp message to the configured number and watch the agent’s reply come back from that same number. Read one answer record by id:
To take a thread off the flow and answer it yourself — or let the agent hand its own conversation to a human — see control mode and operator messages. Multi-number is just more rows: create another route with the same --channel and a different --identity (a second Twilio sender, or a second phone_number_id under one Cloud credential). Each identity resolves to its own route and agent, and each reply leaves from the number that was texted. A (channel, identity) pair may be claimed by only one route. Delivery outcomes — including a failed record when WhatsApp rejects a send inside or outside its 24-hour window — surface on the admin failed-delivery door:

See also