Concept · channels

Channels — one gateway, every inbox.

OpenClawMU keeps every upstream channel adapter and routes each inbound message to the right tenant. Twelve channels out of the box, more via custom adapters.

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.

bash
# 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:

json
{
  "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.

~/.openclaw/tenants/acme/config.yaml
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.

EXFOLIATE!

Run your own gateway today.

Apache-2.0, self-hosted, no SaaS layer between you and your users. Install the CLI, create your first tenant, mint a token — you're routing traffic in 60 seconds.