PyWa: a typed Python framework for WhatsApp Cloud API bots
🤖 Hey there! I am using PyWa.
At a glance
- What is it?
- PyWa wraps the WhatsApp Cloud API in typed Python, covering sending, webhooks, templates, interactive flows, and calls, with a decorator based handler model, listeners for multi-turn conversations, and a CLI that can scaffold a bot or send a message from the terminal. It is MIT licensed and Python 3.10 and newer.
- Who is it for?
- PyWa fits a Python team that has to ship a WhatsApp bot on the Cloud API and wants typed objects, a decorator based handler registry, and a webhook server included rather than assembled by hand. It is the wrong choice if you are on the WhatsApp Business Platform rather than the Cloud API, since PyWa targets the Cloud API specifically, and it is the wrong choice if you need unofficial or multi-device access, which it does not attempt.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
PyWa targets the Cloud API and wraps the whole surface
PyWa describes itself as a comprehensive, fully typed Python framework for the WhatsApp Cloud API, handling sending messages, receiving webhooks, building interactive flows, managing templates, and handling calls. That scope statement is the honest summary of what the library covers, and it is broad. The documented capabilities include rich messaging with text, images, videos, documents, audio, stickers, locations, contacts, buttons and lists; real-time webhooks covering messages, button clicks, delivery receipts, read receipts, reactions and account updates; message templates with full parameter support; multi-screen interactive WhatsApp Flows built in pure Python; and incoming and outgoing call events. The audience is a developer who has decided to build on the Cloud API and does not want to hand-roll request signing, payload parsing, and webhook verification for every message type. The library is MIT licensed, distributed on PyPI as `pywa`, and requires Python 3.10 or newer.
Handlers are decorators and filters decide what reaches them
The core model is a decorator on the WhatsApp client that registers a handler with a filter. The README's echo bot is the entire thing:
# main.py
from pywa import WhatsApp, filters, types
wa = WhatsApp(
phone_id="1234567890",
token="EAA...",
app_id=1234567890,
app_secret="********",
callback_url="https://your-domain.ngrok-free.app",
verify_token="my-verify-token",
)
@wa.on_message(filters.text)
def echo(_: WhatsApp, msg: types.Message):
msg.reply(f"You said: {msg.text}")Two design choices stand out. The filter argument means routing is declared next to the handler rather than in a dispatch table, and `filters.command("start")` shows the same mechanism handles command triggers. And the handler receives typed objects, `types.Message` here, with the README describing the project as fully typed with full autocomplete and static analysis everywhere. The constructor also carries the connection details the Cloud API needs, including the callback URL the webhook posts to and the verify token used during webhook subscription.
Listeners turn a handler into a conversation
Handlers are entry points, and listeners are how a bot keeps talking. The README's example shows a handler that replies with a question and then blocks on the answer:
@wa.on_message(filters.command("start"))
def start(_: WhatsApp, msg: types.Message):
name = msg.reply("What's your name?").wait_for_reply(filters=filters.text).text
msg.reply(f"Nice to meet you, {name}!")`msg.reply(...)` returns something with a `wait_for_reply` method that takes its own filter and returns the matched message, so the conversation continues inline in the handler. The README describes the feature as a way to chain conversations naturally, waiting for replies, clicks, or reactions inline. This is the part that most closely resembles an application framework rather than a protocol wrapper, and it is also the part with the most design opinions baked in. If your bot is a set of stateless webhook handlers that write to a queue and answer later, you would use only a fraction of this.
The CLI runs the server and scaffolds projects
PyWa ships a command line tool, which is unusual for a bot framework and saves a lot of setup. The README lists `pywa dev` and `pywa run` to serve the webhook locally or in production, `pywa new` to scaffold a project, and `pywa send` to message from the terminal. The server commands are:
pywa dev # Local development
pywa run # ProductionAnd the scaffolding commands go further than a stub:
pywa new # # Generate a basic echo-bot template
pywa new examples # List the official example botsThe `examples` subcommand browses and downloads ready-to-run bots, and the README lists an order taking bot, OTP verification, WhatsApp Flows, and calls among them. The repository backs this up with an `examples` directory holding numbered projects from `01-message-router` through `12-existing-app-integration`, plus an `examples.json` index, including a delivery tracker, a loan application flow, an onboarding survey, a helpdesk ticket bot, a business profile manager, a call center bot, a community group manager, and a media inbox bot. That set is a better feature list than any marketing summary, because it shows what the library is actually used for.
Your own FastAPI or Flask app can host the webhook
The built-in server is optional. PyWa can be mounted into an existing application, which is the right choice when the bot is one part of a larger service. The README shows the FastAPI form:
from fastapi import FastAPI
from pywa import WhatsApp, filters, types
app = FastAPI()
wa = WhatsApp(..., server=app, webhook_endpoint="/webhook")
@wa.on_message(filters.text)
def echo(_: WhatsApp, msg: types.Message):
msg.reply(msg.text)The client takes the `server` object and the `webhook_endpoint` path, and the rest of the framework is unchanged. The same section of the README also mentions Flask, and the feature table describes the choice as a built-in webhook server or plugging into your existing FastAPI or Flask app. For a team that already has an ASGI app with health checks, routing, and logging in place, this is the mode that avoids running two servers.
Async is a separate package with the same interface
PyWa ships a single `pywa` distribution containing a separate `pywa_async` module, and the README describes the async support as a full async and await API via `pywa_async` with the same interface and zero friction. The rule is simple: swap the import and add `await`.
from pywa_async import WhatsApp, filters, typesThe package build configuration confirms this is a first-class split rather than a flag, with `module-name` set to `["pywa", "pywa_async"]` and `module-root` empty in the `pyproject.toml`. The repository has top-level `pywa/` and `pywa_async/` directories, so the two implementations sit side by side. Two practical notes. The dependency list is deliberately minimal, with `httpx>=0.27,<1.0` as the only required package, which is what makes an async client practical. And the `server` extra exists, since the quick start installs `pywa[server]` rather than the bare package.
Install, run, and the numbers that tell you what to expect
The install command in the README pulls the server extra:
pip install -U "pywa[server]"The project version is 4.5.0, released on 2026-09-24, with 4.4.0 on 2026-08-11 and 4.3.1 on 2026-07-16, and the last push was on 2026-10-16. The classifiers list Python 3.10 through 3.14, mark the project as a production stable development status, and describe it as OS independent, though the framework is in practice tied to a deployed webhook endpoint you have to expose to the internet. The README mentions a hosted option called PyWa Cloud in its banner, described as a way to ship a WhatsApp bot without shipping a server, with a waitlist. That is a separate commercial service rather than part of the open source package, and it is worth keeping the distinction clear if you read the README quickly.
The limits are the Cloud API limits and the version churn
Two constraints bound what this library can do. The first is the platform. PyWa targets the WhatsApp Cloud API, so anything the Cloud API does not expose, including unofficial access through a linked phone, is out of scope by construction, and features such as group management or calls are exposed only as far as the API itself provides them. The second is the 4.x line. The project moved from 3.x to 4.x with breaking changes, which is why the repository carries a `MIGRATION.md` alongside the `CHANGELOG.md`, and a `SECURITY.md` for reporting. A framework this fast-moving is a real operational consideration: pin the version, read the migration notes before upgrading, and expect to touch handler code on a major bump. The one dependency is `httpx`, and the tests and pre-commit configuration live in the repository with a CI workflow, which is a good sign for the maintenance side of the ledger.
Editorial conclusion
PyWa fits a Python team that has to ship a WhatsApp bot on the Cloud API and wants typed objects, a decorator based handler registry, and a webhook server included rather than assembled by hand. It is the wrong choice if you are on the WhatsApp Business Platform rather than the Cloud API, since PyWa targets the Cloud API specifically, and it is the wrong choice if you need unofficial or multi-device access, which it does not attempt. Before adopting it, read `MIGRATION.md` and the changelog for the 4.x line because the API is moving, and confirm your Cloud API credentials and webhook verification token match the constructor parameters before writing business logic.
Frequently asked questions
How do I install PyWa and start a webhook server?
Install with `pip install -U "pywa[server]"`, then run `pywa dev` for local development or `pywa run` in production. The `pywa new` command scaffolds a working project, and `pywa new examples` browses ready-to-run example bots.
How does PyWa handle multi-turn conversations?
Through listeners. A handler can reply with `msg.reply(...)` and then call `wait_for_reply(filters=...)` on the result, which returns the matched message so the conversation continues inline in the handler.
Can I use PyWa with my existing FastAPI or Flask application?
Yes. You pass the app to the client with `server=app` and a `webhook_endpoint` path, and the rest of the framework works the same way. The README lists both FastAPI and Flask as supported hosts.
What is the difference between pywa and pywa_async?
The async package exposes the same API through async and await, so you swap the import to `from pywa_async import WhatsApp, filters, types` and add `await`. The build configuration lists both `pywa` and `pywa_async` as modules in the same distribution.
Which Python versions does PyWa support?
The project requires Python 3.10 or newer, and the classifiers list 3.10, 3.11, 3.12, 3.13, and 3.14. The current release is 4.5.0, published on 2026-09-24.
What licence is PyWa released under?
MIT, declared in the project metadata with the licence file listed in `license-files`. The package is published on PyPI as `pywa` and the documentation lives at pywa.readthedocs.io.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/david-lev-pywa)Was this useful?