Skip to main content
Trinity
Guides/WhatsApp Integration

WhatsApp Integration

Connect agents to WhatsApp via Twilio. Users can send direct messages to the agent from any WhatsApp account.

Concepts

1:1 Binding — Each agent has its own Twilio account and WhatsApp sender. Twilio accounts cannot be shared across agents.
Sandbox — Twilio's shared test sender (whatsapp:+14155238886). Free to use; users must opt in with a keyword before messaging.
Production Sender — A dedicated phone number registered with Meta via Twilio. Requires Meta Business Manager approval (24–48 hours).
Webhook — Trinity receives inbound messages via a Twilio webhook URL. Requires public_chat_url to be configured in Settings and a Cloudflare Tunnel ingress rule.
Email Verification — Users can verify their identity via /login to access agents with restricted access policies.

Prerequisites

Before connecting a Twilio account, two platform-level prerequisites must be in place — plus one Twilio Console setting if you want inbound attachments to work.

1. Public URL

Go to Settings → Public Chat URL and enter your Trinity instance's public domain (e.g., https://your-domain.com). Trinity uses this to generate the webhook URL shown in the UI.

2. Cloudflare Tunnel Ingress Rule

Add the following path rule in your Cloudflare Tunnel dashboard so Twilio webhooks reach the backend:

