CLI Reference
pip install pywa-cloud-cli gives you every command below, reached as pywa cloud <command> —
installing it pulls in pywa itself too, and pywa’s own CLI automatically mounts pywa cloud ... on top of it. A handful of the most common commands also get a top-level shortcut directly on
pywa, shown below wherever one exists: pywa login, pywa logout, pywa whoami, pywa deploy.
Run pywa cloud --help or pywa cloud <command> --help (or, for a shortcut, pywa <command> --help) for the exact same information this page describes, straight from the CLI itself.
pywa login
Section titled “pywa login”pywa login --api-url https://api.pywa.cloud # opens a device-code flowpywa login --token <token> --api-url https://api.pywa.cloud # CI / scripted login(equivalent to pywa cloud login)
With no --token, login starts a real device-code flow: it prints a short code and opens a
confirmation page in your browser, where you sign in and approve it; the CLI polls until you do,
or the code expires after 10 minutes. --token <token> skips all of that and logs in directly
with an existing token — the CI path, and also how a deploy token is normally
used.
No account yet? Sign up at dashboard.pywa.cloud — that’s also where you’d be sent by the device-code link above if you’re not already signed in.
Either way, the resulting token (and API URL) is stored at an OS-standard config location — never in your project directory, so it can’t end up committed by accident:
- macOS:
~/Library/Application Support/pywa-cloud/auth.json - Linux:
$XDG_CONFIG_HOME/pywa-cloud/auth.json(default~/.config/...) - Windows:
%APPDATA%\pywa-cloud\auth.json
Once you’ve logged in, every other command in this reference just works — no --api-url needed
again. $PYWA_CLOUD_CLI_CONFIG_DIR overrides the config location entirely, useful for running
more than one isolated login on one machine.
pywa logout
Section titled “pywa logout”Forgets the stored login. (equivalent to pywa cloud logout)
pywa whoami
Section titled “pywa whoami”Shows the identity the current login resolves to, and which API it’s pointed at. (equivalent to
pywa cloud whoami)
pywa cloud bots create <name> [--slug <slug>] [--entrypoint-override <module:var>] [--bot-directory <path>]pywa cloud bots listpywa cloud bots get <bot-id>pywa cloud bots delete <bot-id>pywa cloud bots set-entrypoint <bot-id> [<module:var>]pywa cloud bots set-directory <bot-id> [<path>]--slug defaults to a lowercase, hyphenated version of <name> if omitted, and must be unique
across Pywa Cloud. Deleting a bot also stops it, if it’s currently running. set-entrypoint sets
or (called with no module:var) clears the bot’s entrypoint override — see
Deploying a Pywa Bot for when you’d need one. set-directory sets or (called
with no path) clears the bot’s application directory, for deploying one member of a monorepo —
see the same guide’s “Working in a monorepo” section.
Environment variables & secrets
Section titled “Environment variables & secrets”pywa cloud env set <bot-id> <key> <value> [--secret]pywa cloud env get <bot-id> <key>pywa cloud env list <bot-id>pywa cloud env delete <bot-id> <key>See Environment Variables & Secrets for the full semantics —
set is create-or-update, and --secret is fixed at creation.
Scaffolding a project
Section titled “Scaffolding a project”There’s no scaffolding command in pywa-cloud-cli itself — use pywa’s own project generator,
with --cloud so the result is deployable as-is:
pywa new --cloud [--async] [-o <directory>]This writes main.py (credentials read from PYWA_PHONE_ID/PYWA_TOKEN/PYWA_VERIFY_TOKEN, no
hardcoded values, no local tunnel setup) plus a real pyproject.toml and .gitignore — ready for
pywa deploy as-is. Plain pywa new (no --cloud) is pywa’s own default scaffold instead:
meant for editing and running locally, not deploying as-is. See pywa new --help (or
pywa’s own docs) for the full set of options.
Deploying a Pywa Bot covers what a project needs to be deployable if you’d
rather write one from scratch or adapt an existing project.
Linking a directory
Section titled “Linking a directory”pywa cloud link <bot-id> [path]pywa cloud unlink [path]path defaults to the current directory. See Deploying a Pywa Bot for how
this interacts with deploy.
Deploying
Section titled “Deploying”pywa deploy [path] [--bot <bot-id>](equivalent to pywa cloud deploy)
A directory’s first deploy asks which bot this is (or pass --bot to skip the prompt — required
in CI, where there’s no terminal to ask); later deploys in the same directory reuse the link
automatically. See Deploying a Pywa Bot for what actually happens and what’s
excluded from the upload.
pywa cloud deployments list [--bot <bot-id>]pywa cloud deployments get <deployment-id> [--bot <bot-id>]pywa cloud deployments log <deployment-id> [--bot <bot-id>]pywa cloud deployments rollback <deployment-id> [--bot <bot-id>]deployments list shows past deployments for a bot (status, Python version, timestamp).
deployments get fetches full metadata for a specific deployment attempt. deployments rollback
re-runs a previous successful deployment’s already-built image directly — no re-upload, no
rebuild — using the bot’s current env vars (so a secret rotated since then still applies), and
records a new deployment rather than mutating the old one. Requires the Admin/Owner team role.
deployments log (alias logs) views that deployment’s full build log.
Managing a running bot
Section titled “Managing a running bot”pywa cloud status [--bot <bot-id>]pywa cloud stop [--bot <bot-id>]pywa cloud start [--bot <bot-id>]pywa cloud restart [--bot <bot-id>]See Managing a Running Bot for what each one actually does, and what’s automatic versus what needs you to act.
pywa cloud health [--bot <bot-id>]pywa cloud metrics [--bot <bot-id>]health makes a real request into your bot (an unauthenticated GET, expecting pywa’s own webhook
challenge handler to answer 403) — stronger proof of life than status, which only reflects
whether the process is running, not whether it’s actually serving traffic correctly. metrics
shows live CPU/memory usage next to your plan’s resource limits, plus request-volume/latency stats
(total count, counts by status code, p50/p95/p99) for traffic actually proxied to this bot.
Connecting WhatsApp
Section titled “Connecting WhatsApp”pywa cloud connect [--bot <bot-id>]pywa cloud connect-status [--bot <bot-id>]pywa cloud waba list [--bot <bot-id>]pywa cloud waba connect-manual <waba-id> <business-token> [--app-secret <secret>] [--bot <bot-id>]pywa cloud whatsapp assign <connection-id> <phone-id> [--bot <bot-id>]pywa cloud whatsapp disconnect [--bot <bot-id>]See Connecting a WhatsApp Number. A WABA connection is a
team-level resource, shared across every bot on the team — connect is the interactive entry
point: it starts (or reuses) a team’s Meta Embedded Signup connection, then walks you through
picking one of its phone numbers for the given bot; the Embedded Signup link itself is single-use
and expires after 15 minutes. connect-status shows whether (and to which WABA/phone) the bot is
currently connected, including a warning if Meta has since flagged the underlying WABA as
disconnected/restricted/banned. waba list/waba connect-manual and whatsapp assign/disconnect are the non-interactive equivalents — list a team’s WABA connections, connect
one directly with a token from your own separate Meta App, or assign/clear a bot’s phone number by
id without the interactive picker.
Database integrations
Section titled “Database integrations”pywa cloud integrations list [--bot <bot-id>]pywa cloud integrations connect <provider> [--bot <bot-id>]See Database Integrations. integrations list shows which
providers are available (neon, supabase today); integrations connect neon (or connect supabase) opens a browser to the provider’s own consent screen and, once authorized,
auto-provisions a Postgres database and writes its connection string as this bot’s DATABASE_URL
secret — no copy-pasting a connection string by hand. The link is single-use and expires after 15
minutes. Doesn’t trigger a redeploy on its own — your next real deploy is what picks the new
secret up.
pywa cloud logs [--bot <bot-id>] [--tail <n>] [--since <timestamp>] [--follow] [--interval <seconds>]See Logs. --tail defaults to 200 lines; --since (RFC3339, e.g.
2024-01-01T00:00:00Z) is a one-shot filter and is ignored together with --tail when combined
with --follow, which manages its own cursor; --follow polls every --interval seconds
(default 2.0) until Ctrl+C.
Local development
Section titled “Local development”pywa dev --tunnel [--bot <bot-id>]The usual way to develop against real Meta webhooks: pywa dev (pywa’s own local dev server) with
--tunnel also relays this bot’s inbound webhook traffic here instead of to its deployed version,
so you don’t need a separate tunnel tool or a repointed callback URL. --bot picks which Pywa
Cloud bot to relay from (defaults to the current directory’s linked bot). Note that --tunnel only
relays webhook traffic — it does not fetch or inject the bot’s real WhatsApp credentials into your
environment; pywa dev still runs against whatever PYWA_TOKEN/PYWA_PHONE_ID/etc. your own
project already provides (a local .env, hardcoded values, etc.).
pywa cloud tunnel [--port <local-port>] [--bot <bot-id>]The same relay as a standalone, foreground command — for pairing with anything other than pywa dev (a different framework runner, a manual process, etc.). --port (default 8000) is the port
your own bot process is listening on. Opt-in and explicit either way: only active while the
command is running; Ctrl+C (or any disconnect) hands traffic straight back to the deployed version.
Deploy tokens (CI)
Section titled “Deploy tokens (CI)”pywa cloud deploy-tokens create <bot-id> <name> [--expires-in-days <n>] # n: 1-365, default 90pywa cloud deploy-tokens list <bot-id>pywa cloud deploy-tokens delete <bot-id> <token-id>pywa cloud deploy-tokens regenerate <bot-id> <token-id> [--expires-in-days <n>]A deploy token is scoped to exactly one bot and can only be used for deploy — nothing else. The
token value is shown once, at creation (or regeneration), and never again; losing it means
regenerate, not looking it up. For CI, skip pywa login entirely:
export PYWA_CLOUD_TOKEN=<the deploy token>export PYWA_CLOUD_BOT_ID=<bot-id>export PYWA_CLOUD_API_URL=https://api.pywa.cloudpywa deployThis bypasses your stored personal login completely — nothing CI runs ever touches it. --bot on
deploy itself works too, instead of PYWA_CLOUD_BOT_ID.
CI setup
Section titled “CI setup”pywa cloud setup-ci [--bot <bot-id>] [--branch <name>] [--force]Scaffolds .github/workflows/deploy.yml in the current project, wiring up the deploy-token flow
above as an automated on-push deploy. Reads repository secrets PYWA_CLOUD_TOKEN,
PYWA_CLOUD_BOT_ID, and PYWA_CLOUD_API_URL — add these under your repo’s Settings → Secrets
before the workflow can run. --branch defaults to whatever branch your project’s own git
checkout is currently on; --force overwrites an existing workflow file. The generated workflow
installs both pywa and pywa-cloud-cli (pywa alone doesn’t pull the cloud package in) and runs
pywa cloud deploy.
Not built yet
Section titled “Not built yet”Billing/usage metering — a business decision that hasn’t been made yet, not just an unbuilt
command. Teams, roles, and invites are fully implemented (see
Accounts, Teams & Permissions) but don’t have CLI commands of their
own yet, since day-to-day account use rarely needs them — pywa login/logout/whoami above
already cover the everyday auth surface.