Build
Channels
Every messaging platform is a single ChannelAdapter object implementing one interface — the dashboard, dispatcher and Workflow Builder never special-case a platform by name.
The ChannelAdapter interface
Defined once in src/channels/types.ts and registered per-platform in src/channels/registry.ts.
| verifyWebhook(req, secret) | Verify request authenticity (header secret or HMAC) before trusting the payload. |
| parseUpdate(body) | Translate the platform's raw payload into a NormalizedUpdate. |
| send(channelId, msg, token) | Send an outbound message via the platform's own API. |
| setWebhook(token, url, secret) | Register the webhook URL for a bot. |
| validateToken(token) | Validate a bot token/credential set, returning a ChannelIdentity — throws if invalid. |
| getIdentity(token) | Return bot identity (name, username, id) without validating. |
Looking up an adapter
import { getAdapter, isAdapterReady } from "@/channels/registry";
const adapter = getAdapter("TELEGRAM");
if (isAdapterReady("REDDIT")) { /* not yet — stub adapter */ }Normalized types
Every adapter translates its platform's payload into the same shapes, so modules and the dispatcher stay channel-agnostic: NormalizedUpdate, NormalizedMessage, NormalizedCallback, NormalizedUser, NormalizedChannel, NormalizedAttachment, NormalizedButton and NormalizedOutbound. Existing Telegram-specific handlers keep working unchanged — the dispatcher tries normalized handlers first, falling back to Telegram-specific ones only when platform === "TELEGRAM".
Platforms
TelegramLive
Connect via BotFather token — live in minutes
DiscordLive
Connect via Discord Developer Portal credentials
WhatsAppLive
Connect via WhatsApp Cloud API (Meta Business)
InstagramLive
Connect via Instagram Messaging API (Meta Business)
MessengerLive
Connect via Facebook Messenger Platform (Meta Business)
Website ChatLive
Embed a live chat widget on your own website
RedditPlanned
Subreddit automation — on the roadmap