RouteBackend
/api/whatsapp/webhook/*http://backend:8000

The webhook is a backend FastAPI route (Twilio-signature verified). Routing it to the frontend service silently drops inbound messages — point it at the backend.

Without this rule, Twilio webhooks return 404 at the Cloudflare edge and never reach Trinity. The UI shows a yellow notice as a reminder.

Verify the route is working:

curl -s -o /dev/null -w "%{http_code}\n" \
  -X POST https://your-domain.com/api/whatsapp/webhook/test
# Should return 200, not 404

3. HTTP Basic Authentication for Media (required for inbound attachments)

Only needed if users will send your agent images, documents, or voice notes. Text-only agents can skip this.

Most accounts already have this and need no action. Twilio enabled HTTP Basic Authentication for media on all newly-created main accounts from 2023-07-31, without the option to disable it. Only accounts created before that date can still have it off — check the Twilio Console (Messaging → Settings → General) if inbound attachments fail.

Twilio never serves media from api.twilio.com directly — it redirects to a CDN, and which CDN depends on this setting:

Media authRedirect targetTrinity
Enabledmms.twiliocdn.com (short-lived signed URL)✅ Supported
Disableds3-external-1.amazonaws.com❌ Refused

Trinity refuses the S3 target on purpose: that hostname serves everyS3 bucket in the world under one name, so allowing it would let any URL claiming that host pull arbitrary content through Trinity's media fetcher. There is no setting to override this — enable media auth in Twilio instead.

Getting Twilio Credentials

You need three values from Twilio: Account SID, Auth Token, and a WhatsApp sender number.

Sandbox (Development)

1

Go to Twilio ConsoleMessaging → Try WhatsApp

2

Copy your Account SID and Auth Token from the top of the console

3

The sandbox sender is whatsapp:+14155238886 (shared across all Twilio sandbox users)

4

Note the sandbox join keyword shown on the Try WhatsApp page — users must send join <keyword> to the sandbox number before they can message your agent

Production

1

Twilio Console → Messaging → Senders → WhatsApp Senders

2

Register a sender — this requires linking a Meta Business Manager account

3

Display-name approval takes 24–48 hours

4

Once approved, copy the dedicated sender number in E.164 format (e.g., +14155001234)

Connect WhatsApp to an Agent

1

Open the agent detail page

2

Select the Sharing tab and find the WhatsApp row under Channels

3

Click Configure — the WhatsApp (Twilio) configuration opens in a dialog

4
Enter:
  • Twilio Account SID — starts with AC, 34 characters long
  • Auth Token — from the Twilio Console (stored encrypted)
  • WhatsApp From Number — in format whatsapp:+<E.164>, e.g. whatsapp:+14155238886
5

Click Connect

Trinity validates the credentials against Twilio and generates a webhook URL. If the validation fails, the error from Twilio is shown inline.

Wire the Webhook in Twilio

After connecting, a webhook URL appears in the UI. Copy it and paste it into Twilio:

Sandbox:

  • • Twilio Console → Messaging → Try WhatsApp → Sandbox settings
  • • Set "When a message comes in" to HTTP POST + your webhook URL

Production:

  • • Twilio Console → Messaging → Senders → your registered sender
  • • Set the webhook URL on the sender configuration

Sandbox Opt-In

For the sandbox, users must opt in before they can chat. Share these instructions with testers:

1

Open WhatsApp on your phone

2

Send a message to +1 415 523 8886

3

Type: join <your-sandbox-keyword> (shown in Twilio Console → Try WhatsApp)

4

Once Twilio confirms opt-in, the user can message the agent normally

Verify Credentials

On the connected state, click Verify to confirm the stored credentials are still valid (makes a live call to Twilio without sending a message).

Disconnect

Click Disconnectto remove the binding. The Twilio sender is not affected — only the Trinity configuration is removed.

Outbound Media & Files

Agents can deliver files and images in their WhatsApp replies, not just text. Each file is hosted transiently by Trinity (~1 hour) and sent as a Twilio media attachment — one message per file, since WhatsApp allows a single media item per message. The text reply always goes out first, so it survives even if a media send fails.

File typeDelivered asSize cap
Images, audio, videoNative media5 MB
Text and structured documents (txt, JSON, XML, PDF, YAML, SQL, …)Document16 MB
Unknown binary typesNot deliverable as media
Outbound media requires the agent's file-sharing toggle to be on (Sharing tab → Distribution → File sharing) and a configured Public Chat URL (media links must be HTTPS).
A file that is oversized, of an unsupported type, or otherwise undeliverable degrades to a 📎 name: url download link appended to the text reply — it never blocks the reply or other files.

Voice Replies (Outbound)

The agent can speak its replies as WhatsApp voice notes (OGG, delivered via Twilio media). Enable the shared Voice replies toggle inside the WhatsApp dialog — see Voice Replies. Voice notes work even when the file-sharing toggle is off; they are gated only by their own setting.

User Commands

WhatsApp users can send these commands to the agent number:

CommandAction
/login user@example.comSends a 6-digit verification code to the email address
/login 123456Submits the code and verifies the email
/logoutUnlinks the verified email from this WhatsApp number
/whoamiShows the currently verified email address

After successful /login, if the agent has a restricted access policy (require_email enabled), Trinity checks whether the verified email is on the shared-access list. If not, an access request is automatically created and the user is notified that approval is pending.

Access Control

WhatsApp respects the same cross-channel access policy as Telegram and Slack. Configure it in Agent Detail → Sharing → Channel Access Policy:

PolicyEffect
Open accessAny WhatsApp user can chat with the agent without verification
Require emailUsers must complete /login before chatting; unverified users are prompted
Require sharingUsers must be explicitly shared on the agent (owner/admin must approve)

Approving an access request (from Sharing → Access Requests) automatically adds the email to the shared-access list.

API

EndpointMethodDescription
/api/agents/{name}/whatsappGETBinding status and webhook URL
/api/agents/{name}/whatsappPUTConfigure Twilio credentials
/api/agents/{name}/whatsappDELETERemove binding
/api/agents/{name}/whatsapp/testPOSTVerify credentials or send a test message

Configure programmatically:

# Connect a Twilio account to an agent
curl -X PUT http://localhost:8000/api/agents/my-agent/whatsapp \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "account_sid": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "auth_token": "your-auth-token",
    "from_number": "whatsapp:+14155238886"
  }'

# Check binding status
curl http://localhost:8000/api/agents/my-agent/whatsapp \
  -H "Authorization: Bearer $TOKEN"

# Verify credentials (no test message sent)
curl -X POST http://localhost:8000/api/agents/my-agent/whatsapp/test \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

# Send a test message to a specific number
curl -X POST http://localhost:8000/api/agents/my-agent/whatsapp/test \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to_number": "whatsapp:+15551234567", "message": "Test from Trinity"}'

Troubleshooting

"public_chat_url is not set" warning

Go to Settings → Public Chat URLand enter your Trinity instance's public domain. The webhook URL generates automatically once saved.

Twilio webhook returns 404

The Cloudflare Tunnel ingress rule for /api/whatsapp/webhook/* is missing or misconfigured. Add it in the Cloudflare dashboard pointing to the backend service (http://backend:8000).

HMAC signature validation fails

This means the URL Twilio signed does not match the URL Trinity sees. Check that:

  • • nginx has X-Forwarded-Proto $scheme configured
  • • uvicorn runs with --proxy-headers
  • • The public_chat_url in Settings exactly matches the public URL Twilio posts to

Sandbox messages not arriving

  1. Confirm the user sent the sandbox join keyword from their phone
  2. Verify the webhook URL in Twilio Console → Try WhatsApp → Sandbox settings is set to HTTP POST
  3. Check backend logs for signature or binding errors

Credentials rejected

Twilio returns 401 if the AccountSid/AuthToken combination is invalid. Re-copy the Auth Token from the Twilio Console — it resets when you click "regenerate" in Twilio.

Inbound images arrive as "— download failed"

The agent got your message, but not the file. Check the backend log for:

[WHATSAPP] Refusing off-domain media redirect to host=s3-external-1.amazonaws.com

That host means HTTP Basic Authentication for media is not enabledon your Twilio account — see Prerequisites → 3 above. Turn it on in the Twilio Console; no Trinity restart is needed, the next attachment will work.

Any other host in that warning means Twilio changed its media CDN — that needs a Trinity fix, not a config change (the allowlist is intentionally not operator-configurable, because that fetch carries your Twilio Auth Token). Please open an issue with the logged hostname.

If the log shows no Refusing… line at all, the failure is elsewhere:

Log lineMeaning
No credentials to download media for agent=…The binding lost its Auth Token — re-save it
Media download failed (status=…)Twilio-side error (401 = bad Auth Token, 404 = media expired)
Media redirect budget exhaustedTwilio chained more than 3 redirects — please open an issue
Media exceeds transport capThe file is larger than 16 MB
Error downloading media …: ConnectError (or another type name)Network/TLS failure reaching Twilio. Only the exception type is logged, deliberately: the signed media URL is a live credential for ~4 hours and some exception messages embed it

Attachment says "unsupported format"

This is different from "download failed" — the file wasfetched successfully, then rejected by Trinity's file-type policy. PDFs, archives, video, and audio (including WhatsApp voice notes) are not accepted into agent workspaces on any channel. Text, CSV, JSON, and images are.

Limitations

Direct messages only — Twilio's WhatsApp API does not support group chats. WhatsApp groups are not available.
24-hour message window — Twilio can only send freeform messages to users who have messaged within the last 24 hours. Outside this window, Twilio returns error 63016. Approved message templates (Phase 3, not yet available) will lift this restriction for outbound-first use cases.
One Twilio account per agent — Each agent can only have one WhatsApp binding. Multiple agents cannot share the same Twilio account.
Sandbox requires opt-in — Every tester must send the join keyword before messaging. The sandbox sender is shared across all Twilio users, so keywords help route to your account.
No SMS — The binding is WhatsApp-only. SMS on the same Twilio number is not available from Trinity in this release.
Proactive messaging — WhatsApp is not included in the automatic channel fallback (auto). Agents sending proactive messages must specify channel="whatsapp" explicitly and the recipient must have a verified email linked to a prior WhatsApp conversation.