What's bundled
- WhatsApp via Baileys
- Telegram via grammY
- Slack via Bolt
- Discord via discord.js
- Signal via signal-cli
- iMessage via BlueBubbles
- Microsoft Teams Graph API
- Matrix matrix-js-sdk
- LINE official SDK
- Lark / Feishu official SDK
- Google Chat webhooks
- WebChat embeddable widget
How pairing works
Each tenant pairs each channel separately. The pairing flow varies by channel — WhatsApp shows a QR code; Telegram needs a bot token; Slack runs an OAuth dance; Discord wants an invite link. The CLI walks you through it; the same flows are exposed as JSON-RPC methods if you want to build your own pairing UI.
# WhatsApp: scan a QR code on your phone
openclaw channels pair whatsapp --tenant acme
# Telegram: paste the bot token from BotFather
openclaw channels pair telegram --tenant acme --token 1234567:ABC...
# Slack: opens the OAuth URL in your browser
openclaw channels pair slack --tenant acme
# Discord: paste the bot token
openclaw channels pair discord --tenant acme --token <token> Inbound routing
Inbound messages from any channel are normalized into a common envelope:
{
"tenant": "acme",
"channel": "whatsapp",
"user": {
"id": "wa:+15551234567",
"display_name": "Jane Doe"
},
"session_id": "wa:+15551234567:default",
"content": {
"type": "text",
"text": "How many invoices are overdue?"
},
"received_at": "2026-06-03T10:14:22Z"
} The agent runtime sees this normalized envelope, not the raw channel payload. Reply messages are translated back into channel-native form by the adapter — markdown becomes rich text on Slack, plain on WhatsApp.
Cross-channel identity
By default, each channel's user IDs are namespaced (e.g.
wa:+1..., tg:12345) so the same human
talking to your bot on WhatsApp and Slack gets two separate
sessions. To unify identities, the tenant config can define a
mapping table or a callback that resolves a canonical user ID.
identity:
resolve: |
# JS expression; returns the canonical user ID
if (channel === 'slack') return 'slack-' + user.id
if (channel === 'whatsapp') return phone_to_canonical(user.id)
return channel + ':' + user.id Adding your own channel
The channel adapter contract is small: parse inbound, normalize, push to the gateway; receive outbound, translate, send. New channels (LINE Bizz, Twitter DMs, customer support widgets) plug in with about 200 lines of adapter code. See the channel adapter docs on GitHub.