Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
180 lines
9.7 KiB
Markdown
180 lines
9.7 KiB
Markdown
---
|
|
summary: "Zalo bot support status, capabilities, and configuration"
|
|
read_when:
|
|
- Working on Zalo features or webhooks
|
|
title: "Zalo"
|
|
---
|
|
|
|
Status: experimental. Direct messages and group chats are both implemented; the [Capabilities](#capabilities) table below reflects verified behavior on Zalo Bot Creator / Marketplace bots.
|
|
|
|
## Bundled plugin
|
|
|
|
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:
|
|
|
|
- Install: `openclaw plugins install @openclaw/zalo`
|
|
- Pinned version: `openclaw plugins install @openclaw/zalo@2026.6.11`
|
|
- From a local checkout: `openclaw plugins install ./path/to/local/zalo-plugin`
|
|
- Details: [Plugins](/tools/plugin)
|
|
|
|
## Quick setup
|
|
|
|
1. Create a bot token at [https://bot.zaloplatforms.com](https://bot.zaloplatforms.com) (sign in, create a bot, configure settings). The token is `numeric_id:secret`; for Marketplace bots the usable runtime token may appear in the bot's welcome message.
|
|
2. Set the token, either as env `ZALO_BOT_TOKEN=...` (default account only) or in config.
|
|
3. Restart the gateway.
|
|
4. Approve the pairing code on first DM contact (default DM policy is pairing).
|
|
|
|
Minimal config:
|
|
|
|
```json5
|
|
{
|
|
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.
|
|
|
|
## What it is
|
|
|
|
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.
|
|
|
|
## How it works
|
|
|
|
- Inbound messages are normalized into the shared channel envelope with media placeholders.
|
|
- Replies always route back to the same Zalo chat; quote-reply is not used (`replyToMode` is fixed off).
|
|
- Long-polling (`getUpdates`) by default; webhook mode available via `channels.zalo.webhookUrl`.
|
|
- Groups require an @mention to trigger the bot; this is not configurable per channel.
|
|
|
|
## Limits
|
|
|
|
| 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) |
|
|
|
|
## Access control
|
|
|
|
### Direct messages
|
|
|
|
- `channels.zalo.dmPolicy`: `pairing` (default) | `allowlist` | `open` | `disabled`.
|
|
- Pairing: unknown senders get a pairing code; messages are ignored until approved. Codes expire after 1 hour.
|
|
- `openclaw pairing list zalo`
|
|
- `openclaw pairing approve zalo <CODE>`
|
|
- Details: [Pairing](/channels/pairing)
|
|
- `channels.zalo.allowFrom` accepts numeric Zalo user IDs (no username lookup). `open` requires `"*"`.
|
|
|
|
### Groups
|
|
|
|
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.
|
|
- Default resolution: when `channels.zalo` is configured, an unset `groupPolicy` resolves to `open`. When `channels.zalo` is missing entirely, runtime fails closed to `allowlist`.
|
|
- Reported real-world caveat: on some Marketplace-bot setups the bot could not be added to a group at all. If you hit that, verify with your bot's Zalo Bot Platform settings; it is a platform-side constraint, not an OpenClaw policy.
|
|
|
|
## Long-polling vs webhook
|
|
|
|
- Default: long-polling (no public URL required).
|
|
- Webhook mode: set `channels.zalo.webhookUrl` and `channels.zalo.webhookSecret`.
|
|
- Webhook URL must use HTTPS.
|
|
- Webhook secret must be 8-256 characters.
|
|
- Zalo sends events with an `X-Bot-Api-Secret-Token` header, checked with a constant-time comparison.
|
|
- Gateway HTTP handles webhook requests at `channels.zalo.webhookPath` (defaults to the webhook URL's path).
|
|
- Requests must use `Content-Type: application/json` (or a `+json` media type).
|
|
- getUpdates polling and webhook are mutually exclusive per Zalo API docs.
|
|
|
|
## Supported message types
|
|
|
|
- Text: full support, chunked to 2000 characters.
|
|
- Media: inbound/outbound, capped by `mediaMaxMb`.
|
|
- Reactions, threads, polls, native commands: not supported by the plugin.
|
|
- Streaming: the plugin declares block-streaming capability, but Zalo has no dedicated outbound queue/merge-text tuning knobs (unlike some other regional channels); verify current behavior in your environment if this matters for your use case.
|
|
|
|
## Capabilities
|
|
|
|
| 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) |
|
|
|
|
## Delivery targets (CLI/cron)
|
|
|
|
Use a chat ID as the target:
|
|
|
|
```bash
|
|
openclaw message send --channel zalo --target 123456789 --message "hi"
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
**Bot does not respond:**
|
|
|
|
- Check the token: `openclaw channels status --probe`
|
|
- Verify the sender is approved (pairing or `allowFrom`)
|
|
- Check gateway logs: `openclaw logs --follow`
|
|
|
|
**Webhook not receiving events:**
|
|
|
|
- Confirm the webhook URL uses HTTPS
|
|
- Confirm the secret is 8-256 characters
|
|
- Confirm the gateway HTTP endpoint is reachable on the configured path
|
|
- Confirm getUpdates polling is not also running (they are mutually exclusive)
|
|
- A burst of requests can return HTTP 429 (120 requests / 60s per path+IP); back off and retry
|
|
|
|
## Configuration reference
|
|
|
|
Full configuration: [Configuration](/gateway/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](#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.
|
|
|
|
## Related
|
|
|
|
- [Channels Overview](/channels) - all supported channels
|
|
- [Pairing](/channels/pairing) - DM authentication and pairing flow
|
|
- [Groups](/channels/groups) - group chat behavior and mention gating
|
|
- [Channel Routing](/channels/channel-routing) - session routing for messages
|
|
- [Security](/gateway/security) - access model and hardening
|