ZeroClaw supports two WhatsApp backends under the same channels.whatsapp config family:
| Mode | Use it when | Required selector |
|---|---|---|
| WhatsApp Cloud API | You have a Meta Business app and WhatsApp Business phone number ID | phone_number_id |
| WhatsApp Web | You want to link a regular WhatsApp account through the Web protocol | session_path |
Do not configure both selectors in the same channel unless you intentionally want Cloud API mode to win for backward compatibility.
Who can talk to the agent
Inbound senders are gated against the peer set resolved for the bound
agent, drawn from the peer_groups config the agent belongs to. Matching strips
a leading @ and is case-insensitive against the channel’s native sender
identifier. An empty set denies everyone; a set containing "*" accepts
anyone; otherwise only the listed external peers (and peer agents) are accepted.
This is separate from gateway pairing (gateway.require_pairing), which
authenticates HTTP/WebSocket clients, not chat-channel senders.
A peer group for whatsapp sets channel to whatsapp, lists the allowed senders in
external_peers (for whatsapp, a phone identifier (Cloud API) or the JID user part (Web mode); ["*"] accepts anyone), optionally
names peer agents for cross-agent dispatch, an ignore blocklist, and an
output_modality (mirror, voice, or text). See Peer Groups
for the field reference.
Where to set this:
Gateway dashboard
Open /config/peer_groups in the web dashboard.
zerocode
In the Config pane, under Peer groups.
Cloud API mode
Cloud API mode is the Meta Business Platform integration. It requires a Meta Business account, a WhatsApp Business app, a phone number ID, a verify token, an access token, and an app secret. It is the right mode for business deployments that receive messages through Meta webhooks.
Inbound webhooks are signature-verified against app_secret, and verification is mandatory. With no app secret configured the gateway cannot verify a request, so it answers 401 and processes nothing. Set app_secret before pointing Meta at the callback URL.
The gateway must be reachable by Meta for inbound webhooks. Configure a tunnel under the top-level [tunnel] section (tunnel_provider and the related provider blocks, see the config reference), or front the gateway with your own reverse proxy when developing locally.
Point Meta’s Callback URL at the alias of the [channels.whatsapp.<alias>]
instance that should receive it: GET/POST https://<your-public-url>/whatsapp/<alias>
(e.g. [channels.whatsapp.work] → /whatsapp/work). This per-alias routing
(#6312) lets multiple WhatsApp numbers run side by side. The bare /whatsapp
path still works but is deprecated: it resolves to the lexicographically-first
alias (deterministic across restarts) and sets an X-Zeroclaw-Deprecation response
header. An unknown alias returns 404. Single-instance deployments need no change.
Web mode
WhatsApp Web mode links a regular WhatsApp account through the optional Web backend. It does not need a Meta Business account. It does need a ZeroClaw build with the whatsapp-web feature enabled and a persistent session database path.
On first start, the Web backend pairs the account using QR or pair-code linking (pair_phone seeds pair-code linking; leave it unset for QR). Keep session_path on persistent storage; removing it forces a fresh device link. Bind the channel to an agent via that agent’s channels list.
push_name sets the display name recipients see; leave it unset and the account keeps the name the phone was registered with. It is applied on connect, only when it differs from the name the linked device already carries, and a failure to apply it is logged without stopping the channel. Cloud API mode ignores it; there the display name comes from the Meta Business profile.
The shared interrupt_on_new_message option applies to both Cloud API mode and Web mode. When enabled, a newer WhatsApp message from the same sender/chat cancels the in-flight response.
Personal and business behavior
For Web mode, dm_policy and group_policy apply under both modes. self_chat_mode is personal-only:
| Field | Values | Applies under | Effect |
|---|---|---|---|
dm_policy | allowlist, ignore, all | both modes | Controls direct messages |
group_policy | allowlist, ignore, all | both modes | Controls group chats |
self_chat_mode | true, false | personal only | Controls the user’s self-chat |
mention_only | true, false | both modes | Requires group messages to mention the bot |
passive_group_context | true, false | both modes | Records allowed unaddressed group messages as context only |
self_chat_mode stays personal-only because the self-chat affordance is scoped to the personal branch by design. mode selects ZeroClaw’s policy posture, not a WhatsApp account type: both modes drive the same linked-device session.
The fromMe guard also stays inside the personal branch, but not because business mode lacks an equivalent. Business mode is still a WhatsApp Web linked-device session, and WhatsApp mirrors the operator’s own outbound messages to linked devices as fromMe in either mode. The linked account is persisted as an authorized peer, so under business mode that mirror can satisfy the allowlist and reach dispatch, which is the shape #6353 closed for personal mode. That behaviour predates this change and is not introduced here; it is called out rather than asserted away, and repairing it is tracked separately.
Compatibility note for mode = "business"
Business mode previously accepted dm_policy and group_policy and then never consulted either one, so a channel that read as restrictive answered every message it received. Both keys are now enforced under business mode.
dm_policy defaults to allowlist, so a business-mode deployment that relied on the previous permissive behavior must choose one of:
- Keep answering everyone - set
dm_policy = "all"andgroup_policy = "all"explicitly. - Keep the restriction - leave the defaults and make sure the senders you intend to serve are reachable through the channel’s peer group, via
[peer_groups.<name>].external_peers.
Do not wait for config validate to tell you this. Under mode = "business" it reports
self_chat_mode as inert and says nothing about dm_policy or group_policy, precisely because
those two are now live rather than inert. So the keys whose behaviour actually changed for you are
the ones the validator will not mention. Read this section before upgrading; that is the only
notice a business-mode deployment gets.
passive_group_context = true is opt-in and applies only to WhatsApp Web group chats. Allowed unaddressed group messages are stored in the room-scoped conversation history without starting an agent turn, sending reactions, downloading media, or calling the model. Later addressed messages in the same group can use that passive context.
Restricting which groups (allowed_groups)
allowed_groups (Web mode) scopes the bot to a named set of group chats by JID. It is independent of mode - it applies in both business and personal mode, and runs before the chat-type policy. An empty list is not permission: what it means is decided by group_policy. Under allowlist (the default) or ignore an empty list admits no group, and under all it admits every group. A list that admits everything cannot be told apart from a list nobody configured, so open group access has to be asked for by name. A non-empty list drops every group message whose chat JID matches no entry, and keeps doing so under every policy including all, so all widens the empty-list default rather than overriding an explicit list. Direct messages always bypass this filter.
Each entry matches either the full group JID (123456789012345@g.us) or the JID user part - the segment before @ (123456789012345) - compared exactly, not as a string prefix (so 123 admits 123@g.us but never 123999@g.us). This gates group identity, which group_policy (chat type) and the sender allowlist (sender) do not.
[channels.whatsapp.myaccount]
enabled = true
session_path = "/var/lib/zeroclaw/wa.db"
# Only operate in these two groups; all other groups are dropped.
allowed_groups = ["120363012345678901@g.us", "120363098765432109"]
Tool approval over chat (approval_timeout_secs)
When a tool needs approval (it is in always_ask, or the risk profile does not
auto-approve it), the agent posts the request into the chat the message came from
and waits for a reply. Answer with the token from the prompt:
a1b2c3 yes
a1b2c3 no
a1b2c3 always
approval_timeout_secs bounds that wait. The default is 300 seconds, and 0
denies immediately rather than disabling approval, so a zero is a way to refuse
every gated tool, not a way to wait forever. On timeout the request is denied and
the token is discarded, so a late reply cannot approve a call nobody is waiting
on any more.
Who may answer. The token is a correlator, not a password: it travels in plaintext into the chat, so in a group every member can read it.
The two modes differ, and the difference is a security boundary rather than an implementation detail.
In Web mode, a reply is honoured only when it comes from the same chat the prompt was posted into and from a peer this alias is authorized to take instructions from. A reply that fails either check is logged and ignored, and the request stays open so the operator can still answer it. In a group the prompt says so, because otherwise there is no way to tell why a bystander’s reply did nothing.
The authorized peers are the ones the canonical resolver returns for this
alias, which is the peer group whose channel points at it:
[peer_groups.whatsapp_default]
channel = "whatsapp.personal" # this alias only; bare "whatsapp" covers every alias
external_peers = ["+15550100"]
There is no allowed_numbers field to set. That was the v2 spelling, and
migration folds it into a peer group like the one above, so a v2 config keeps
working and a v3 config has nowhere to put the old key.
See Peer groups for the full field list and the identifier shape each channel matches against.
In Cloud API mode, neither check is applied. Its pending entry is a bare responder keyed by the token, with no chat and no identity recorded alongside it, so the webhook treats possession of the token as authority. In a group that means any member who can read the prompt can answer it, including from a different chat. Until that path is hardened, a Cloud-mode approval is proof that someone possessed the token and nothing more. It authenticates neither the chat nor the responder, so prefer Web mode wherever either matters.
Configuration surfaces
access_token 🔑
Access token from Meta Business Suite (Cloud API mode)
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.access_token field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.access_token field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.access_token # masked input, stored encrypted
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__access_token=
allowed_groups
Allowed group chats by JID (Web mode). An empty list (the default) admits NO group unless group_policy = "all", which admits every group; a non-empty list drops every group message whose chat JID matches no entry. Each entry matches either the full group JID (123456789012345@g.us) or the JID user part - the segment before @ (123456789012345) - compared exactly, not as a string prefix. Direct messages bypass this filter regardless of list contents. Modeled on the Matrix channel’s allowed_rooms; it gates group identity, which dm_policy/group_policy (chat type) and the sender allowlist (sender) do not.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.allowed_groups field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.allowed_groups field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.allowed_groups <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__allowed_groups=
app_secret 🔑
App secret from Meta Business Suite (for webhook signature verification) Can also be set with the alias-qualified generic environment override: ZEROCLAW_channels__whatsapp__<alias>__app_secret. Only used in Cloud API mode. Required to receive webhooks. Inbound requests are signature-verified, and with no secret configured the gateway cannot verify them, so it refuses them with 401 rather than accepting them unverified.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.app_secret field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.app_secret field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.app_secret # masked input, stored encrypted
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__app_secret=
approval_timeout_secs
Seconds to wait for operator approval on always_ask tools before auto-denying.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.approval_timeout_secs field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.approval_timeout_secs field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.approval_timeout_secs <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__approval_timeout_secs=
dm_mention_patterns
Regex patterns for DM mention gating (case-insensitive). When non-empty, only direct messages matching at least one pattern are processed; matched fragments are stripped from the forwarded content. Example: ["@?ZeroClaw", "\\+?15555550123"]
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.dm_mention_patterns field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.dm_mention_patterns field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.dm_mention_patterns <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__dm_mention_patterns=
dm_policy
Policy for direct messages, applied under both modes. “allowlist” (default) | “ignore” | “all”.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.dm_policy field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.dm_policy field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.dm_policy <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__dm_policy=
excluded_tools
Tools excluded from this channel’s tool spec. When set, these tools are not exposed to the model when responding via this channel.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.excluded_tools field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.excluded_tools field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.excluded_tools <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__excluded_tools=
group_mention_patterns
Regex patterns for group-chat mention gating (case-insensitive). When non-empty, only group messages matching at least one pattern are processed; matched fragments are stripped from the forwarded content. Example: ["@?ZeroClaw", "\\+?15555550123"]
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.group_mention_patterns field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.group_mention_patterns field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.group_mention_patterns <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__group_mention_patterns=
group_policy
Policy for group chats, applied under both modes. “allowlist” (default) | “ignore” | “all”.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.group_policy field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.group_policy field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.group_policy <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__group_policy=
interrupt_on_new_message
Cancel an in-flight response from this channel sender when a newer WhatsApp message arrives. Default: false.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.interrupt_on_new_message field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.interrupt_on_new_message field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.interrupt_on_new_message <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__interrupt_on_new_message=
mention_only
When true, only respond to messages that @-mention the bot in groups (Web mode only). Direct messages are always processed. Bot identity is resolved from the wa-rs device at runtime; pair_phone seeds it on first connect.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.mention_only field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.mention_only field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.mention_only <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__mention_only=
mode
Usage mode for WhatsApp Web: “business” (default) or “personal”. dm_policy and group_policy apply under BOTH modes. Personal mode additionally applies self_chat_mode and the fromMe handling; both are scoped to the personal branch by design, not by any protocol difference between the two modes.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.mode field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.mode field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.mode <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__mode=
pair_code
Custom pair code for linking (Web mode, optional) Leave empty to let WhatsApp generate one
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.pair_code field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.pair_code field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.pair_code <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__pair_code=
pair_phone
Phone number for pair code linking (Web mode, optional) Format: country code + number (e.g., “15551234567”) If not set, QR code pairing will be used
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.pair_phone field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.pair_phone field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.pair_phone <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__pair_phone=
passive_group_context
When true in WhatsApp Web group chats, unaddressed messages that pass sender/chat authorization are recorded as passive conversation context without starting an agent turn. Default: false.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.passive_group_context field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.passive_group_context field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.passive_group_context <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__passive_group_context=
phone_number_id
Phone number ID from Meta Business API (Cloud API mode)
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.phone_number_id field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.phone_number_id field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.phone_number_id <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__phone_number_id=
proxy_url
Per-channel proxy URL (http, https, socks5, socks5h). Overrides the global [proxy] setting for this channel only.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.proxy_url field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.proxy_url field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.proxy_url <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__proxy_url=
push_name
Display name announced to contacts (Web mode, optional) Applied on connect when it differs from the name the linked device already carries; leave unset to keep the account’s own name
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.push_name field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.push_name field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.push_name <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__push_name=
reply_min_interval_secs
Per-(channel, recipient) outbound pacing floor in seconds. Range: 0..=REPLY_MIN_INTERVAL_MAX_SECS (0 disables).
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.reply_min_interval_secs field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.reply_min_interval_secs field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.reply_min_interval_secs <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__reply_min_interval_secs=
reply_queue_depth_max
Per-(channel, recipient) outbound pacing queue depth. Range: 0..=REPLY_QUEUE_DEPTH_CEILING. When reply_min_interval_secs > 0 and this value is 0, the pacing wrapper substitutes DEFAULT_REPLY_QUEUE_DEPTH (16). When the queue is full, the newest send is dropped and a WARN is logged.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.reply_queue_depth_max field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.reply_queue_depth_max field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.reply_queue_depth_max <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__reply_queue_depth_max=
self_chat_mode
When true and mode = “personal”, always respond to messages in the user’s own self-chat (Notes to Self). Defaults to false.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.self_chat_mode field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.self_chat_mode field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.self_chat_mode <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__self_chat_mode=
session_path
Session database path for WhatsApp Web client (Web mode) When set, enables native WhatsApp Web mode with wa-rs
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.session_path field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.session_path field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.session_path <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__session_path=
verify_token 🔑
Webhook verify token (you define this, Meta sends it back for verification) Only used in Cloud API mode
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.verify_token field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.verify_token field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.verify_token # masked input, stored encrypted
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__verify_token=
ws_url
Override the WhatsApp Web WebSocket URL (Web mode, optional). Used by integration tests and proxy setups; leave unset to use the default endpoint that ships with wa-rs.
Set it on any surface:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.ws_url field.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.ws_url field.
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.ws_url <value>
Environment variable
Export the override (POSIX shells; drop into ~/.bashrc, ~/.zshrc, .env, or a Dockerfile). Replace <alias> with the literal alias:
export ZEROCLAW_channels__whatsapp__<alias>__ws_url=
Gateway dashboard
Open /config/channels/whatsapp in the web dashboard.
zerocode
In the Config pane, under Channels.
channels.whatsapp.<alias>.access_tokenis a secret. Stored encrypted, never in plainconfig.toml. Set it through one of these, which encrypt on write:
Gateway dashboard
Open /config/channels/whatsapp and set the channels.whatsapp.<alias>.access_token field there.
zerocode
In the Config pane, set the channels.whatsapp.<alias>.access_token field (input is masked).
zeroclaw config
zeroclaw config set channels.whatsapp.<alias>.access_token # prompts for masked input, stores encrypted
The same applies to verify_token and app_secret (Cloud API).
Start and check
After configuring one mode, start the channel runner:
sh
zeroclaw channel start
Use zeroclaw channel doctor for a first check. For Web mode, also confirm the binary was built with whatsapp-web; for Cloud API mode, confirm the webhook tunnel and Meta verify token agree.