Prerequisite: mint and bind a least-privilege execution key
A conversation route runs its turn as anexecution_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.Provider A — Twilio
Configure the channel
Set theCHANNEL_TWILIO_* env group and load the channel module in the manifest.
manifest.yml
CHANNEL_TWILIO_AUTH_TOKEN is a secret — it authenticates the outbound send and
keys the inbound signature check (a mis-signed webhook is rejected, fail-closed).
CHANNEL_TWILIO_ACCOUNT_SID and the WhatsApp sender come from your Twilio account
and its WhatsApp sender registration.
Point the webhooks at the deployment
Twilio calls two webhooks (configured in the Twilio console or REST — the plugin never mutates your Twilio account):- Inbound message (“A message comes in”, HTTP POST) →
{public base URL}/api/channels/twilio/inbound - Delivery status callback (HTTP POST) →
{public base URL}/api/channels/twilio/status
failed/undelivered status, which flips the answer record
to failed.
Create the route
Bind the texted WhatsApp number to the agent.our_identity is the number the
client texts — the Twilio WhatsApp sender, whatsapp:-prefixed:
Provider B — Meta Cloud API
Configure the channel
Set theCHANNEL_WHATSAPP_CLOUD_* env group and load the channel module.
manifest.yml
ACCESS_TOKEN is the Graph API bearer token for the send (one token serves many
numbers). APP_SECRET keys the X-Hub-Signature-256 HMAC the inbound door checks
over the raw body. VERIFY_TOKEN is the shared secret echoed during Meta’s
subscribe handshake. All three are secrets, masked in logs.
Point the webhook at the deployment
Meta uses a single webhook endpoint for verification, inbound messages, and delivery statuses (configured in the Meta App dashboard):- Callback URL →
{public base URL}/api/channels/whatsapp-cloud/inbound - Verify token → the value of
CHANNEL_WHATSAPP_CLOUD_VERIFY_TOKEN
GET with hub.challenge; the door echoes the
challenge only when the verify token matches. Inbound messages and delivery
statuses then arrive as signed POSTs on the same URL — the failed status posted
outside WhatsApp’s service window flips the answer record to failed here.
Create the route
For the Cloud API,our_identity is the number’s phone_number_id (from the
Meta dashboard), not the display number:
The 24-hour window failure
WhatsApp only lets you send freeform messages inside a 24-hour service window opened by the client’s last message. Outside it, a freeform reply is rejected and must be a pre-approved template. The bridge surfaces this failure on both providers, in both timings:- Synchronous — the provider rejects the send outright; the delivery attempt
fails and retries within the attempt budget, then the record ends
failed. - Asynchronous — the provider accepts the send (
2xx) and later posts afailed/undelivereddelivery-status webhook (Twilio’s status callback, Meta’s same-URL status), which flips the record tofailed.
failed and listed on the admin failed-delivery door.
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:--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.
See also
- Client conversations — doors, routing, and delivery outcomes.
- Conversation bridge reference — every setting, the read doors, and the authorization model.
- Use owned keys — minting and capping the execution key.

