Skip to content

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.

Terminal window
pywa login --api-url https://api.pywa.cloud # opens a device-code flow
pywa 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.

Forgets the stored login. (equivalent to pywa cloud logout)

Shows the identity the current login resolves to, and which API it’s pointed at. (equivalent to pywa cloud whoami)

Terminal window
pywa cloud bots create <name> [--slug <slug>] [--entrypoint-override <module:var>] [--bot-directory <path>]
pywa cloud bots list
pywa 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.

Terminal window
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.

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:

Terminal window
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.

Terminal window
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.

Terminal window
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.

Terminal window
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.

Terminal window
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.

Terminal window
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.

Terminal window
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.

Terminal window
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.

Terminal window
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.

Terminal window
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.).

Terminal window
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.

Terminal window
pywa cloud deploy-tokens create <bot-id> <name> [--expires-in-days <n>] # n: 1-365, default 90
pywa 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:

Terminal window
export PYWA_CLOUD_TOKEN=<the deploy token>
export PYWA_CLOUD_BOT_ID=<bot-id>
export PYWA_CLOUD_API_URL=https://api.pywa.cloud
pywa deploy

This bypasses your stored personal login completely — nothing CI runs ever touches it. --bot on deploy itself works too, instead of PYWA_CLOUD_BOT_ID.

Terminal window
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.

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.