🚀 Build WhatsApp Bots in Python • Fast, Effortless, Powerful
Project description
PyWa
The Python framework for building WhatsApp bots.
Fast. Typed. Production-ready. From prototype to production in minutes.
PyWa is a comprehensive, fully-typed Python framework for the WhatsApp Cloud API. It handles everything — sending messages, receiving webhooks, building interactive flows, managing templates, handling calls — so you can focus on building your bot, not wrestling with the API.
pip install -U "pywa[server]"
✨ Why PyWa?
| 💬 Rich Messaging | Text, images, videos, documents, audio, stickers, locations, contacts, buttons, lists & more |
| 📩 Real-Time Webhooks | Messages, button clicks, delivery receipts, read receipts, reactions & account updates |
| 🔔 Listeners | Chain conversations naturally — wait for replies, clicks, or reactions inline |
| 📄 Templates | Create, send, and manage WhatsApp message templates with full parameter support |
| ♻️ Flows | Build rich, multi-screen interactive WhatsApp Flows in pure Python |
| 📞 Calls | Handle incoming and outgoing WhatsApp call events |
| ⚡ Async Support | Full async/await API via pywa_async — same interface, zero friction |
| 🔌 Server Integrations | Built-in webhook server, or plug into your existing FastAPI / Flask app |
| 🛡️ Type Safety | Fully typed - full autocomplete and static analysis everywhere |
| 🔬 Smart Filters | Composable filters with logical operators for precise update routing |
| 🧰 CLI Tools | pywa dev for local development, pywa run for production |
🚀 Quick Start
1. Echo Bot — 5 lines of code
# 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}")
Start the webhook server:
pywa dev # Local development
pywa run # Production
2. Rich Messages — Buttons, Media & More
from pywa import WhatsApp, types
wa = WhatsApp(phone_id="1234567890", token="EAA...")
# Text with interactive buttons
wa.send_message(
to="9876543210",
text="How can I help you today?",
buttons=[
types.Button(title="📋 Menu", callback_data="menu"),
types.Button(title="💬 Support", callback_data="help"),
],
)
# Images, documents, audio — one-liners
wa.send_image(to="9876543210", image="https://example.com/photo.jpg", caption="Check this out!")
wa.send_document(to="9876543210", document="report.pdf")
3. Conversational Flows — Listeners
Handlers define entry points. Listeners let you continue the conversation naturally:
@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}!")
4. Plug Into Your Own Server
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)
@app.get("/")
def health():
return {"status": "ok"}
5. Full Async Support
Same API. Just swap the import and add await:
from pywa_async import WhatsApp, filters, types
wa = WhatsApp(...)
@wa.on_message(filters.text)
async def hello(_: WhatsApp, msg: types.Message):
await msg.react("👋")
await msg.reply("Hello from async PyWa!")
6. Templates
Create and send WhatsApp message templates with full parameter support:
from pywa import WhatsApp
from pywa.types.templates import *
wa = WhatsApp(..., waba_id=123456)
wa.create_template(
template=Template(
name="order_update",
category=TemplateCategory.MARKETING,
language=TemplateLanguage.ENGLISH_US,
parameter_format=ParamFormat.NAMED,
components=[
ht := HeaderText("Your order #{{order_id}} has shipped!", order_id="12345"),
bt := BodyText("Track it with code {{code}}.", code="ABC123"),
FooterText(text="Powered by PyWa"),
Buttons(buttons=[
url := URLButton(text="Track Order", url="https://example.com/track/{{1}}", example="12345"),
QuickReplyButton(text="Unsubscribe"),
]),
],
),
)
# Send it
wa.send_template(
to="9876543210",
name="order_update",
language=TemplateLanguage.ENGLISH_US,
params=[
ht.params(order_id="67890"),
bt.params(code="XYZ789"),
url.params(url_variable="67890", index=0),
],
)
7. Interactive Flows
Build WhatsApp Flows — multi-screen interactive experiences — entirely in Python:
from pywa import WhatsApp, types
from pywa.types.flows import *
wa = WhatsApp(..., waba_id=123456)
my_flow = FlowJSON(
screens=[
Screen(
id="SIGNUP",
title="Join Our Newsletter",
layout=Layout(children=[
TextHeading(text="Subscribe for updates"),
name := TextInput(name="name", label="Name", input_type=InputType.TEXT),
email := TextInput(name="email", label="Email", input_type=InputType.EMAIL, required=True),
Footer(
label="Subscribe",
on_click_action=CompleteAction(
payload={"name": name.ref, "email": email.ref}
),
),
]),
)
]
)
wa.create_flow(name="newsletter_signup", categories=[FlowCategory.SIGN_UP], flow_json=my_flow, publish=True)
@wa.on_flow_completion
def on_signup(_: WhatsApp, flow: types.FlowCompletion):
flow.reply(text=f"Welcome, {flow.response['name']}! You're subscribed at {flow.response['email']}.")
8. Account & Resource Management
Beyond messaging, PyWa gives you full control over your WhatsApp Business resources:
from pywa import WhatsApp
wa = WhatsApp(phone_id="1234567890", token="EAA...", waba_id=123456)
# Business profile
profile = wa.get_business_profile()
wa.update_business_profile(about="Powered by PyWa", description="We build bots!", profile_picture="profile.jpg")
# Media management
media = wa.upload_media(media="photo.jpg")
media.stream(), media.download(), media.reupload(), media.delete()
# QR codes
qr = wa.create_qr_code(prefilled_message="Hi! I saw your QR code")
qr.qr_image_url, qr.code, qr.update(prefilled_message="Hello"), qr.delete()
# Usernames
wa.get_reserved_usernames()
wa.set_username(username="mybusiness")
wa.get_current_username()
# Groups
wa.create_group(subject="VIP Customers")
wa.get_groups()
wa.get_group_join_requests()
# Commerce
wa.get_commerce_settings()
wa.update_commerce_settings(is_catalog_visible=True, is_cart_enabled=
True)
# User management
wa.block_users(users=["9876543210"])
blocked = wa.get_blocked_users()
See the Client guide for the full resource management API — templates, flows, media, QR codes, commerce, groups, calls, and more.
9. Partners & Tech Providers
Building a platform on top of WhatsApp? PyWa supports multi-WABA management, phone number provisioning, and callback routing for Solution Partners and Tech Providers:
from pywa import WhatsApp, types, filters
wa = WhatsApp(phone_id="1234567890", token="EAA...", waba_id=123456)
@wa.on_message(filters.sent_to(phone_number_id=...))
def handle_message_for_specific_phone_number(wa: WhatsApp, msg: types.Message): ...
@wa.on_account_update(filters.account_restriction)
def handle_account_restriction(wa: WhatsApp, update: types.AccountUpdate): ...
@wa.on_message(filters.account_deleted)
def handle_account_deletion(wa: WhatsApp, update: types.AccountUpdate): ...
# Get all WABAs you manage
shared_wabas = wa.get_shared_business_accounts()
owned_wabas = wa.get_owned_business_accounts()
# Provision phone numbers on a WABA
phone = wa.create_phone_number(country_calling_code="1", phone_number="5551234567", verified_name="John Doe")
wa.request_verification_code(phone_id=phone.id, code_method="SMS")
wa.verify_phone_number(code="123456", phone_id=phone.id)
wa.register_phone_number(phone_id=phone.id)
# Route webhooks per-WABA or per-phone
wa.override_waba_callback_url(callback_url="https://your-platform.com/waba/123")
wa.override_phone_callback_url(callback_url="https://your-platform.com/phone/456")
# Migrate templates & flows between WABAs
wa.migrate_templates(source_waba_id=111111, destination_waba_id=222222)
wa.migrate_flows(source_waba_id=111111, destination_waba_id=222222, source_flow_names=["flow_1"])
📦 Installation
# Core (sending messages, no webhook server)
pip install -U pywa
# With built-in webhook server (recommended)
pip install -U "pywa[server]"
# For Flow encryption support
pip install -U "pywa[cryptography]"
# Everything
pip install -U "pywa[server,cryptography]"
Requirements: Python 3.10+
📚 Documentation
Full documentation is available at pywa.readthedocs.io.
| Topic | Description |
|---|---|
| Getting Started | Setup, first bot, and key concepts |
| Client | Sending messages, media, and managing resources |
| Handlers | Decorators, filters, and webhook routing |
| Listeners | Conversational flows and inline waiting |
| Updates | Message, callback, status, and system updates |
| Filters | Composable, reusable update filtering |
| Templates | Create, send, and manage message templates |
| Flows | Build interactive multi-screen flows |
| Calls | Handle voice call events |
🤝 Contributing
Contributions are welcome! Check out the Contributing Guide to get started.
💬 Community
Questions? Ideas? Join the conversation:
- 💬 Telegram Chat — Community discussions & support
- 📢 Telegram Channel — Announcements & updates
⚖️ License
PyWa is open-source software licensed under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pywa-4.2.1.tar.gz.
File metadata
- Download URL: pywa-4.2.1.tar.gz
- Upload date:
- Size: 365.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d868f954a5b40a7282a29223a4a283b473c619552dcac17ee5b9ef1ade53e2a0
|
|
| MD5 |
b6dc980ef012e5215d028b1b52856541
|
|
| BLAKE2b-256 |
8fe2fbc1b5aabeac51f58a4e9446a8771a020a570e38de8fd717250a37ad8e6f
|
Provenance
The following attestation bundles were made for pywa-4.2.1.tar.gz:
Publisher:
publish.yml on david-lev/pywa
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pywa-4.2.1.tar.gz -
Subject digest:
d868f954a5b40a7282a29223a4a283b473c619552dcac17ee5b9ef1ade53e2a0 - Sigstore transparency entry: 2036791316
- Sigstore integration time:
-
Permalink:
david-lev/pywa@4e5789a52d3b98462b7db45d37b01c6f8e72dd0a -
Branch / Tag:
refs/tags/4.2.1 - Owner: https://github.com/david-lev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4e5789a52d3b98462b7db45d37b01c6f8e72dd0a -
Trigger Event:
release
-
Statement type:
File details
Details for the file pywa-4.2.1-py3-none-any.whl.
File metadata
- Download URL: pywa-4.2.1-py3-none-any.whl
- Upload date:
- Size: 355.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c05579a78c87a6734545d259e0f3343566bd9bd7a39327f40c6e46ffe8cc68d6
|
|
| MD5 |
0da0bf9219584db553263378825c1175
|
|
| BLAKE2b-256 |
a80fa035bc77b4a018ed2c0eda16efd53776f929309af64eb3f053fc6e963ae8
|
Provenance
The following attestation bundles were made for pywa-4.2.1-py3-none-any.whl:
Publisher:
publish.yml on david-lev/pywa
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pywa-4.2.1-py3-none-any.whl -
Subject digest:
c05579a78c87a6734545d259e0f3343566bd9bd7a39327f40c6e46ffe8cc68d6 - Sigstore transparency entry: 2036791425
- Sigstore integration time:
-
Permalink:
david-lev/pywa@4e5789a52d3b98462b7db45d37b01c6f8e72dd0a -
Branch / Tag:
refs/tags/4.2.1 - Owner: https://github.com/david-lev
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4e5789a52d3b98462b7db45d37b01c6f8e72dd0a -
Trigger Event:
release
-
Statement type: