docs/channels/zalo.md
Status: experimental. Direct messages and group chats are both implemented; the Capabilities table below reflects verified behavior on Zalo Bot Creator / Marketplace bots.
Zalo ships as a bundled plugin in current OpenClaw releases, so packaged builds do not need a separate install.
On an older build or a custom install that excludes Zalo, install the npm package directly:
openclaw plugins install @openclaw/zaloopenclaw plugins install @openclaw/[email protected]openclaw plugins install ./path/to/local/zalo-pluginnumeric_id:secret; for Marketplace bots the usable runtime token may appear in the bot's welcome message.ZALO_BOT_TOKEN=... (default account only) or in config.Minimal config:
{
channels: {
zalo: {
enabled: true,
accounts: {
default: {
botToken: "12345689:abc-xyz",
dmPolicy: "pairing",
},
},
},
},
}
Multi-account: add more entries under channels.zalo.accounts.<id>, each with its own botToken/name. channels.zalo.botToken (flat, no accounts) is a legacy single-account shorthand; prefer accounts.<id>.* for new configs.
Zalo is a Vietnam-focused messaging app. Its Bot API lets the Gateway run a bot for both 1:1 conversations and group chats, with deterministic routing back to Zalo (the model never chooses channels).
This page covers Zalo Bot Creator / Marketplace bots. Zalo Official Account (OA) bots are a different product surface and may behave differently; this page does not cover them.
replyToMode is fixed off).getUpdates) by default; webhook mode available via channels.zalo.webhookUrl.| Limit | Value |
|---|---|
| Outbound text chunk size | 2000 characters (Zalo API limit) |
| Media size (inbound/outbound) | channels.zalo.mediaMaxMb, default 5 MB |
| Webhook request body | 1 MB, 30s read timeout |
| Webhook rate limit | 120 requests / 60s per path+client IP, then HTTP 429 |
| Webhook duplicate-event window | 5 minutes (keyed on path + account + event name + chat + sender + message id) |
channels.zalo.dmPolicy: pairing (default) | allowlist | open | disabled.openclaw pairing list zaloopenclaw pairing approve zalo <CODE>channels.zalo.allowFrom accepts numeric Zalo user IDs (no username lookup). open requires "*".Group chats are supported by the plugin (chatTypes: ["direct", "group"]) and gated by mention plus group policy:
channels.zalo.groupPolicy: open | allowlist | disabled.channels.zalo.groupAllowFrom restricts which sender IDs can trigger the bot in groups; falls back to allowFrom when unset.channels.zalo is configured, an unset groupPolicy resolves to open. When channels.zalo is missing entirely, runtime fails closed to allowlist.channels.zalo.webhookUrl and channels.zalo.webhookSecret.
X-Bot-Api-Secret-Token header, checked with a constant-time comparison.channels.zalo.webhookPath (defaults to the webhook URL's path).Content-Type: application/json (or a +json media type).mediaMaxMb.| Feature | Status |
|---|---|
| Direct messages | Supported |
| Groups | Supported (mention-gated) |
| Media (inbound/outbound) | Supported, capped by mediaMaxMb |
| Reactions | Not supported |
| Threads | Not supported |
| Polls | Not supported |
| Native commands | Not supported |
| Reply-to / quote | Not used (fixed off) |
Use a chat ID as the target:
openclaw message send --channel zalo --target 123456789 --message "hi"
Bot does not respond:
openclaw channels status --probeallowFrom)openclaw logs --followWebhook not receiving events:
Full configuration: Configuration
| Setting | Description | Default |
|---|---|---|
channels.zalo.enabled | Enable/disable channel startup | true |
channels.zalo.accounts.<id>.botToken | Bot token from Zalo Bot Platform | - |
channels.zalo.accounts.<id>.tokenFile | Read token from a file (symlinks rejected) | - |
channels.zalo.accounts.<id>.name | Display name | - |
channels.zalo.accounts.<id>.enabled | Enable/disable this account | true |
channels.zalo.accounts.<id>.dmPolicy | Per-account DM policy | pairing |
channels.zalo.accounts.<id>.allowFrom | DM allowlist (user IDs) | - |
channels.zalo.accounts.<id>.groupPolicy | Per-account group policy | see Groups |
channels.zalo.accounts.<id>.groupAllowFrom | Group sender allowlist; falls back to allowFrom | - |
channels.zalo.accounts.<id>.mediaMaxMb | Inbound/outbound media cap (MB) | 5 |
channels.zalo.accounts.<id>.webhookUrl | Enable webhook mode (HTTPS required) | - |
channels.zalo.accounts.<id>.webhookSecret | Webhook secret (8-256 chars) | - |
channels.zalo.accounts.<id>.webhookPath | Webhook path on the gateway HTTP server | webhook URL path |
channels.zalo.accounts.<id>.proxy | Proxy URL for API requests | - |
channels.zalo.accounts.<id>.responsePrefix | Outbound response prefix override | - |
channels.zalo.defaultAccount | Default account when multiple are configured | default |
channels.zalo.botToken, channels.zalo.dmPolicy, and other flat top-level keys are the legacy single-account shorthand for the fields above; both forms are supported.
Env option: ZALO_BOT_TOKEN=... resolves the default account's token only.