The Universal Multi-Channel Messaging SDK for AI Agents, Autonomous Systems & Microservices
English | Tiếng Việt | 中文
One SDK, every inbox. ChannelHub unifies Zalo, Telegram, Messenger, TikTok, Discord, Slack, WhatsApp/SMS (Twilio), Email, GitHub and Calendar behind a single, strongly-typed
UnifiedMessagecontract — with a built-in MCP server, a live web dashboard, and zero heavy runtime dependencies. Write your agent's communication logic once; run it everywhere.
- Why ChannelHub?
- Channel Capability Matrix
- Performance Benchmarks
- How It Works Deep Dive
- Installation
- Quick Start (Zero-Config)
- Channel Adapters
- Advanced Engine Features
- Rich Media, Stickers & GIFs
- SmartStreamer for LLMs
- CLI Toolkit
- Model Context Protocol (MCP) Server
- Live Dashboard
- Security Hardening
- License
| Capability | What you get | |
|---|---|---|
| 🔌 | Unified Multi-Platform API | Write your agent's communication logic once; execute identically across TikTok, Zalo, Telegram, Discord, Messenger and Slack. |
| 🤖 | AI-Native MCP Daemon | Built-in Model Context Protocol stdio server exposing 30+ high-level tools for Claude Desktop, Hermes Agent, OpenClaw and Codex. |
| 🌊 | SmartStreamer Token Batcher | Converts LLM token streams into real-time in-place message edits or sentence-boundary chunks — without hitting rate limits. |
| 🧅 | Onion Middleware Pipeline | Express/Koa-style hub.use() to intercept, modify or short-circuit any message. |
| 🛡 | Backpressure & Bounded Ingress Queue | Built-in 2,000-item buffer with async-generator drain waiters to avoid memory leaks during message spikes. |
| 🎬 | Video Engine & 100MB Uploads | Native resumable upload of video assets up to 100MB on Meta Messenger, plus an AI-Shorts VideoEngine (FFmpeg / Shotstack). |
| 🐱 | Native Sticker & GIF Engine | Send stickers and animated GIFs natively across all supported platforms. |
| 📊 | Live Web Dashboard | One-line traffic dashboard — message counts, active users, hourly heatmap — with zero extra dependencies. |
| 🪶 | Zero Heavy Core | The engine depends exclusively on the Node.js / Bun standard library (node:events, native fetch, node:crypto). |
| Channel | Outbound Send | Inbound Ingestion | Rich Media & Attachments | Native Reactions | Streaming & Typing | Auth Mode | Current Status |
|---|---|---|---|---|---|---|---|
| 🔵 Zalo | ✅ Full API | ✅ Listener / Polling | ✅ Image, Video, File, Sticker, GIF | ✅ Full Native | ✅ Typing & Sentence Stream | Session Cookie / OA Token | Stable Inbound/Outbound |
| ✅ Bot API | ✅ Polling & Webhook | ✅ Photo, Video, File, Sticker, GIF | ✅ Full Native | ✅ In-place Edit Stream | Bot Token | Stable Inbound/Outbound | |
| 🎵 TikTok | ✅ Business API v1.3 | ✅ HMAC Webhook (message.receive) |
✅ Images (via media_id) |
❌ N/A | ❌ N/A | OAuth2 Access-Token | Stable Webhook Inbound/Outbound |
| 💬 Messenger | ✅ Graph API v19.0 | ⚡ Webhook Normalizer | ✅ Image, Video (100MB), File, Sticker | ⏳ Planned | ⚡ Typing Indicator | Page Token & Secret | Stable Outbound + Normalizer |
| 🎮 Discord | ✅ Bot REST API | ⚡ Webhook Normalizer | ✅ Embeds & Attachments | ✅ Full Native | ⚡ In-place Edit Stream | Bot Token | Stable Outbound + Normalizer |
| 💼 Slack | ✅ Web API / Chat | ⚡ Events Normalizer | ✅ Files & Blocks | ⏳ Planned | ⚡ Typing Indicator | Bot Token | Stable Outbound + Normalizer |
| 📱 Twilio | ✅ WhatsApp / SMS / MMS | ✅ HMAC Webhook | ✅ Media via URL | ❌ N/A | ❌ N/A | Account SID & Auth Token | Stable Inbound/Outbound |
Measured on standard development hardware (Bun v1.4.2 / Node v26.3 runtime, x64 Windows 11). Run bun run bench to reproduce locally:
| Subsystem | Metric | Measured Result | Latency / Overhead |
|---|---|---|---|
| Idempotency Cache | Sliding-window deduplication | 3,500,000+ ops/sec | ~280 ns / op |
| Token Bucket Limiter | Egress rate throttle & burst control | 2,300,000+ ops/sec | ~430 ns / op |
| Ingress Pipeline | Dedup + Context Wrap + Backpressure Queue | 640,000+ msgs/sec | ~1.5 µs / message |
| SmartStreamer | LLM sentence boundary batching & typing pulse | Instant (< 2ms) | Sub-millisecond |
# Execute the benchmark suite
bun run bench ┌──────────────────────────────────────────┐
│ Your Application / │
│ AI Agent Framework │
└────────────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────────────┐
│ ChannelHub │
│ (Core Event Engine) │
└─────────┬──────────┬──────────┬──────────┘
│ │ │
┌──────────────────┴──┐ │ ┌──┴──────────────────┐
▼ ▼ ▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ TikTok │ │ Messenger │ │ Zalo │ │ Telegram / │
│ Business │ │ Adapter │ │ Adapter │ │ Discord/Slack │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │ │
▼ ▼ ▼ ▼
TikTok Business Meta Graph API zca-js Web API Bot Gateways &
Messaging API Resumable Upload & OA v3 API REST Webhooks
Every incoming payload — regardless of originating protocol (TikTok Webhook, Telegram Polling, Discord WebSocket, Meta Graph API) — is normalized into an immutable, cross-platform standard representation:
export interface UnifiedMessage {
id: string; // Normalized message identifier
channel: ChannelType; // "tiktok" | "zalo" | "telegram" | "discord" | "slack" | "messenger"
sender: {
id: string;
name?: string;
username?: string;
avatarUrl?: string;
isBot?: boolean;
};
chat: {
id: string;
type: "dm" | "group" | "channel";
title?: string;
};
content: {
text: string;
attachments?: MediaAttachment[];
replyToId?: string;
};
raw: unknown; // Original vendor payload preserved for platform-specific access
timestamp: number;
}When an event occurs, ChannelHub constructs a MessageContext wrapper around the event. This decouples message reply logic from the underlying protocol:
- Calling
await ctx.reply("Hello")automatically resolves the originating channel, routes through the target adapter, manages rate-limiting queues, and emits typing indicators. - Calling
await ctx.sendMedia({ type: "image", source: "./image.png" })validates local paths against directory traversal, detects MIME headers, and handles chunked file uploading seamlessly.
# Bun (Recommended)
bun add @theowlops/channelhub
# NPM
npm install @theowlops/channelhub
# PNPM
pnpm add @theowlops/channelhub
# Yarn
yarn add @theowlops/channelhubGet started in 3 simple steps. ChannelHub handles all the boilerplate for you!
Run the interactive init command in an empty folder:
mkdir my-bot && cd my-bot
npx @theowlops/channelhub init(This automatically creates .env, bot.ts, and package.json for you).
Open the newly created .env file and paste your bot tokens (e.g., from @BotFather for Telegram).
Install dependencies and start the bot:
bun install # or npm install
bun bot.ts # or npx tsx bot.tsNot working? ChannelHub comes with a built-in doctor to check your environment and tokens. Run:
npx @theowlops/channelhub doctorOr skip scaffolding entirely and wire a bot + live dashboard by hand:
import { ChannelHub, TelegramChannelAdapter } from "@theowlops/channelhub";
const hub = new ChannelHub();
hub.register(new TelegramChannelAdapter({ botToken: process.env.TELEGRAM_BOT_TOKEN }));
hub.onMessage(async (ctx) => {
await ctx.reply(`Echo: ${ctx.message.content.text}`);
});
await hub.dashboard(); // 📊 live dashboard → http://127.0.0.1:8790
await hub.startAll();Supports TikTok Business Messaging API v1.3. Handles inbound webhooks with timing-safe HMAC-SHA256 signature verification and replay prevention.
import { TikTokBusinessAdapter } from "@theowlops/channelhub/channels/tiktok";
const tiktok = new TikTokBusinessAdapter({
appId: "YOUR_TIKTOK_APP_ID",
clientSecret: "YOUR_TIKTOK_CLIENT_SECRET",
accessToken: "YOUR_TIKTOK_ACCESS_TOKEN",
maxWebhookAgeSeconds: 300 // Replay attack protection (default 300s)
});
// In your HTTP server (Fastify, Express, Bun.serve)
app.post("/webhook/tiktok", async (req, res) => {
const verified = await tiktok.handleWebhook(req.rawBody, req.headers["tiktok-signature"]);
if (!verified) return res.status(401).send("Unauthorized");
return res.status(200).send("OK");
});ChannelHub provides two native Messenger integrations:
1. Meta Graph API (Official Page Bot) Supports webhook challenge verification, permissions discovery, and large file support.
import { MessengerChannelAdapter } from "@theowlops/channelhub/channels/messenger";
const messenger = new MessengerChannelAdapter({
pageAccessToken: "EAA...",
verifyToken: "custom_webhook_secret",
appSecret: "facebook_app_secret",
autoSubscribePage: true, // Automatically subscribe to webhook events
});2. Personal Profile Adapter (Playwright Stealth) Automates your personal Facebook account. Uses a persistent browser context to emulate human behavior and bypass Meta security checkpoints.
import { MessengerPersonalAdapter } from "@theowlops/channelhub/channels/messenger";
// Run 'channelhub login:messenger' first to generate cookies!
const personal = new MessengerPersonalAdapter({
headless: true,
maxMessagesPerMinute: 15,
humanTypingDelayMs: 40,
});Supports reverse-engineered Web API (zca-js) personal sessions and Official Account (OA) v3 OpenAPI. Includes anti-ban jitter algorithms and automatic quote object generation.
import { ZaloChannelAdapter } from "@theowlops/channelhub/channels/zalo";
const zalo = new ZaloChannelAdapter({
credentialsPath: "./credentials.json", // Auto-captured session
minDelayMs: 300,
maxDelayMs: 800
});Lightweight bot integration via Telegram Bot API with native webhook and polling dispatchers.
import { TelegramChannelAdapter } from "@theowlops/channelhub/channels/telegram";
const telegram = new TelegramChannelAdapter({
botToken: "123456:ABC-DEF..."
});Omnichannel adapter for WhatsApp, SMS, MMS, and RCS via Twilio API. Supports timing-safe HMAC-SHA1 signature verification for webhooks.
import { TwilioChannelAdapter } from "@theowlops/channelhub/channels/twilio";
const twilio = new TwilioChannelAdapter({
accountSid: "AC...",
authToken: "YOUR_TWILIO_AUTH_TOKEN",
phoneNumber: "whatsapp:+14155238886" // Or standard SMS number
});import { DiscordChannelAdapter } from "@theowlops/channelhub/channels/discord";
import { SlackChannelAdapter } from "@theowlops/channelhub/channels/slack";
const discord = new DiscordChannelAdapter({ botToken: "DISCORD_TOKEN" });
const slack = new SlackChannelAdapter({ botToken: "xoxb-...", signingSecret: "..." });Express / Koa-style middleware pipeline allows intercepting, modifying, or short-circuiting message dispatching:
// Rate limiting or authentication middleware
hub.use(async (ctx, next) => {
if (ctx.message.content.text.includes("DROP_ME")) {
return; // Short-circuit, halts pipeline
}
await next(); // Proceed to downstream handlers
});Temporarily mute automated bot responses in a specific chat when human customer support steps in:
hub.on("message", async (ctx) => {
if (ctx.message.content.text === "talk to human") {
// Pause bot in this chat for 30 minutes
ctx.handoff(30 * 60 * 1000, "Human agent takeover");
await ctx.reply("Connecting you to a human agent. Bot muted for 30 minutes.");
return;
}
});
// Resume bot manually:
// ctx.resume() or hub.handoff.resume(channel, chatId);Synchronize rate limits across multiple Node/Bun Worker Threads using SharedArrayBuffer and CPU Atomics:
- Throughput: ~3,700,000 ops/second (nano-second memory latency).
- Zero Redis Dependency: Pure in-memory zero-cost synchronization on a single machine.
import { SharedTokenBucketLimiter } from "@theowlops/channelhub/core";
const limiter = new SharedTokenBucketLimiter(100, 20); // 100 capacity, 20 refills/sec
if (limiter.tryAcquire(1)) {
// Dispatched safely within provider quota
}ChannelHub normalizes rich media transmission across all platforms:
// 1. Send Images / Files via URL or Local Path
await ctx.sendMedia({
type: "image",
source: "https://example.com/art.png",
caption: "Concept Art"
});
// 2. Send Large Videos (Meta Resumable Upload up to 100MB)
await ctx.sendMedia({
type: "video",
source: "/var/media/demo_video.mp4"
});
// 3. Send Native Stickers
// Supports Telegram file_id, Zalo sticker ID, or Messenger sticker ID
await ctx.sendSticker("369239263222822");
// 4. Send Animated GIFs
await ctx.sendGif("https://media.giphy.com/media/cat.gif", "Cat Dancing");LLMs generate responses token by token. Direct API calls per token hit rate limits. SmartStreamer batches tokens adaptively:
- Editable Channels (Discord, Telegram): Streams first chunk, then edits the message at throttled intervals (
updateIntervalMs: 800). - Non-Editable Channels (Zalo, Messenger, TikTok): Accumulates tokens and flushes them chunk by chunk on sentence boundaries (
.,!,?,\n) while emitting typing signals.
import { SmartStreamer } from "@theowlops/channelhub/core";
const streamer = new SmartStreamer(ctx, {
chunkSentences: true,
updateIntervalMs: 800
});
// Pipe tokens directly from OpenAI / Anthropic / Local LLM
for await (const chunk of llmTokenStream) {
await streamer.write(chunk);
}
await streamer.end();ChannelHub includes a built-in CLI (channelhub) to streamline project scaffolding, account authentication, and environment troubleshooting:
| Command | Purpose | When & How to Use |
|---|---|---|
npx @theowlops/channelhub init |
Project Scaffolder | Run in an empty folder to auto-generate .env, bot.ts, and package.json. |
npx @theowlops/channelhub doctor |
Environment Diagnostics | Check missing tokens, inspect Node/Bun runtimes, and verify credential files. |
npx @theowlops/channelhub login:zalo |
Zalo Personal Login | Generates a terminal QR code. Scan with your phone to extract credentials.json. |
npx @theowlops/channelhub login:messenger |
Messenger Personal Login | Opens a browser window. Log into Facebook to auto-save messenger.credentials.json. |
npx @theowlops/channelhub start |
Runtime Runner | Starts configured ChannelHub services directly from terminal. |
npx @theowlops/channelhub version |
Version Inspector | Prints current installed version of @theowlops/channelhub. |
npx @theowlops/channelhub help |
Command Reference | Displays list of available CLI commands and usage flags. |
ChannelHub ships with a standalone stdio JSON-RPC MCP server. Connect your AI agent directly to all your chat channels with zero boilerplate.
channelhub-mcpAdd to claude_desktop_config.json:
{
"mcpServers": {
"channelhub": {
"command": "bun",
"args": ["run", "channelhub-mcp"]
}
}
}| Group | Tools |
|---|---|
| Messaging | channelhub_send_message · channelhub_send_media · channelhub_send_sticker · channelhub_send_gif · channelhub_send_typing · channelhub_edit_message · channelhub_add_reaction · channelhub_broadcast · channelhub_list_channels · channelhub_get_status |
| Group Management | channelhub_group_create_poll · channelhub_group_cast_vote · channelhub_group_get_poll_results · channelhub_group_check_spam · channelhub_group_check_profanity · channelhub_group_issue_warning · channelhub_group_leaderboard · channelhub_group_recap · channelhub_group_welcome_challenge · channelhub_group_verify_challenge |
| Messenger (Personal) | channelhub_messenger_get_threads · channelhub_messenger_get_history · channelhub_messenger_get_members · channelhub_messenger_get_user_profile · channelhub_messenger_recall_message |
| Productivity | channelhub_send_email · channelhub_github_create_issue · channelhub_github_comment · channelhub_calendar_quick_add |
| Media & Research | channelhub_video_create_short · channelhub_video_burn_subtitles · channelhub_video_add_watermark · channelhub_web_search · channelhub_web_extract |
A built-in, zero-dependency web dashboard for your bot traffic — no database, no external service, one line of code:
await hub.dashboard(); // 📊 → http://127.0.0.1:8790 — that's it| Widget | What it shows |
|---|---|
| Counters | Inbound / outbound totals, today's traffic, active users, errors, connected channels |
| 24h Bar Chart | Hourly inbound vs outbound messages |
| 14-Day Trend | Daily traffic with hover tooltips |
| Activity Heatmap | 7 days × 24 hours inbound intensity |
| Top Channels / Users | Ranked tables with last-seen timestamps |
The page auto-refreshes every 5 seconds; GET /api/stats returns the same JSON snapshot for your own tooling. Non-default port, auth and persistence are optional flags on the same call:
await hub.dashboard({
port: 3000, // default 8790, binds 127.0.0.1
// host: "0.0.0.0", // expose beyond localhost — requires apiKey
apiKey: process.env.DASHBOARD_KEY, // or CHANNELHUB_DASHBOARD_KEY env
dataFile: "./channelhub-stats.json", // persist stats across restarts
});Prefer explicit control? new DashboardBridge(hub, options) + await start() is exactly equivalent.
Security model: the HTML page is static and public; all data flows through GET /api/stats. On the default loopback binding no key is needed. When host is set beyond loopback without an apiKey, the API fails closed (401 for every request). With apiKey (or the CHANNELHUB_DASHBOARD_KEY env), a timing-safe Bearer check protects the endpoint — the page prompts for the key and keeps it in sessionStorage.
- HMAC-SHA256 & Timing-Safe Verification: All inbound webhooks (TikTok, Messenger, Slack) verify cryptographic signatures via
crypto.timingSafeEqualto thwart timing attacks. - Anti-Replay Attack Protection: Webhook deliveries outside the allowed time window (default 300s) are immediately discarded.
- Zero Token Leak in URLs: Authentication tokens are strictly transmitted in HTTP headers (
Access-Token,Authorization: Bearer), never in URL query strings. - Localhost Loopback Default: Webhook bridge and dashboard default to
127.0.0.1rather than0.0.0.0. - DoS Payload Limits: Enforces a strict 1MB JSON body size ceiling before socket termination.
- Path Traversal Guard: All file uploads run through
path.resolveand verifyfs.statSync().isFile(), preventing arbitrary file disclosure. - Credential Hygiene: Auto-masks sensitive tokens in logs (
[REDACTED]) and enforces.gitignorerules against credential files.
ChannelHub is licensed under the MIT License. Maintained by TheOwlOps Team.
