A WhatsApp Business number as a bot
Use a WhatsApp Business test number through Meta's Cloud API, separately from personal device linking.
wa <profile> bot … speaks for a WhatsApp Business number on Meta's
Cloud API, not for your
own WhatsApp. It never links a device and never starts the engine that wa <profile> chats … uses. It talks to
graph.facebook.com over HTTPS with a token you keep in the system keychain.
Never register your own phone number, or any number whose WhatsApp you still use on a phone. Registering a number on the Cloud API deletes that number's WhatsApp account. Use Meta's free test number, or a number that has no WhatsApp account.
What you can do
A chat is the person's phone number in digits, such as 70000000001. Meta names some people only by a
business-scoped user id; bot watch shows that chat as user:<id>, and you send to it the same way.
The 24-hour rule. You can send free text only within 24 hours of the person's last message to the number. After
that, WhatsApp delivers only a template. When the local store holds the person's last message, wa refuses a late
free-form send before it leaves and tells you to send a template. When it does not, Meta refuses it.
Set up the test number
You do these steps once, in Meta's App Dashboard. wa cannot do them for you.
-
On Meta for Developers, create an app with the use case "Connect with customers through WhatsApp". Meta adds a test WhatsApp Business Account and a test number.
-
Under WhatsApp → API Setup, add up to five recipient numbers and confirm each with the code WhatsApp sends to it. The test number sends only to these.
-
In Business Settings, create a system user with the
business_management,whatsapp_business_messagingandwhatsapp_business_managementpermissions, and generate a token for it that does not expire. Note the app secret under App settings → Basic. -
Copy the phone number ID and the WhatsApp Business Account ID from WhatsApp → API Setup into the profile:
wa cloudtest config set --bot phone_number_id 100000000000001 wa cloudtest config set --bot waba_id 200000000000002graph_versionisv23.0unless you set another. -
Keep the token and the two secrets. Each command asks at a hidden prompt; nothing appears on screen or in the shell history:
wa cloudtest bot auth set wa cloudtest bot auth set --secret app-secret wa cloudtest bot auth set --secret verify-tokenThe verify token is any string you choose. You type the same string in the App Dashboard in step 6.
-
Open a tunnel and start the receiver (receive messages). Then, in WhatsApp → Configuration, enter the tunnel's address as the Callback URL with the same verify token, and subscribe to the
messagesfield.
Check it: wa cloudtest bot me names the test number, and
wa cloudtest bot templates send <your verified number> hello_world arrives on your phone.
Receive messages
Meta never lets a client ask for new messages. It sends each one to an HTTPS address you give it, and retries for up
to seven days until that address answers. bot watch --public-url is that address's receiver: it listens on
127.0.0.1:8766 on your computer, and your tunnel publishes it.
wa cloudtest bot watch --public-url https://<name>.ts.net:8443- It answers Meta's subscription check with the verify token you kept.
- It refuses any delivery whose
X-Hub-Signature-256does not match your app secret. - It answers Meta only after the message is in the local store, so a crash or a full disk loses nothing: Meta sends it again.
--portchanges the local port. The receiver needs its own port and its own public address besidemcp --http.
The tunnel must keep one address: Meta checks each new address again. Use Tailscale Funnel or a named Cloudflare Tunnel, set up as in ChatGPT, Codex or Claude in the browser. A Cloudflare Quick Tunnel changes its address every time it starts.
Meta keeps one callback address per app, set in the App Dashboard, and sends template and account events only there.
bot webhooks set <url> adds an address for this number alone; set it to the same tunnel address.
Permissions
A bot profile has its own permissions under bot in the configuration. bot api operations that cannot be undone,
such as register-phone-number and delete-template, ask before they run. The recipient list and the hourly limit
apply to bot sends as to personal ones (permissions).