Zalo (Bot API)
Status: experimental. DMs are supported. The Capabilities section below reflects current Marketplace-bot behavior.Plugin required
Zalo ships as a plugin and is not bundled with the core install.- Install via CLI:
openclaw plugins install @openclaw/zalo - Or select Zalo during setup and confirm the install prompt
- Details: Plugins
Quick setup (beginner)
- Install the Zalo plugin:
- From a source checkout:
openclaw plugins install ./extensions/zalo - From npm (if published):
openclaw plugins install @openclaw/zalo - Or pick Zalo in setup and confirm the install prompt
- From a source checkout:
- Set the token:
- Env:
ZALO_BOT_TOKEN=... - Or config:
channels.zalo.accounts.default.botToken: "...".
- Env:
- Restart the gateway (or finish setup).
- DM access is pairing by default; approve the pairing code on first contact.
What it is
Zalo is a Vietnam-focused messaging app; its Bot API lets the Gateway run a bot for 1:1 conversations. It is a good fit for support or notifications where you want deterministic routing back to Zalo. This page reflects current OpenClaw behavior for Zalo Bot Creator / Marketplace bots. Zalo Official Account (OA) bots are a different Zalo product surface and may behave differently.- A Zalo Bot API channel owned by the Gateway.
- Deterministic routing: replies go back to Zalo; the model never chooses channels.
- DMs share the agent’s main session.
- The Capabilities section below shows current Marketplace-bot support.
Setup (fast path)
1) Create a bot token (Zalo Bot Platform)
- Go to https://bot.zaloplatforms.com and sign in.
- Create a new bot and configure its settings.
- Copy the full bot token (typically
numeric_id:secret). For Marketplace bots, the usable runtime token may appear in the bot’s welcome message after creation.
2) Configure the token (env or config)
Example:groupPolicy and groupAllowFrom explicitly. For current Marketplace-bot behavior, see Capabilities.
Env option: ZALO_BOT_TOKEN=... (works for the default account only).
Multi-account support: use channels.zalo.accounts with per-account tokens and optional name.
- Restart the gateway. Zalo starts when a token is resolved (env or config).
- DM access defaults to pairing. Approve the code when the bot is first contacted.
How it works (behavior)
- Inbound messages are normalized into the shared channel envelope with media placeholders.
- Replies always route back to the same Zalo chat.
- Long-polling by default; webhook mode available with
channels.zalo.webhookUrl.
Limits
- Outbound text is chunked to 2000 characters (Zalo API limit).
- Media downloads/uploads are capped by
channels.zalo.mediaMaxMb(default 5). - Streaming is blocked by default due to the 2000 char limit making streaming less useful.
Access control (DMs)
DM access
- Default:
channels.zalo.dmPolicy = "pairing". Unknown senders receive a pairing code; messages are ignored until approved (codes expire after 1 hour). - Approve via:
openclaw pairing list zaloopenclaw pairing approve zalo <CODE>
- Pairing is the default token exchange. Details: Pairing
channels.zalo.allowFromaccepts numeric user IDs (no username lookup available).
Access control (Groups)
For Zalo Bot Creator / Marketplace bots, group support was not available in practice because the bot could not be added to a group at all. That means the group-related config keys below exist in the schema, but were not usable for Marketplace bots:channels.zalo.groupPolicycontrols group inbound handling:open | allowlist | disabled.channels.zalo.groupAllowFromrestricts which sender IDs can trigger the bot in groups.- If
groupAllowFromis unset, Zalo falls back toallowFromfor sender checks. - Runtime note: if
channels.zalois missing entirely, runtime still falls back togroupPolicy="allowlist"for safety.
groupPolicy: "disabled"— blocks all group messages.groupPolicy: "open"— allows any group member (mention-gated).groupPolicy: "allowlist"— fail-closed default; only allowed senders are accepted.
Long-polling vs webhook
- Default: long-polling (no public URL required).
- Webhook mode: set
channels.zalo.webhookUrlandchannels.zalo.webhookSecret.- The webhook secret must be 8-256 characters.
- Webhook URL must use HTTPS.
- Zalo sends events with
X-Bot-Api-Secret-Tokenheader for verification. - Gateway HTTP handles webhook requests at
channels.zalo.webhookPath(defaults to the webhook URL path). - Requests must use
Content-Type: application/json(or+jsonmedia types). - Duplicate events (
event_name + message_id) are ignored for a short replay window. - Burst traffic is rate-limited per path/source and may return HTTP 429.
Supported message types
For a quick support snapshot, see Capabilities. The notes below add detail where the behavior needs extra context.- Text messages: Full support with 2000 character chunking.
- Plain URLs in text: Behave like normal text input.
- Link previews / rich link cards: See the Marketplace-bot status in Capabilities; they did not reliably trigger a reply.
- Image messages: See the Marketplace-bot status in Capabilities; inbound image handling was unreliable (typing indicator without a final reply).
- Stickers: See the Marketplace-bot status in Capabilities.
- Voice notes / audio files / video / generic file attachments: See the Marketplace-bot status in Capabilities.
- Unsupported types: Logged (for example, messages from protected users).
Capabilities
This table summarizes current Zalo Bot Creator / Marketplace bot behavior in OpenClaw.| Feature | Status |
|---|---|
| Direct messages | ✅ Supported |
| Groups | ❌ Not available for Marketplace bots |
| Media (inbound images) | ⚠️ Limited / verify in your environment |
| Media (outbound images) | ⚠️ Not re-tested for Marketplace bots |
| Plain URLs in text | ✅ Supported |
| Link previews | ⚠️ Unreliable for Marketplace bots |
| Reactions | ❌ Not supported |
| Stickers | ⚠️ No agent reply for Marketplace bots |
| Voice notes / audio / video | ⚠️ No agent reply for Marketplace bots |
| File attachments | ⚠️ No agent reply for Marketplace bots |
| Threads | ❌ Not supported |
| Polls | ❌ Not supported |
| Native commands | ❌ Not supported |
| Streaming | ⚠️ Blocked (2000 char limit) |
Delivery targets (CLI/cron)
- Use a chat id as the target.
- Example:
openclaw message send --channel zalo --target 123456789 --message "hi".
Troubleshooting
Bot doesn’t respond:- Check that the token is valid:
openclaw channels status --probe - Verify the sender is approved (pairing or allowFrom)
- Check gateway logs:
openclaw logs --follow
- Ensure webhook URL uses HTTPS
- Verify secret token is 8-256 characters
- Confirm the gateway HTTP endpoint is reachable on the configured path
- Check that getUpdates polling is not running (they’re mutually exclusive)
Configuration reference (Zalo)
Full configuration: Configuration The flat top-level keys (channels.zalo.botToken, channels.zalo.dmPolicy, and similar) are a legacy single-account shorthand. Prefer channels.zalo.accounts.<id>.* for new configs. Both forms are still documented here because they exist in the schema.
Provider options:
channels.zalo.enabled: enable/disable channel startup.channels.zalo.botToken: bot token from Zalo Bot Platform.channels.zalo.tokenFile: read token from a regular file path. Symlinks are rejected.channels.zalo.dmPolicy:pairing | allowlist | open | disabled(default: pairing).channels.zalo.allowFrom: DM allowlist (user IDs).openrequires"*". The wizard will ask for numeric IDs.channels.zalo.groupPolicy:open | allowlist | disabled(default: allowlist). Present in config; see Capabilities and Access control (Groups) for current Marketplace-bot behavior.channels.zalo.groupAllowFrom: group sender allowlist (user IDs). Falls back toallowFromwhen unset.channels.zalo.mediaMaxMb: inbound/outbound media cap (MB, default 5).channels.zalo.webhookUrl: enable webhook mode (HTTPS required).channels.zalo.webhookSecret: webhook secret (8-256 chars).channels.zalo.webhookPath: webhook path on the gateway HTTP server.channels.zalo.proxy: proxy URL for API requests.
channels.zalo.accounts.<id>.botToken: per-account token.channels.zalo.accounts.<id>.tokenFile: per-account regular token file. Symlinks are rejected.channels.zalo.accounts.<id>.name: display name.channels.zalo.accounts.<id>.enabled: enable/disable account.channels.zalo.accounts.<id>.dmPolicy: per-account DM policy.channels.zalo.accounts.<id>.allowFrom: per-account allowlist.channels.zalo.accounts.<id>.groupPolicy: per-account group policy. Present in config; see Capabilities and Access control (Groups) for current Marketplace-bot behavior.channels.zalo.accounts.<id>.groupAllowFrom: per-account group sender allowlist.channels.zalo.accounts.<id>.webhookUrl: per-account webhook URL.channels.zalo.accounts.<id>.webhookSecret: per-account webhook secret.channels.zalo.accounts.<id>.webhookPath: per-account webhook path.channels.zalo.accounts.<id>.proxy: per-account proxy URL.