Channels Setup
Polyant agents can be exposed through multiple channels. Each channel is configured per-instance in the admin panel under the Channels tab. All channel credentials are AES-256-GCM encrypted at rest.
Three channels are built in: Telegram, Slack, and WhatsApp (via Twilio). The OpenAI-compatible HTTP API is always on (no setup required).
Telegram
Protocol: Long polling (via grammY ).
Prerequisites
- A Telegram account
@BotFatherbot token
Setup
- Open Telegram and start a chat with
@BotFather. - Send
/newbot, pick a name and username for your bot. - Copy the HTTP API token BotFather gives you (looks like
1234567890:ABC...). - In the Polyant admin panel → your instance → Channels tab → Telegram.
- Paste the token. Optionally, fill Allowed User IDs with a comma-separated list of numeric Telegram user IDs to restrict who can talk to the bot — leave empty to accept everyone.
- Click Save & Start.
Usage
The adapter starts long-polling immediately. Users can now send messages to your bot on Telegram. Photos and documents are downloaded, stored, and passed to the LLM as multimodal content.
Supported attachments
- Photos (JPG, PNG, WebP) → passed as vision input
- Documents (PDF, images) → stored in S3, passed to the LLM
Slack
Protocol: Socket Mode (via @slack/bolt ).
Prerequisites
- A Slack workspace where you can install apps
- An admin account (or app-installer permission)
Setup
- Go to api.slack.com/apps → Create New App → From scratch.
- Enable Socket Mode in the sidebar; generate an App-Level Token with
connections:writescope. Copy it (starts withxapp-). - In OAuth & Permissions, add these Bot Token Scopes:
chat:writeim:historyim:readim:writeapp_mentions:readchannels:historygroups:historyfiles:read(if you want file attachments)
- Install the app to your workspace; copy the Bot User OAuth Token (starts with
xoxb-). - In Basic Information → App Credentials, copy the Signing Secret. It is required by Polyant to verify request signatures.
- In Event Subscriptions, enable events and subscribe to:
message.immessage.channels(for channel mentions)app_mention
- In the Polyant admin panel → your instance → Channels tab → Slack.
- Fill in:
- Bot Token (
xoxb-...) - App Token (
xapp-...) - Signing Secret (from step 5)
- Bot Token (
- Click Save & Start.
Usage
DM your bot directly, or mention it in a channel. The adapter handles both. Rich Slack formatting (blocks, code blocks) is supported.
WhatsApp (via Twilio)
Protocol: Webhook (via Twilio’s Messaging API).
Prerequisites
- A Twilio account
- A WhatsApp-enabled Twilio phone number (sandbox or production)
- A public URL for the webhook (use ngrok for local development)
Setup
-
In the Twilio Console → Messaging → Try it out → Send a WhatsApp message → get your sandbox number (e.g.
+14155238886) and join code. -
Under Account → API keys & tokens, copy your Account SID and Auth Token.
-
In the Polyant admin panel → your instance → Channels tab → WhatsApp.
-
Fill in:
- Account SID (
AC...) - Auth Token
- From number (e.g.
whatsapp:+14155238886)
- Account SID (
-
The webhook URL for your instance is:
https://<your-engine-host>/webhooks/twilio/<instance-slug>/whatsapp(mounted by
TwilioWebhookControlleratpackages/engine/src/server/channels/twilio-webhook.controller.ts:25,29). -
In the Twilio Console, set that URL as the WHEN A MESSAGE COMES IN webhook for your WhatsApp sender. Twilio signs every request with your Auth Token, and the engine verifies the signature before processing.
-
Click Save & Start in the admin panel.
Inbound typing indicator
On every inbound WhatsApp message, Polyant fires a typing indicator against Twilio’s /v2/Indicators/Typing.json endpoint. The user sees the animated “typing…” dots until the agent’s response is delivered. As a documented side-effect, Twilio also marks the inbound message as read (double blue check).
Message debouncer
When a user sends several short messages in quick succession (a common pattern on WhatsApp/Telegram), Polyant collapses them into a single pipeline run to avoid firing the LLM multiple times on fragments of one thought. Three env vars tune the behavior:
MESSAGE_SOFT_DEBOUNCE_MS— the quiet window after a fragment before the pipeline fires (default2000). New fragments inside the window reset the timer.MESSAGE_TYPING_DELAY_MS— how long after the first fragment Polyant shows the WhatsApp typing indicator (default1500).MESSAGE_MAX_RESTARTS— the maximum number of consecutive cancel-and-restart cycles when a fragment arrives mid-pipeline (default3). Beyond this, late fragments accumulate and are flushed in a follow-up run.
Supported attachments
- Photos → vision input
- PDFs and documents → stored in S3 (if configured), passed to the LLM as multimodal content
Agent (in-process)
Protocol: virtual, in-process function call — no network, no credentials.
Enable the agent channel on an instance to make it callable from any other instance via a synthesized ask_<slug> tool. The Supervisor of the caller invokes the callee as if it were a regular tool; depth is capped at 1 (a callee cannot call a third agent) and each call is bounded by AGENT_CALL_TIMEOUT_MS (default 60s).
There is nothing to configure beyond toggling the channel on in the Channels tab. See Channels → Agent-to-agent for the full picture.
OpenAI-compatible HTTP API
This channel is always on. Every instance is exposed as a selectable model at POST /v1/chat/completions:
curl -s http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "your-instance-slug", "messages": [{"role":"user","content":"hi"}]}'To require authentication for this endpoint:
- In the instance Settings tab, open the API Authentication section and toggle Require authentication on (this sets
authEnabled = trueon the instance). - Add an entry to Secrets with key
auth_api_key(the bearer token clients must present). - Clients now need to send
Authorization: Bearer <auth_api_key>.
Per-instance architecture
All channel adapters are per-instance. Starting a Slack channel for instance A does not affect instance B. Adapters start and stop dynamically when you save/delete a channel config — no engine restart needed.
Channel config is stored in the instance_channels table, encrypted with your ENCRYPTION_KEY.
Where to look when something does not work
| Symptom | Likely cause | Where to fix |
|---|---|---|
| Telegram bot does not reply | Wrong token, or two engines polling with the same token (Conflict: terminated by other getUpdates in the engine logs) | Regenerate the token via BotFather, or stop the duplicate engine |
| Some Telegram users are silently ignored | The Allowed User IDs whitelist on the Channels tab excludes them | Add their numeric user id, or clear the field to accept everyone |
| Slack: app cannot connect | App token missing the connections:write scope, or Socket Mode disabled | Re-check the Slack app settings, then Reinstall app |
Slack: missing_scope in engine logs | One of the bot scopes was not granted | Read the missing scope from the error, add it on the Slack side, reinstall |
| WhatsApp: nothing happens | Webhook URL not reachable from Twilio (typical when running locally without a tunnel) | Test with curl from outside; expose the engine via ngrok or a public host |
| WhatsApp sandbox stopped working after 72 h | Twilio sandbox sessions expire on inactivity | Send join <sandbox-code> again from the test phone |
For deeper troubleshooting (login, database, provider) see Troubleshooting.