π Build WhatsApp Bots in Python β’ Fast. Effortless. Powerful.
π€ Hey there! I am using PyWa.
π« PyWa is an all-in-one Python framework for the WhatsApp Cloud API.
Send rich media messages, use interactive buttons, listen to real-time events, build and send flows, design and send template messages, and enjoy blazing-fast async support with full integration for FastAPI, Flask, and more. Fully typed, documented, and production-ready β build powerful bots in minutes.
π Quick Documentation Index#
Get Started β’ WhatsApp Client β’ Handlers β’ Listeners β’ Filters β’ Updates β’ Flows β’ Examples
β‘ Why PyWa?#
π Fast and Simple: Focus on building your bot without worrying about low-level details.
π¬ Rich Messaging: Send text, images, videos, documents, audio, locations, contacts, and interactive keyboards.
π© Real-Time Updates: Receive messages, callbacks, and message status updates effortlessly.
π Listeners: Use powerful listeners to wait for specific user events.
β»οΈ Flows Support: Create, send, and listen to Flows seamlessly.
π Webhook Integration: Built-in support for popular frameworks like Flask and FastAPI.
π¬ Advanced Filters: Handle incoming updates with powerful filtering options.
π Template Messaging: Easily create and send template messages.
β Production-Ready: Fully typed, documented, and rigorously tested for reliability.
π¨βπ» How to Use#
Send a message
See WhatsApp Client for all the options.
from pywa import WhatsApp, types
# Create a WhatsApp client
wa = WhatsApp(
phone_id="100458559237541",
token="EAAEZC6hUxkTIB"
)
# Send a text message with buttons
wa.send_message(
to="9876543210",
text="Hello from PyWa!",
buttons=[
types.Button(title="Menu", callback_data="menu"),
types.Button(title="Help", callback_data="help")
]
)
# Send a image message from URL
wa.send_image(
to="9876543210",
image="https://example.com/image.jpg",
caption="Check out this image!",
)
Handle incoming updates (with FastAPI in this example)
See Handlers for fully detailed guide.
# wa.py
from pywa import WhatsApp, filters, types
from fastapi import FastAPI
fastapi_app = FastAPI() # FastAPI server
# Create a WhatsApp client
wa = WhatsApp(
phone_id=1234567890,
token="************",
server=fastapi_app, # the server to listen to incoming updates
callback_url="https://yourdomain.com/", # the public URL of your server
verify_token="xyz123", # some random string to verify the webhook
app_id=123456, # your app id
app_secret="*******" # your app secret
)
# Register callback to handle incoming messages
@wa.on_message(filters.matches("Hello", "Hi")) # Filter to match text messages that contain "Hello" or "Hi"
def hello(client: WhatsApp, msg: types.Message):
msg.react("π") # React to the message with a wave emoji
msg.reply_text( # Short reply to the message
text=f"Hello {msg.from_user.name}!", # Greet the user
buttons=[ # Add buttons to the reply
types.Button(
title="About me",
callback_data="about_me" # Callback data to identify the click
)
]
)
# Use the `wait_for_reply` listener to wait for a reply from the user
age = msg.reply(text="What's your age?").wait_for_reply(filters=filters.text).text
msg.reply_text(f"Your age is {age}.")
# Register another callback to handle incoming button clicks
@wa.on_callback_button(filters.matches("about_me")) # Filter to match the button click
def click_me(client: WhatsApp, clb: types.CallbackButton):
clb.reply_text(f"Hello {clb.from_user.name}, I am a WhatsApp bot built with PyWa!") # Reply to the button click
To run the server, use fastapi-cli (
pip install "fastapi[standard]"):
fastapi dev wa.py # see uvicorn docs for more options (port, host, reload, etc.)
Async Usage
PyWa also supports async usage with the same API. This is useful if you want to use async/await in your code. To use the async version, replace all the imports from
pywatopywa_async:
# wa.py
import fastapi
from pywa_async import WhatsApp, types # Same API, just different imports
fastapi_app = fastapi.FastAPI()
wa = WhatsApp(..., server=fastapi_app)
async def main():
await wa.send_message(...) # async call
@wa.on_message
async def hello(_: WhatsApp, msg: types.Message): # async callback
await msg.react("π")
await msg.reply(...)
Create and send flows
See Flows for much more details and examples.
from pywa import WhatsApp, types
from pywa.types.flows import *
# Create a WhatsApp client
wa = WhatsApp(..., business_account_id=123456)
# Build a flow
my_flow_json = FlowJSON(
screens=[
Screen(
id="NEWSLETTER",
title="PyWa Newsletter",
layout=Layout(
children=[
TextHeading(text="Subscribe to our newsletter"),
name := TextInput(
name="name",
label="Name",
input_type=InputType.TEXT,
required=False,
),
email := TextInput(
name="email",
label="Email",
input_type=InputType.EMAIL,
required=True,
),
Footer(
label="Subscribe",
on_click_action=CompleteAction(
payload={ # Payload to send to the server
"name": name.ref,
"email": email.ref,
}
)
)
]
)
)
]
)
# Create the flow
wa.create_flow(
name="subscribe_to_newsletter",
categories=[FlowCategory.SIGN_UP, FlowCategory.OTHER],
flow_json=my_flow_json,
publish=True
)
# Send the flow to a user
wa.send_text(
to="9876543210",
text="Hello from PyWa!",
buttons=types.FlowButton(
title="Subscribe to our newsletter!",
flow_name="subscribe_to_newsletter",
)
)
# Handle the flow response
@wa.on_flow_completion
def handle_flow_response(_: WhatsApp, flow: types.FlowCompletion):
flow.reply(
text=f"Thank you for subscribing to our newsletter, {flow.response['name']}! "
f"We will send you updates to {flow.response['email']}.",
buttons=[types.Button(title="Unsubscribe", callback_data="unsubscribe")]
)
Create and send template messages
from pywa import WhatsApp
from pywa.types.templates import *
wa = WhatsApp(..., business_account_id=123456)
# Create a template
wa.create_template(
template=Template(
name="buy_new_iphone_x",
category=TemplateCategory.MARKETING,
language=TemplateLanguage.ENGLISH_US,
parameter_format=ParamFormat.NAMED,
components=[
ht := HeaderText("The New iPhone {{iphone_num}} is here!", iphone_num=15),
bt := BodyText("Buy now and use the code {{code}} to get {{per}}% off!", code="WA_IPHONE_15", per=15),
FooterText(text="Powered by PyWa"),
Buttons(
buttons=[
url := URLButton(text="Buy Now", url="https://example.com/shop/{{1}}", example="iphone15"),
PhoneNumberButton(text="Call Us", phone_number="1234567890"),
qrb1 := QuickReplyButton(text="Unsubscribe from marketing messages"),
qrb2 := QuickReplyButton(text="Unsubscribe from all messages"),
]
),
]
),
)
# Send the template message
wa.send_template(
to="9876543210",
name="buy_new_iphone_x",
language=TemplateLanguage.ENGLISH_US,
params=[
ht.params(iphone_num=30),
bt.params(code="WA_IPHONE_30", per=30),
url.params(url_variable="iphone30", index=0),
qrb1.params(callback_data="unsubscribe_from_marketing_messages", index=1),
qrb2.params(callback_data="unsubscribe_from_all_messages", index=2),
]
)
π Installation#
Install using pip3:
pip3 install -U pywa
Install from source (the bleeding edge):
pip3 install -U git+https://github.com/david-lev/pywa.git
If you going to use the webhook features, here is shortcut to install the required dependencies:
pip3 install -U "pywa[fastapi]"
pip3 install -U "pywa[flask]"
If you going to use the Flow features and want to use the default FlowRequestDecryptor and the default FlowResponseEncryptor, here is shortcut to install the required dependencies:
pip3 install -U "pywa[cryptography]"
πΎ Requirements#
Python 3.10 or higher - https://www.python.org
π Setup and Usage#
See the Documentation for detailed instructions
βοΈ TODO#
~~Add support for async~~
~~Add support for more web frameworks (Django, aiohttp, etc.)~~
~~Add support for flows~~
Add support for more types of updates (
account_alerts,phone_number_quality_updates,template_category_updates, etc.)Add more examples and guides
Feel free to open an issue if you have any suggestions. or even better - submit a PR!
βοΈ License#
This project is licensed under the MIT License - see the LICENSE file for details
π± Contributing#
Contributions are welcome! Please see the Contributing Guide for more information.
π Changelog#
NOTE: pywa follows the semver versioning standard.
3.0.0-rc.3 (2025-08-06)#
[templates]
paramsis now can be called on class level[templates] adding support for
library_inputwhen creating library templates[templates] adding support for
degrees_of_freedom_specwhen creating template[listeners] handling old
toparameter inlistenand update migration guide
3.0.0-rc.2 (2025-08-04)#
[client] allowing to use mm-lite-api when sending a template
[templates] allowing to set app-depplinks in
URLButtonβs[templates] adding
TopBlockReasonTypeenum[client] adding
get_business_accountmethod[client] adding
deregister_phone_numbermethod[client] allowing to get and set
StorageConfiguration[callback] adding
is_quick_replytoCallbackButton[callback] validate not
kw_onlyin dataclasses[client] fix creating
LibraryTemplate[system] support old
customer_changed_numbersys type[docs] new logo for pywa!
3.0.0-rc.1 (2025-07-31)#
[templates] refactored and improved templates support
See the full changelog here.
π Contents#
- βοΈ Get Started
- π Client
WhatsApp- Sending messages
- Handling updates
- Listening
- Media
- Templates
- Flows
- Business
- Managing users
- QR Codes
- Commerce
- Calls
- Server
- Others
- Client Reference
WhatsApp.send_message()WhatsApp.send_image()WhatsApp.send_video()WhatsApp.send_audio()WhatsApp.send_document()WhatsApp.send_location()WhatsApp.request_location()WhatsApp.send_contact()WhatsApp.send_sticker()WhatsApp.send_catalog()WhatsApp.send_template()WhatsApp.send_product()WhatsApp.send_products()WhatsApp.send_reaction()WhatsApp.remove_reaction()WhatsApp.mark_message_as_read()WhatsApp.indicate_typing()WhatsApp.listen()WhatsApp.stop_listening()WhatsApp.upload_media()WhatsApp.download_media()WhatsApp.get_media_url()WhatsApp.delete_media()WhatsApp.get_business_account()WhatsApp.get_business_profile()WhatsApp.get_business_phone_numbers()WhatsApp.get_business_phone_number()WhatsApp.get_business_phone_number_settings()WhatsApp.update_business_phone_number_settings()WhatsApp.update_business_profile()WhatsApp.update_display_name()WhatsApp.update_conversational_automation()WhatsApp.set_business_public_key()WhatsApp.get_commerce_settings()WhatsApp.update_commerce_settings()WhatsApp.create_template()WhatsApp.upsert_authentication_template()WhatsApp.update_template()WhatsApp.get_template()WhatsApp.get_templates()WhatsApp.delete_template()WhatsApp.unpause_template()WhatsApp.migrate_templates()WhatsApp.create_flow()WhatsApp.update_flow_metadata()WhatsApp.update_flow_json()WhatsApp.publish_flow()WhatsApp.delete_flow()WhatsApp.deprecate_flow()WhatsApp.get_flow()WhatsApp.get_flows()WhatsApp.get_flow_metrics()WhatsApp.get_flow_assets()WhatsApp.migrate_flows()WhatsApp.block_users()WhatsApp.unblock_users()WhatsApp.get_blocked_users()WhatsApp.register_phone_number()WhatsApp.deregister_phone_number()WhatsApp.create_qr_code()WhatsApp.get_qr_code()WhatsApp.get_qr_codes()WhatsApp.update_qr_code()WhatsApp.delete_qr_code()WhatsApp.get_call_permissions()WhatsApp.pre_accept_call()WhatsApp.accept_call()WhatsApp.reject_call()WhatsApp.terminate_call()WhatsApp.get_app_access_token()WhatsApp.set_app_callback_url()WhatsApp.override_waba_callback_url()WhatsApp.delete_waba_callback_url()WhatsApp.override_phone_callback_url()WhatsApp.delete_phone_callback_url()WhatsApp.webhook_update_handler()WhatsApp.webhook_challenge_handler()WhatsApp.get_flow_request_handler()WhatsApp.load_handlers_modules()
- API Reference
- Client Reference
- ποΈ Handlers
- Automatically registering the callback url
- Registering the callback url manually in the WhatsApp App Dashboard
- Available handlers
- Filtering updates
- Listen instead of registering
- Stop or continue handling updates
- Validating the updates
- Handler Decorators
WhatsApp.on_message()WhatsApp.on_callback_button()WhatsApp.on_callback_selection()WhatsApp.on_flow_completion()WhatsApp.on_flow_request()WhatsApp.on_message_status()WhatsApp.on_chat_opened()WhatsApp.on_phone_number_change()WhatsApp.on_identity_change()WhatsApp.on_call_connect()WhatsApp.on_call_terminate()WhatsApp.on_call_status()WhatsApp.on_call_permission_update()WhatsApp.on_user_marketing_preferences()WhatsApp.on_template_status_update()WhatsApp.on_template_category_update()WhatsApp.on_template_quality_update()WhatsApp.on_template_components_update()WhatsApp.on_raw_update()WhatsApp.remove_callbacks()WhatsApp.load_handlers_modules()
- Handler Objects
WhatsApp.add_handlers()WhatsApp.add_flow_request_handler()WhatsApp.remove_handlers()MessageHandlerCallbackButtonHandlerCallbackSelectionHandlerFlowCompletionHandlerFlowRequestHandlerMessageStatusHandlerChatOpenedHandlerPhoneNumberChangeHandlerIdentityChangeHandlerCallConnectHandlerCallTerminateHandlerCallStatusHandlerCallPermissionUpdateHandlerUserMarketingPreferencesHandlerTemplateStatusUpdateHandlerTemplateCategoryUpdateHandlerTemplateQualityUpdateHandlerTemplateComponentsUpdateHandlerRawUpdateHandler
- Handler Decorators
- π₯ Listeners
- π¬ Updates
- Message
- Callback Button
- Callback Selection
- Flow Completion
- Message Status
- Chat Opened
- Phone Number Change
- Identity Change
- Call Connect
- Call Terminate
- Call Status
- Call Permission Update
- User Marketing Preferences
- Template Status Update
- Template Category Update
- Template Quality Update
- Template Components Update
- Common methods
BaseUpdateBaseUserUpdateBaseUserUpdate.reply_text()BaseUserUpdate.reply_image()BaseUserUpdate.reply_video()BaseUserUpdate.reply_audio()BaseUserUpdate.reply_document()BaseUserUpdate.reply_location()BaseUserUpdate.reply_location_request()BaseUserUpdate.reply_contact()BaseUserUpdate.reply_sticker()BaseUserUpdate.reply_template()BaseUserUpdate.reply_catalog()BaseUserUpdate.reply_product()BaseUserUpdate.reply_products()BaseUserUpdate.react()BaseUserUpdate.unreact()BaseUserUpdate.mark_as_read()BaseUserUpdate.indicate_typing()BaseUserUpdate.call()BaseUserUpdate.senderBaseUserUpdate.recipientBaseUserUpdate.block_sender()BaseUserUpdate.unblock_sender()BaseUserUpdate.message_id_to_reply
- β»οΈ Flows
- Creating Flow
- Sending Flow
- Handling Flow requests and responding to them
- Getting Flow Completion message
- Flow JSON
FlowJSONScreenScreenDataScreenDataUpdateLayoutLayoutTypeFormFormComponentTextHeadingTextSubheadingTextBodyTextCaptionRichTextFontWeightTextInputInputTypeTextAreaCheckboxGroupChipsSelectorRadioButtonsGroupMediaSizeFooterOptInDropdownEmbeddedLinkNavigationListNavigationItemNavigationItemStartNavigationItemMainContentNavigationItemEndDatePickerCalendarPickerCalendarPickerModeCalendarDayImageScaleTypePhotoPickerPhotoSourceDocumentPickerIfSwitchDataSourceDataExchangeActionNavigateActionCompleteActionUpdateDataActionOpenUrlActionNextNextTypeFlowStrScreenDataRefComponentRefConditionMathExpression
- Flow Types
FlowRequestFlowRequestActionTypeFlowResponseFlowCategoryFlowDetailsFlowStatusFlowPreviewFlowJSONUpdateResultFlowValidationErrorFlowAssetFlowMetricNameFlowMetricGranularityCreatedFlowMigrateFlowsResponseMigratedFlowMigratedFlowErrorFlowResponseErrorFlowTokenNoLongerValidFlowRequestSignatureAuthenticationFailedFlowRequestDecryptedMediaFlowRequestDecryptorFlowResponseEncryptordefault_flow_request_decryptor()default_flow_response_encryptor()flow_request_media_decryptor()FlowRequestCallbackWrapper
- Flow JSON
- π Templates
- Defining Template
- Template Components
- Creating Template
- Sending Template
- Media Templates
- Authentication Templates
- Library Templates
- Template Types
TemplateTemplateDetailsTemplateStatusTemplateRejectionReasonQualityScoreQualityScoreTypeLibraryTemplateTemplateCategoryTemplateSubCategoryTemplateLanguageParamFormatHeaderTextHeaderImageHeaderVideoHeaderDocumentHeaderLocationHeaderProductBodyTextDateTimeCurrencyFooterTextButtonsCopyCodeButtonFlowButtonFlowButtonIconPhoneNumberButtonVoiceCallButtonCallPermissionRequestButtonQuickReplyButtonURLButtonAppDeepLinkCatalogButtonMPMButtonSPMButtonOneTapOTPButtonZeroTapOTPButtonCopyCodeOTPButtonOTPSupportedAppLimitedTimeOfferCarouselCarouselCardAuthenticationBodyAuthenticationFooterTemplatesResultCreatedTemplateCreatedTemplatesUpdatedTemplateTemplateUnpauseResultTemplatesCompareResultTopBlockReasonTypeMigrateTemplatesResultMigratedTemplateMigratedTemplateErrorDegreesOfFreedomSpecCreativeFeaturesSpec
- Template Types
- π¬ Filters
- Combining Filters
- Custom Filters
- Built-in Filters
- Common filters
new()filters.messagefilters.callback_buttonfilters.callback_selectionfilters.message_statusfilters.flow_completionfilters.template_statusfilters.chat_openedfilters.call_connectfilters.call_terminatefilters.call_statusfilters.call_permission_updatefilters.phone_number_changefilters.identity_changesent_to()filters.sent_to_mefrom_users()from_countries()matches()contains()startswith()endswith()regex()
- Message Filters
filters.forwardedfilters.forwarded_many_timesfilters.replyreplays_to()filters.has_referred_productfilters.textfilters.is_commandcommand()filters.mediamimetypes()extensions()filters.has_captionfilters.imagefilters.videofilters.audiofilters.audio_onlyfilters.voicefilters.documentfilters.stickerfilters.animated_stickerfilters.static_stickerfilters.reactionfilters.reaction_addedfilters.reaction_removedreaction_emojis()filters.unsupportedfilters.locationfilters.current_locationlocation_in_radius()filters.contactsfilters.contacts_has_wafilters.order
- Message Status Filters
- Common filters
- β οΈ Errors
- Base Exception
WhatsAppError- Sending Messages Errors
SendMessageErrorMessageUndeliverableReEngagementMessageUnsupportedMessageTypeRecipientNotInAllowedListInvalidParameterMissingRequiredParameterMediaDownloadErrorMediaUploadErrorTemplateParamCountMismatchTemplateParamFormatMismatchTemplateNotExistsTemplateTextTooLongGenericErrorUnknownErrorAccessDeniedServiceUnavailableRecipientCannotBeSenderBusinessPaymentIssueIncorrectCertificateAccountInMaintenanceModeUserIsInExperimentGroup
- Flows Errors
- Authorization Errors
- Rate Limit Errors
- Integrity Errors
- Block Users Errors
- Calling Errors
- Base Exception
- βοΈ Types
- Media
- Keyboard
- Message Fields
- Others
SuccessResultResultPaginationWhatsAppBusinessAccountBusinessVerificationStatusMarketingMessagesLiteAPIStatusMarketingMessagesOnboardingStatusBusinessProfileBusinessPhoneNumberBusinessPhoneNumberSettingsStorageConfigurationConversationalAutomationQRCodeCommandCommerceSettingsIndustryWhatsAppBusinessAccountFacebookApplicationUsersBlockedResultUsersUnblockedResultBlockUserFailureVersionStopHandlingContinueHandlingCallbackURLScope
- π Calls
- Call Types
CallingSettingsCallingSettingsStatusCallIconVisibilityCallbackPermissionStatusSIPServerSIPStatusSTRPKeyExchangeProtocolCallHoursCallingSettingsStatusWeekDayMondayTuesdayWednesdayThursdayFridaySaturdaySundayHolidayScheduleCallPermissionsCallPermissionCallPermissionStatusCallPermissionActionCallPermissionActionLimit
- Call Types
- π‘ Examples
- π Changelog
- 3.0.0-rc.3 (2025-08-06)
- 3.0.0-rc.2 (2025-08-04)
- 3.0.0-rc.1 (2025-07-31)
- 2.11.0 (2025-06-17) Latest
- 2.10.0 (2025-05-14)
- 2.9.0 (2025-05-04)
- 2.8.0 (2025-04-27)
- 2.7.0 (2025-01-18)
- 2.6.0 (2025-01-11)
- 2.5.2 (2025-01-07)
- 2.5.1 (2025-01-02)
- 2.5.0 (2025-01-02)
- 2.4.0 (2024-12-14)
- 2.3.0 (2024-11-30)
- 2.2.0 (2024-11-29)
- 2.1.0 (2024-11-24)
- 2.0.5 (2024-11-10)
- 2.0.4 (2024-11-08)
- 2.0.3 (2024-11-02)
- 2.0.2 (2024-10-30)
- 2.0.1 (2024-10-30)
- 2.0.0 (2024-10-30)
- 1.26.0 (2024-09-22)
- 1.25.0 (2024-08-15)
- 1.24.0 (2024-07-26)
- 1.23.0 (2024-07-14)
- 1.22.0 (2024-06-16)
- 1.21.0 (2024-06-14)
- 1.20.2 (2024-06-02)
- 1.20.1 (2024-06-02)
- 1.20.0 (2024-06-02)
- 1.19.0-rc.3 (2024-05-23)
- 1.19.0-rc.2 (2024-05-17)
- 1.19.0-rc.1 (2024-05-08)
- 1.18.1 (2024-05-05)
- 1.18.0 (2024-05-02)
- 1.17.0 (2024-04-30)
- 1.16.2 (2024-02-15)
- 1.16.0 (2024-01-22)
- 1.15.0 (2024-01-14)
- 1.14.0 (2024-01-01)
- 1.13.0 (2023-12-22)
- 1.13.0-rc.6 (2023-12-20)
- 1.13.0-rc.5 (2023-12-18)
- 1.13.0-rc.4 (2023-12-16)
- 1.13.0-rc.3 (2023-12-15)
- 1.13.0-rc.2 (2023-12-14)
- 1.13.0-rc.1 (2023-12-14)
- 1.12.1 (2023-11-29)
- 1.12.0 (2023-11-20)
- 1.11.1 (2023-11-07)
- 1.11.0 (2023-11-01)
- 1.10.0 (2023-10-29)
- 1.9.0 (2023-10-25)
- 1.8.0 (2023-10-20)
- 1.7.3 (2023-10-18)
- 1.7.2 (2023-10-12)
- 1.7.1 (2023-10-12)
- 1.7.0 (2023-10-12)
- 1.6.0 (2023-10-11)
- 1.5.4 (2023-10-08)
- 1.5.3 (2023-10-03)
- 1.5.2 (2023-10-03)
- 1.5.1 (2023-10-02)
- 1.5.0 (2023-10-02)
- 1.4.1 (2023-09-12)
- 1.4.0 (2023-09-10)
- 1.3.0 (2023-09-06)
- 1.2.0 (2023-08-21)
- 1.1.0 (2023-08-20)
- 1.0.0 (2023-08-16)
- π€ Contributing
- Prerequisites
- Getting Started
- Code Standards
- Making Changes
- Communication
- License
- Project Structure
- π Migration
- Migration from 2.x to 3.x
- Migration from 1.x to 2.x