Channels
Channels are communication plugins that connect assistants to different platforms. Each channel handles inbound messages from a platform, routes them to the appropriate assistant, and delivers responses back.
Available Channels
| Channel | Type | Description |
|---|---|---|
| Browser Internal | Browser | In-app chat for logged-in admin and staff users |
| Staff Access | Browser | Staff-specific chat experience |
| Slack | Messaging | Direct messages via a Slack bot |
| Telegram | Messaging | Chat via a Telegram bot |
| Postmark | Send and receive email via Postmark | |
| WebRTC | Voice | Voice conversations via OpenAI Realtime API |
| Web Trigger | API | HTTP trigger for external services (Zapier, Make, n8n) |
The Embeddable Widget is a browser-based channel for external websites and has its own dedicated section.
How Channels Work
All inbound messages from channels flow through a generic webhook endpoint that routes by plugin name and assistant ID (e.g., /webhooks/channels/slack/42/inbound). New channel plugins get webhook routing automatically without changes to the routing layer.
Request Verification
Each channel plugin implements its own request verification. Slack uses HMAC signature verification (comparing a computed hash of the request body against the X-Slack-Signature header). Telegram uses a secret token comparison via X-Telegram-Bot-Api-Secret-Token. Unverified requests are rejected before any processing occurs.
Message Routing
The system uses two routing strategies depending on the channel type. Email-style channels embed a reply_token in reply-to addresses to match replies to existing conversations. Chat-style channels (like Telegram) use a channel_address (the sender’s chat ID) combined with the assistant ID to find or create conversations. Both strategies include deduplication by message ID to prevent double-processing from webhook retries.
Async Processing
After parsing and validation, the webhook handler dispatches message processing as an asynchronous background task and returns an immediate 200 response to the channel provider. This prevents timeout errors from providers that expect fast responses while the agent loop runs in the background.
One Conversation, Many Channels
Every message — both inbound from a user and outbound from the assistant — is stored in a canonical, channel-agnostic form. The agent doesn’t write Telegram-flavoured Markdown or Postmark-flavoured HTML; it produces a structured list of content blocks, and each channel converts that to whatever its medium needs at the moment of delivery.
The block kinds the system understands today are:
| Block | Used for |
|---|---|
| Text | Markdown prose. Renderers translate to channel-native formatting. |
| Media | Images, files, and audio attachments. |
| Card | A rich content card (title, body, optional inline image and actions). Backed by a generated content row, so the same card can also appear on the assistant canvas. |
| Data table | Structured rows and columns (e.g. dataset query results). |
| Actions | Buttons that the user can click to drive the conversation forward (see Interactive actions below). |
Because the blocks are stored on the message itself, an exchange that happened over Telegram can be reopened in the browser with text, images, and action buttons all visible. A reply email can carry the same image attachment that arrived inline on Slack. There’s no per-channel rewriting pass — the content travels untouched between mediums.
What each channel renders natively
Channels do their best with what the medium supports and fall back gracefully where it doesn’t. The matrix below summarises the v1 rendering capability:
| Block | Browser | Postmark email | Telegram | Slack | WebRTC voice |
|---|---|---|---|---|---|
| Text | HTML | HTML | MarkdownV2 | mrkdwn | TTS |
| Media (image) | inline <img> | MIME inline | sendPhoto | image block | spoken summary |
| Media (file) | link | MIME attachment | sendDocument | files API | spoken summary |
| Card | rich card | HTML card | text + photo | Block Kit | spoken summary |
| Data table | HTML table | HTML table | markdown table | Block Kit fields | spoken summary |
| Actions | HTMX buttons | URL links | inline keyboard | block actions | spoken summary |
A channel that doesn’t render a block kind natively falls back to a markdown rendering, so every block always reaches the recipient in some form.
Interactive actions
Assistants can present the user with a small set of buttons rather than asking for a free-text reply. Clicking a button is treated like a structured response: the channel routes the click back through a webhook, the conversation resumes from where it paused, and the agent receives the chosen option as the result of its question.
Action buttons render as native interactive controls where the channel supports them — Telegram inline keyboards, Slack Block Kit buttons, in-browser HTMX buttons. Where the channel can only carry text and links (email, voice transcripts), each option is rendered as a signed URL that resolves the same way when clicked. The agent’s prompt is identical regardless of which channel the user clicks from.
Configuring Channels on Assistants
Channels are enabled and configured per assistant. See Assistant Channel Configuration for details on enabling channels, setting access control, and managing feedback settings.