Permissions
Set WhatsApp CLI permission levels per command and distinguish local changes from account writes.
Use this page before you let an AI agent, a script or another person work with your WhatsApp account through wa.
It shows how to decide, for each profile, what may only be read, what asks you first, and what may go ahead without
a question. By the end you can make a profile read-only, allow one action such as sending, and know which other
checks still apply.
Words this page uses:
- Profile: a named set of settings for one linked account, such as
work(profiles). - Permission key: the name of a command or a group of commands, such as
messagesormessages.send. A longer key is more specific. - Access level: what happens when that command runs:
deny,readonly,askorallow.
Start with reading, and allow changes only when you need them.
Choose an access level
| Level | What happens |
|---|---|
deny | The action is refused, including reading. |
readonly | Reading works; changes are refused. |
ask | A change asks in the terminal. |
allow | The action can run without another question. |
With no permissions set, everything is allowed, except deleting and a few other changes, which ask. A refusal
exits with code 5 and names the permission key. It does not mean the link to WhatsApp is broken. Do not ask an
agent to remove a restriction just to finish a task.
Allow one action
wa work config set permissions.messages.send askReplace work with your profile. For a default that allows reading messages and refuses changes:
wa work config set permissions.messages readonlyMore specific keys win: permissions.messages.send ask still permits sending, with a question in the terminal and
without a server form over MCP. Set that key to readonly to refuse sends. Check other exceptions with
wa work config show.
This controls messages. Other actions have their own keys: reactions for reactions, polls for polls and votes,
chats.mark-read for read receipts. The other side sees all three, so give them the same care as sending.
chats.mute and chats.unmute cover chats mute and chats unmute, which nobody else sees; a setting for
chats.mute alone still covers both. messages.star and messages.unstar cover starring a message, which nobody
else sees either. chats.archive, chats.unarchive, chats.pin, chats.unpin and chats.mark-unread cover the
commands of those names, which nobody else sees; each key stands alone, so chats.archive readonly still lets
chats unarchive through. account.update covers account update: other people can see the new name, about and photo.
chats.delete and chats.clear cover deleting a chat or its messages from your own devices; they ask by default,
since nothing brings the messages back.
Questions in scripts
A write at the ask level asks in the terminal. With --json, --no-input or no terminal there is nobody to
answer, so the write is refused with exit code 7 unless you add --yes; a deletion needs --allow-dangerous.
These flags only answer the question. They never lift deny or readonly.
Restrict recipients and repeated sends
A recipient list limits which chats the profile may send to. The first recipients add turns the list on; a send to
any other chat is then refused with exit code 7:
wa work recipients add 100000000000001@lid
wa work recipients list
wa work recipients remove 100000000000001@lidA chat added by its phone number (…@s.whatsapp.net) is saved under its LID when WhatsApp has already given one,
because a send to that number goes to the LID. An entry saved under the phone number earlier moves to the LID by
itself once this device knows the number's LID: when the store holds the chat under the number, the first command
that names it by the number moves the chat and the entry before it acts; otherwise the next serve or watch start
moves the entry. The number is never asked of WhatsApp for this. Until the entry moves, a send to the LID is refused
with exit code 7, and the message names the id to add. recipients remove with the number takes the old entry
off.
Two changes to the list at the same time cannot undo each other. When another process holds the list for 5 s,
the change is refused with exit code 9 and the list stays as it was.
An hourly send limit, sends_per_hour (30 by default), helps stop a loop. wa work sends list shows every attempt
to send — sent, refused, failed or not known — without the text. These checks remain active when a command is
allowed (limits).
A temporary change for an MCP server
Add --permission messages.send=readonly to the server's start command to stop sending for that process. Saved
settings stay the same. --permission only narrows: one that would loosen the profile — readonly to allow, a
deny to anything — stops the server at startup with validation_error naming the key. To let an agent do more,
set the level in the profile itself. Over MCP, ask does not require a server form: the app controls its own
approvals and may allow a call without asking again. Use deny or readonly to refuse changes.
The MCP server and the browser setup explain the full connection.
Limits and detailed rules
An agent that can edit configuration files or run unrestricted terminal commands may be able to change these
settings. Pin it to one profile with WA_PROFILE_LOCK (profiles in linking), and read
security before giving that access. Every setting is in the
configuration reference.