Skip to Content
Polyant is open source under AGPL-3.0 — star us on GitHub.
Getting StartedConnect a Channel

Channels Setup

On this page

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 messaging channels are built in: Telegram, Slack, and WhatsApp (via Twilio). The OpenAI-compatible HTTP API is the Web/API channel, and like the others it starts off on a new agent (see below).

A managed-services deployment adds four more - the synchronous REST channel, Email, HubSpot and Voice for phone calls through Twilio. This page walks through the built-in three; the field reference for every channel is Channels, which also says where each provider keeps the values you are asked for.

Once a channel is saved, test it: the Test control under its credentials exercises them against the provider, read-only, and names what it cannot verify from here. Telegram, Slack, WhatsApp, Email and HubSpot all have it.

Telegram

Protocol: HTTPS webhook (via grammY ). The engine needs a public HTTPS address, and /webhooks/* must reach it.

Prerequisites

  • A Telegram account
  • @BotFather bot token

Setup

  1. Open Telegram and start a chat with @BotFather.
  2. Send /newbot, pick a name and username for your bot.
  3. Copy the HTTP API token BotFather gives you (looks like 1234567890:ABC...).
  4. In the Polyant admin panel → your instance → Channels tab → Telegram.
  5. 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.
  6. Set the channel to On and save from the page header.

Usage

The engine registers https://<engine-base-url>/webhooks/telegram/<instance-slug> with Telegram when the channel starts. Set the engine’s public address (in Installation policies, or BASE_URL) to a public HTTPS address before enabling it. Users can then message your bot. 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: Events API over HTTPS (via @slack/bolt ). The engine needs a public HTTPS address, and /webhooks/* must reach it.

Prerequisites

  • A Slack workspace where you can install apps
  • An admin account (or app-installer permission)

Setup

  1. Go to api.slack.com/apps  → Create New App → From scratch.

  2. Keep Socket Mode off. Make sure the engine’s public address (in Installation policies, or BASE_URL) is its public HTTPS address.

  3. In OAuth & Permissions, add these Bot Token Scopes:

    • chat:write
    • app_mentions:read
    • im:history
    • im:write
    • users:read (optional: lets replies use people’s names; without it the adapter uses the raw user id)

    The first four are the ones the channel cannot work without, and the ones the channel’s Test checks. The adapter ignores uploaded files, so files:read is not needed.

  4. Install the app to your workspace; copy the Bot User OAuth Token (starts with xoxb-).

  5. In Basic Information → App Credentials, copy the Signing Secret. It is required by Polyant to verify request signatures.

  6. In the Polyant admin panel → your instance → Channels tab → Slack. Fill in the Bot Token and Signing Secret, set the channel to On, and save.

  7. In Event Subscriptions, enable events. Paste the Slack Events API Request URL shown on that page (https://<engine-base-url>/webhooks/slack/<instance-slug>), then subscribe to:

    • message.im - direct messages
    • app_mention - mentions in a channel
    • message.channels (optional; the adapter deliberately ignores non-DM messages, answering channel traffic only on an explicit mention)

    The first two are the ones the adapter listens for. Scopes without these subscriptions produce an agent that connects, logs nothing wrong, and never answers.

  8. Send the bot a DM to verify delivery. Slack validates the Request URL when you save it; the channel must already be On for that check.

Each agent you want to reach directly on Slack needs its own Slack app and its own Events API Request URL (/webhooks/slack/<instance-slug>). You can also connect one agent to Slack and let it consult other agents through ask_<slug> delegation: enable the Agent-to-Agent channel on each agent it will call, then enable the corresponding agent:<slug> tools in the Slack agent’s Tools section and click Save changes. See Agent (in-process) for the setup.

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

  1. In the Twilio Console → Messaging → Try it out → Send a WhatsApp message → get your sandbox number (e.g. +14155238886) and join code.

  2. Under Account → API keys & tokens, copy your Account SID, and then either your Auth Token or a newly created API key (its SK… SID and its secret - Twilio shows the secret once).

  3. In the Polyant admin panel → your instance → Channels tab → WhatsApp.

  4. Pick a credential mode, and fill in what it asks for:

    ModeFill in
    Auth TokenAccount SID (AC…), Auth Token, From number (e.g. +14155238886)
    API KeyAccount SID (AC…), API Key SID (SK…), API Key Secret, From number

    The From number is stored without the whatsapp: prefix - the field accepts a plain E.164 number (+ followed by digits) and rejects anything else. Account SID must be AC plus 32 hex characters, API Key SID SK plus 32.

    Auth Token is the mode an existing setup is already in, and the one that keeps Twilio’s request signature as the inbound authentication. API Key uses a credential you can revoke on its own in Twilio, and authenticates inbound with a secret in the webhook URL instead.

  5. Save. The webhook URL depends on the mode you chose:

    • Auth Token:

      https://<your-engine-host>/webhooks/twilio/<instance-slug>/whatsapp
    • API Key - the engine mints the secret on that first save and shows the whole URL on the WhatsApp card, with a copy button:

      https://<your-engine-host>/webhooks/twilio/<instance-slug>/whatsapp/<webhook-secret>
  6. In the Twilio Console, set that URL as the WHEN A MESSAGE COMES IN webhook for your WhatsApp sender. In Auth Token mode Twilio signs every request with your Auth Token and the engine verifies the signature before processing; in API Key mode the secret in the path is the credential, compared in constant time.

  7. Set the channel to On and save it from the WhatsApp card’s own Save button.

Changing mode later means re-pasting the URL in Twilio. Saving a mode change discards the other mode’s credentials, the minted webhook secret included, so whatever URL the Console currently holds starts answering 404. That applies to going back, too.

Behind a reverse proxy, set TRUST_PROXY to the number of hops - but only Auth Token mode needs it. The signature is checked against the URL the engine reconstructs, so unhonoured X-Forwarded-* headers make every inbound request fail verification. An API Key channel is unaffected.

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 per-agent values in the agent’s Behaviour overrides tune the behavior:

  • Burst window (ms) - the quiet window after a fragment before the pipeline fires (default 2000). New fragments inside the window reset the timer.
  • Typing indicator delay (ms) - how long after the first fragment Polyant shows the WhatsApp typing indicator (default 1500).
  • Max restarts - the maximum number of consecutive cancel-and-restart cycles when a fragment arrives mid-pipeline (default 3). 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-to-Agent channel on an instance to make it selectable as an agent:<slug> tool by other instances in the same organization. In the calling instance’s Tools section, enable that tool and click Save changes. The Supervisor exposes it as ask_<slug> at runtime. 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 the agent-to-agent call timeout, an installation policy (default 60s).

The channel is configured in the Channels section of the instance you want to call, and the tool is enabled on the caller. See Channels → Agent-to-agent for the full picture.

OpenAI-compatible HTTP API

Each agent is exposed as a selectable model at POST /v1/chat/completions, but only while its Web channel is on. A new agent starts with Web off and with authentication required, so the endpoint answers 404 until you switch it on:

  1. In the agent’s Channels section, pick Web/API.
  2. Leave Require authentication on and click Generate key (or type your own key in API Key). Copy the key now: once saved it can no longer be shown, only replaced. It is stored as the agent’s auth_api_key, the bearer token clients must present.
  3. Switch Web channel enabled on and save from the page header. The engine refuses to enable Web while authentication is on and no key is saved.
  4. Clients now send Authorization: Bearer <auth_api_key>:
curl -s http://localhost:4000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $AGENT_API_KEY" \ -d '{"model": "your-instance-slug", "messages": [{"role":"user","content":"hi"}]}'

Turning Require authentication off asks you to accept the risk first: with it off and Web on, anyone who can reach the engine and knows the slug can talk to the agent, which suits a public agent and nothing else. Agents that existed before the upgrade to 1.2.0 kept Web on and their authentication setting. The panel’s Playground works with Web off and needs no key.

The same card maps a request’s context onto the conversation state; see Channels → Web/API.

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

SymptomLikely causeWhere to fix
Telegram bot does not replyWrong token, inaccessible public HTTPS Base URL, or a webhook still pointing at another deploymentRun the channel Test, check the platform Base URL and Telegram webhook status, then restart the channel to register its URL again
Some Telegram users are silently ignoredThe Allowed User IDs whitelist on the Channels tab excludes themAdd their numeric user id, or clear the field to accept everyone
Slack: no messages arriveSocket Mode is still on, the Events API URL is wrong, or subscriptions are missingTurn Socket Mode off, check the Request URL and subscriptions, then test with a DM
Slack: missing_scope in engine logsOne of the bot scopes was not grantedRead the missing scope from the error, add it on the Slack side, reinstall
WhatsApp: nothing happensWebhook 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 hTwilio sandbox sessions expire on inactivitySend join <sandbox-code> again from the test phone
A channel was just configured and nothing worksSomething on the provider’s side, or a credentialRun the channel’s Test before reading further down this table: it separates “our credentials are wrong” from “their side is not wired up”, which most of the rows below are variations of
Email: inbound never arrivesThe inbound URL is not configured in the provider’s console, or it was rotated afterwardsCopy the URL from the Email card and paste it into the provider
Email: the agent stops mid-threadThe per-thread reply cap - 10 replies an hour - or a header gate that read the message as machine-generatedCheck the thread’s traffic before treating it as a fault
HubSpot: the agent receives but never repliesNo Sender actor ID on the channel - a reply has no actor to be attributed toSet it on the HubSpot card

For deeper troubleshooting (login, database, provider) see Troubleshooting.

Last updated on