Messaging
Connect Slack and WhatsApp, and chat with them from inside Hrida AI Studio.
The Messaging plugin gives you a two-way bridge to Slack and WhatsApp Business: messages sent to a connected account are cached in real time via webhook, you can read and reply to them from the Dashboard > Messaging page, and — once linked — a chat-selectable AI assistant (Slack Chat Assistant / WhatsApp Chat Assistant) can read and send messages on your behalf from a normal Hrida chat, the same way the Email Triage Assistant works for a connected inbox.
Each platform is enabled independently and only visible once an admin has installed it under Admin Settings > Messaging. See Admin Setup below.
Slack and WhatsApp are not symmetric
Both platforms share one architecture (accounts, a webhook receiver, a Tool + Pipe pair, access control), but their underlying APIs are genuinely different, and that shows up in what you can do:
| Slack | ||
|---|---|---|
| Credential | One Bot User OAuth Token | Phone Number ID + Access Token |
| Webhook verification | POST, signed, JSON challenge/response | GET, hub.challenge handshake, plain-text response |
| Listing conversations | Live API call (conversations.list) | Not supported by Meta's Cloud API — derived from cached message history instead |
| Message history | Live API call (conversations.history) | Not supported by Meta's Cloud API at all — only what's arrived via webhook is available |
| Sending a reply | Always allowed | Only within 24h of the customer's last message — a pre-approved template is required outside that window |
None of this is a limitation of the plugin — it's what each platform's own API actually allows.
Admin Setup
1. Install the plugins
Go to Admin Settings > Messaging. It has one tab per platform (Slack / WhatsApp), each with an identical install flow:
- Toggle Enable {Platform} Plugin — this only controls whether the Messaging tab is visible in the Dashboard sidebar for regular users; it doesn't install anything by itself.
- Fill in Hrida API URL (leave as the default internal address unless your deployment's internal port differs from 8080) and API Key.
- Click Install for All Users.
This registers two components per platform:
| Plugin | Type | ID (Slack) | ID (WhatsApp) |
|---|---|---|---|
| Manager | Tool | slack_manager | whatsapp_manager |
| Chat Assistant | Pipe (function) | slack_chat_assistant | whatsapp_chat_assistant |
The install is idempotent — click it again after an update and it re-syncs both components from the latest source, owned by whichever admin clicked it, with a public read grant so every user can attach the Tool / select the Pipe.
Unlike the Chat Assistant pipe (which falls back to your own signed-in session token), the Manager Tool always calls the API using the HRIDA_API_KEY valve directly — every /api/v1/messaging/… endpoint requires authentication, so an empty key means every tool call fails outright. Generate a key under Settings > Account > API Keys, ideally for a dedicated service account, and paste it in before installing.
2. Pipe settings (optional)
Both Chat Assistant pipes expose the same tunables as Email's (gear icon under Admin > Workspace > Functions):
| Valve | Default | Notes |
|---|---|---|
MODEL_ID | (empty) | Model that writes the replies; empty falls back to the Task Model |
TRIAGE_SYSTEM_PROMPT | Built-in persona | Customize the assistant's instructions |
AUTO_TRIAGE_ON_LOAD | true | Include a digest of recent cached messages in the context of every reply |
AUTO_TRIAGE_LIMIT | 15 | Max cached messages pulled into that digest |
Setting up an account
Go to Dashboard > Messaging, pick the Slack or WhatsApp tab, and click + Add Account. The form fields are driven entirely by the provider's own config schema — you're not filling out a fixed form, you're filling out whatever that platform actually needs:
Slack
| Field | Where to get it |
|---|---|
| Bot User OAuth Token | Create a Slack app at api.slack.com → OAuth & Permissions, grant chat:write, channels:read, channels:history, im:history (add im:write too if you want the bot to open DMs), install to your workspace → copy the xoxb-… token |
| Signing Secret | Same app's Basic Information page |
| Default Channel ID | Optional — used when a tool call doesn't specify a channel |
After saving, copy the account's Webhook URL (shown in the detail panel) into that same Slack app's Event Subscriptions as the Request URL, and subscribe to the message.channels / message.im bot events. Slack immediately POSTs a verification challenge to that URL — confirming Slack's UI shows "Verified" proves the account is wired correctly end to end.
WhatsApp
| Field | Where to get it |
|---|---|
| Phone Number ID | Meta App Dashboard → WhatsApp → API Setup |
| Access Token | Same page — use a permanent/long-lived token for anything beyond testing |
| Webhook Verify Token | Any string you choose — you'll set the same value again in Meta's dashboard |
| App Secret | Meta App Dashboard → App Settings → Basic — used only to verify inbound webhook signatures, not the same value as the verify token above |
| Business Account ID | Optional — only needed to list approved message templates |
After saving, set the account's Webhook URL plus your Webhook Verify Token in Meta's App Dashboard → WhatsApp → Configuration, then click "Verify and Save" — this is a one-time GET request/response handshake (distinct from Slack's POST/JSON one), and Meta's UI will show it verified once your token matches.
Access control
Every account has an Access section in its form (the same component Tools/Models/Knowledge use): by default a newly created account is private to you, but you can grant specific users or groups read (view/use) or write (edit/delete/send) access, or make it public. This matters more here than it does for Email — a Slack bot token or WhatsApp number typically belongs to a whole team, not one person, so the normal flow is: one person (often an admin) creates the account and grants the rest of the team access to it, rather than everyone connecting their own.
Testing the connection: click Test Connection in the account detail panel — for Slack this calls auth.test; for WhatsApp it fetches the phone number's own metadata to confirm the access token is valid.
Linking your account to the Chat Assistant
- In Dashboard > Messaging, select your account and copy its Account ID.
- Open a new chat and select Slack Chat Assistant (or WhatsApp Chat Assistant) as the model.
- Open its Chat Controls panel → Valves, and paste the Account ID into
account_idunder User Valves.
This is the same UserValves.account_id pattern Email uses — one account, shared via its ID, linked independently by each user who wants to use it from chat.
Using the Chat Assistant
The first message of a new chat triggers a digest of recent activity, injected into the assistant's context automatically. From there:
- "What's happening in #general?" / "Any new WhatsApp messages?"
- "Send a message to [channel/number] saying …"
- "Search for messages about the Q3 report"
Slack digest example:
💬 Slack Digest — 2026-08-14 09:30 UTC
Account: Engineering workspace
#general (3 recent messages)
← alice: Can someone review PR #482?
→ You: On it
← bob: Thanks!
WhatsApp digest example — note the per-conversation window status, computed from the same cached data the digest already fetched (no extra API call):
📱 WhatsApp Digest — 2026-08-14 09:30 UTC
Account: Support line
+15551234567 (2 recent, 🟢 free-form OK)
← Hi, is my order still on track?
→ Yes! Shipping today.
+15559876543 (1 recent, 🔴 template required)
← Thanks for your help last week
The WhatsApp 24-hour window, in practice
If you ask the assistant to message someone outside that window, it won't guess at a template on your behalf — it responds with the available template names and asks you to either pick one explicitly or wait for the customer to message first. From the Dashboard UI, the same rule shows up as an automatic switch: the plain text box is replaced with a template picker whenever the selected conversation's window has closed.
Security
- Fernet encryption: account credentials (bot tokens, access tokens, signing/app secrets) are encrypted with a key derived from the instance's
HRIDAAI_SECRET_KEY, the same mechanism Email's account credentials use — never returned in API responses, logs, or error messages. - Webhook signature verification: every inbound webhook is verified before anything else happens — Slack via HMAC-SHA256 over
v0:{timestamp}:{body}(X-Slack-Signature, with a 5-minute replay window), WhatsApp via HMAC-SHA256 over the raw body using the App Secret (X-Hub-Signature-256). This includes the one-time verification handshake itself — Slack signs that request exactly like any other Events API call, so it's verified first, not treated as a special unauthenticated case. - Idempotency: duplicate webhook deliveries (Slack retries aggressively on any slow or non-2xx response) are deduplicated via a 60-second Redis window per message ID.
- Access-grant enforcement: every account, connection-test, conversation, message, and send endpoint checks the caller's access (owner, admin, or an explicit grant) before doing anything — see Access control above.
Troubleshooting
Slack shows "unable to verify" when saving the Events Request URL
Confirm the account's Signing Secret matches the Slack app's current Basic Information page — regenerating it in Slack invalidates the old value. Also confirm the webhook URL is reachable from the public internet (Slack cannot reach localhost).
WhatsApp verification fails in Meta's dashboard
The Webhook Verify Token you entered when creating the account must exactly match what you type into Meta's Configuration screen — these are two independent places holding the same string, not something the account reads back from Meta. If they don't match, or you're confusing this with the App Secret (a different field, used only for signature verification, never sent to Meta as a verify token), the handshake will fail.
The Chat Assistant's tool calls fail immediately
Almost always the HRIDA_API_KEY valve is blank or invalid — see the warning under Admin Setup. Unlike the pipe itself, the Manager Tool never falls back to your session token.
"Cannot send a free-form message" on WhatsApp
Expected behavior, not an error — the 24-hour customer service window has closed for that conversation. Use a template (send_template from the assistant, or the template picker in the Dashboard) instead.
No messages appearing after connecting
- Confirm the webhook handshake actually succeeded (see the two verification sections above) — a broken handshake means Slack/Meta never registered the URL and will never deliver anything to it.
- Send a real test message to the connected number/channel and check Dashboard > Messaging for it within a few seconds.
- Check server logs for
Messaging webhook: account=… platform=… processed=…— if it's not appearing at all, the request likely isn't reaching your server (firewall, tunnel, or DNS issue), not a plugin bug.
API reference
All messaging endpoints are under /api/v1/messaging.
# Providers
GET /api/v1/messaging/providers
GET /api/v1/messaging/providers/{platform}/schema
# Account management
GET /api/v1/messaging/accounts ?platform=slack|whatsapp
POST /api/v1/messaging/accounts
GET /api/v1/messaging/accounts/{id}
PATCH /api/v1/messaging/accounts/{id}
DELETE /api/v1/messaging/accounts/{id}
# Connection test
POST /api/v1/messaging/accounts/{id}/test
# Conversations / message cache / send
GET /api/v1/messaging/accounts/{id}/conversations
GET /api/v1/messaging/accounts/{id}/cache ?conversation_id=&skip=&limit=
POST /api/v1/messaging/accounts/{id}/send # {"conversation_id", "text"}
# WhatsApp-only
GET /api/v1/messaging/accounts/{id}/can-send-freeform ?conversation_id=
GET /api/v1/messaging/accounts/{id}/templates
POST /api/v1/messaging/accounts/{id}/send-template # {"conversation_id", "template_name", "language", "params"}
# Plugin install (admin only)
POST /api/v1/messaging/plugin/install/slack # {"hrida_api_url", "hrida_api_key"}
POST /api/v1/messaging/plugin/install/whatsapp # {"hrida_api_url", "hrida_api_key"}
# Inbound webhook receiver — one per account, not called directly by clients
GET/POST /api/v1/webhooks/messaging/{account_id}