### Install Dependencies Source: https://pywa.readthedocs.io/en/latest/content/contributing.html Set up a virtual environment and install the necessary development and documentation dependencies. ```bash python3 -m venv .venv source .venv/bin/activate pip install -e ".[dev]" # for docs changes: pip install -e ".[dev,docs]" ``` -------------------------------- ### Install Pywa from source Source: https://pywa.readthedocs.io/en/latest/content/getting-started.html Install the bleeding-edge version of pywa by cloning the repository and installing from source. ```bash git clone https://github.com/david-lev/pywa.git cd pywa && pip3 install -U . ``` -------------------------------- ### Install PyWa with All Features Source: https://pywa.readthedocs.io/en/latest/index.html Install PyWa with all available features, including the server and cryptography support. ```bash pip install -U "pywa[server,cryptography]" ``` -------------------------------- ### HeaderGIF Example Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Instantiate a HeaderGIF with an example URL and set the GIF parameter. ```python >>> header_gif = HeaderGIF(example="https://example.com/animation.gif") >>> header_gif.params(gif="https://cdn.com/animation.gif") ``` -------------------------------- ### HeaderDocument Example Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Instantiate a HeaderDocument with an example URL and set the document parameter. ```python >>> header_document = HeaderDocument(example="https://example.com/document.pdf") >>> header_document.params(document="https://cdn.com/document.pdf") ``` -------------------------------- ### Install Pywa with webhook support Source: https://pywa.readthedocs.io/en/latest/content/getting-started.html Install pywa with the 'server' extra to enable webhook features. ```bash pip3 install -U "pywa[server]" ``` -------------------------------- ### HeaderProduct Example Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Instantiate a HeaderProduct and set its parameters for catalog ID and SKU. ```python >>> header_product = HeaderProduct() >>> header_product.params(catalog_id="1234567890", sku="SKU12345") ``` -------------------------------- ### Start ngrok Tunnel for Callback URL Source: https://pywa.readthedocs.io/en/latest/content/handlers/overview.html Use `start_ngrok_tunnel` to create a public HTTPS callback URL for local development. Ensure the 'ngrok' package is installed. ```python from pywa import WhatsApp, filters, types, utils callback_url = utils.start_ngrok_tunnel( port=8000, auth_token="your-ngrok-auth-token", domain="subdomain.ngrok-free.app", ) wa = WhatsApp( phone_id="1234567890", token="EAA...", app_id="1234567890", app_secret="xxxx", callback_url=callback_url, verify_token="my-verify-token", ) @wa.on_message(filters.text) def echo(client: WhatsApp, msg: types.Message): msg.reply(msg.text) ``` -------------------------------- ### SPMButton Example Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Instantiate an SPMButton for single-product messages. Requires HeaderProduct for context. ```python >>> header_product = HeaderProduct() >>> spm_button = SPMButton(text="View Product") ``` -------------------------------- ### Install PyWa with Server Integration Source: https://pywa.readthedocs.io/en/latest/index.html Install the PyWa package with server integration capabilities using pip. ```bash pip install -U "pywa[server]" ``` -------------------------------- ### State Visibility Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html This example shows how to set the state visibility to false. ```json false ``` -------------------------------- ### Install Pywa Server Extras Source: https://pywa.readthedocs.io/en/latest/content/handlers/overview.html Install the necessary extras for running the pywa server. This command is run in the terminal. ```bash pip install "pywa[server]" ``` -------------------------------- ### Install Pywa using pip Source: https://pywa.readthedocs.io/en/latest/content/getting-started.html Install the pywa library using pip for general use. ```bash pip3 install -U pywa ``` -------------------------------- ### Install PyWa with Core Functionality Source: https://pywa.readthedocs.io/en/latest/index.html Use this command to install the core PyWa library for sending messages without a webhook server. ```bash pip install -U pywa ``` -------------------------------- ### Start Screen Definition Source: https://pywa.readthedocs.io/en/latest/content/examples/sign_up_flow.html Defines the static start screen with a welcome message and links for signing up or logging in. The payload for navigation actions includes initial values for form fields. ```python START = Screen( id='START', title='Home', layout=Layout( children=[ TextHeading( text='Welcome to our app', ), EmbeddedLink( text='Click here to sign up', on_click_action=Action( name=FlowActionType.NAVIGATE, next=Next( type=NextType.SCREEN, name='SIGN_UP', ), payload={ "first_name_initial_value": "", "last_name_initial_value": "", "email_initial_value": "", "password_initial_value": "", "confirm_password_initial_value": "", }, ), ), EmbeddedLink( text='Click here to login', on_click_action=Action( name=FlowActionType.NAVIGATE, next=Next( type=NextType.SCREEN, name='LOGIN', ), payload={ "email_initial_value": "", "password_initial_value": "", }, ), ), ] ), ) ``` -------------------------------- ### CatalogButton Example Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Instantiate a CatalogButton and set its thumbnail product SKU and display index. ```python >>> catalog_button = CatalogButton(text="View Products") >>> catalog_button.params(thumbnail_product_sku="SKU12345", index=0) ``` -------------------------------- ### Start Pywa Development Server Source: https://pywa.readthedocs.io/en/latest/index.html Commands to start the Pywa webhook server for local development or production deployment. ```shell pywa dev # Local development ``` ```shell pywa run # Production ``` -------------------------------- ### Example: Basic message command filter Source: https://pywa.readthedocs.io/en/latest/content/filters/account_update_filters.html Demonstrates how to use a simple text command filter to trigger a welcome message. This is a fundamental example for setting up message handlers. ```python >>> @wa.on_message(fil.text.command("start")) ... def on_hi_msg(_: WhatsApp, m: types.Message): ... print("This is a welcome message!") ``` -------------------------------- ### Navigation Item Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Demonstrates the structure of a NavigationItem with content, pricing, and navigation actions. ```python NavigationItem( id="dream", main_content=NavigationItemMainContent( title="Dream Loss Insurance", metadata="Protection from recurring nightmares or lost opportunities due to poor sleep", ), end=NavigationItemEnd( title="$540", description="/ month" ), on_click_action=NavigateAction( next=Next(name="FIFTH_SCREEN"), payload={"first_name": True}, ), ) ``` -------------------------------- ### Example Pincode Data Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html This example demonstrates the structure for pincode data, including its ID and title. ```json { "id": "M6B2A9", "title": "M6B2A9" } ``` -------------------------------- ### Document Picker Flow Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Shows how to create a document picker for users to attach files like contracts. This example requires imports for FlowJSON, Screen, Layout, Form, DocumentPicker, and specific allowed MIME types. ```Python from pywa.types.flows import * doc_picker = FlowJSON( version="4.0", routing_model={"SECOND": []}, data_api_version="3.0", screens=[ Screen( id="SECOND", terminal=True, title="Document Picker Example", data={}, layout=Layout( type=LayoutType.SINGLE_COLUMN, children=[ Form( name="flow_path", children=[ document_picker := DocumentPicker( name="document_picker", label="Contract", description="Attach the signed copy of the contract", min_uploaded_documents=1, max_uploaded_documents=1, max_file_size_kb=1024, allowed_mime_types=[ "image/jpeg", "application/pdf", ], ), ], ) ], ), ) ], ) ``` -------------------------------- ### Dynamic Handler Registration Example Source: https://pywa.readthedocs.io/en/latest/content/handlers/overview.html Shows how to dynamically add and remove handlers at runtime using `add_handlers()` and `remove_handlers()`. This example implements a maintenance mode that can be toggled by administrators. ```python from pywa import WhatsApp, filters, handlers, types wa = WhatsApp(...) admin_filter = filters.from_users("1234567890", "9876543210") # Define a high-priority handler callback that intercepts messages during maintenance def maintenance_callback(client: WhatsApp, msg: types.Message): msg.reply("🛠️ The bot is currently undergoing maintenance. Please try again later.") msg.stop_handling() # Prevent other, lower-priority handlers from running # Create the handler instance with high priority maintenance_handler = handlers.MessageHandler( callback=maintenance_callback, filters=~admin_filter, # Only non-admins priority=100, ) # Handler to turn maintenance mode ON or OFF @wa.on_message(filters.command("maintenance") & admin_filter) def enable_maintenance(client: WhatsApp, msg: types.Message): if msg.text.split("maintenance")[1].strip() == "on": client.add_handlers(maintenance_handler) msg.reply("Maintenance mode has been activated.") else: client.remove_handlers(maintenance_handler, silent=True) msg.reply("Maintenance mode has been deactivated.") ``` -------------------------------- ### Instantiate and Use HeaderVideo Component Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Creates a HeaderVideo component with an example URL and then fills its parameters with a specific video URL. ```python >>> header_video = HeaderVideo(example="https://example.com/video.mp4") >>> header_video.params(video="https://cdn.com/video.mp4") ``` -------------------------------- ### Create a NavigationList Source: https://pywa.readthedocs.io/en/latest/content/flows/flow_json.html Example of creating a NavigationList with multiple NavigationItems, each with rich content and click actions. Ensure on_click_action is defined. ```python >>> NavigationList( ... name='navigation_list', ... list_items=[ ... NavigationItem( ... id='1', ... main_content=NavigationItemMainContent(title='Title 1', description='Description 1'), ... start=NavigationItemStart(image='base64image...'), ... end=NavigationItemEnd(title="$100", description="/ month"), ... badge='New', ... on_click_action=NavigateAction(next=Next(name='SCREEN_1')) ... ), ... ... ... ], ... ) ``` -------------------------------- ### Initialize WhatsApp with Handlers Module Source: https://pywa.readthedocs.io/en/latest/content/client/client_reference.html Example of initializing the WhatsApp client and specifying a handlers module during instantiation. ```python 1from pywa import WhatsApp 2from . import my_handlers 3 4wa = WhatsApp(..., handlers_modules=[my_handlers]) ``` -------------------------------- ### HeaderLocation Example Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Instantiate a HeaderLocation and set its parameters for latitude, longitude, name, and address. ```python >>> header_location = HeaderLocation() >>> header_location.params(lat=37.7749, lon=-122.4194, name="San Francisco", address="California, USA") ``` -------------------------------- ### Install Pre-commit Hooks Source: https://pywa.readthedocs.io/en/latest/content/contributing.html Activate pre-commit to enforce code quality standards automatically. ```bash pre-commit install ``` -------------------------------- ### Text Input Component Example Source: https://pywa.readthedocs.io/en/latest/content/flows/flow_json.html Example of creating a TextArea component for multi-line text input. It includes name, label, required status, maximum length, and helper text. ```python >>> TextArea( ... name='description', ... label='Description', ... required=True, ... max_length=100, ... helper_text='Enter your description', ... ) ``` -------------------------------- ### Instantiate and Use HeaderImage Component Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Creates a HeaderImage component with an example URL and then fills its parameters with a specific image URL. ```python >>> header_image = HeaderImage(example="https://example.com/image.jpg") >>> header_image.params(image="https://cdn.com/image.jpg") ``` -------------------------------- ### preview Method Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Generates a preview of the template text with example values filled in. ```APIDOC ## preview Method ### Description Returns a preview of the template text with examples filled in. ### Parameters #### Positional Parameters * `override_positionals` – Positional arguments to override the example values (no need to provide all). #### Named Parameters * `override_named` – Named arguments to override the example values (no need to provide all). ### Return Type str ``` -------------------------------- ### Start ngrok Tunnel for Local Development Source: https://pywa.readthedocs.io/en/latest/content/types/others.html Starts an ngrok tunnel to expose your local server to the internet, enabling local webhook testing. Requires the ngrok package and an auth token. A static domain can be used to maintain a constant public URL. ```python >>> from pywa.utils import start_ngrok_tunnel >>> from pywa import WhatsApp >>> callback_url = start_ngrok_tunnel( ... auth_token="your_ngrok_auth_token", # https://dashboard.ngrok.com/get-started/your-authtoken ... domain="subdomain.ngrok-free.app", # https://dashboard.ngrok.com/domains ... ) >>> wa = WhatsApp(callback_url=callback_url, ...) # when using a static domain, you can comment out the callback_url parameter after the first run to avoid unnecessary webhook re-registration every time you restart the server. ``` -------------------------------- ### Handle Incoming Message for Reaction Source: https://pywa.readthedocs.io/en/latest/content/client/client_reference.html Example of how to set up a message handler to react to incoming messages using the `react()` method. ```python wa = WhatsApp() @wa.on_message def message_handler(_: WhatsApp, msg: Message): msg.react('👍') ``` -------------------------------- ### Responding to a Flow Request Source: https://pywa.readthedocs.io/en/latest/content/flows/flow_types.html Example of how to respond to a flow request by specifying a screen and data. This is useful for guiding the user through a flow. ```python >>> wa = WhatsApp(business_private_key="...", ...) >>> @wa.on_flow_request("/my-flow-endpoint") ... def my_flow_endpoint(_: WhatsApp, req: FlowRequest) -> FlowResponse: ... return req.respond( ... screen="SCREEN_ID", ... data={"key": "value"}, ... ) ``` -------------------------------- ### MPMButton Example with Product Sections Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Create an MPMButton and configure it with product sections, thumbnail SKU, and display index. Requires importing ProductsSection and Product. ```python >>> from pywa.types import ProductsSection, Product >>> mpm_button = MPMButton(text="View Products") >>> mpm_button.params( ... thumbnail_product_sku="SKU12345", ... index=0, ... product_sections=[ ... ProductsSection( ... title="Section 1", ... skus=["SKU12345", "SKU12346"], ... ), ... ProductsSection( ... title="Section 2", ... skus=["SKU12347", "SKU12348"], ... ), ... ], ... ) ``` -------------------------------- ### URL Uploader Bot Example Source: https://pywa.readthedocs.io/en/latest/content/examples/demo-bots.html A bot that uploads files from URLs provided in messages, using a filter to trigger on messages starting with 'http'. It also handles media download and upload errors, replying with a specific error message. Initialize the WhatsApp client with your credentials. ```python from pywa import WhatsApp, types, filters, errors wa = WhatsApp( phone_id='your_phone_number', token='your_token', verify_token='xyzxyz', ) @wa.on_message(filters.startswith('http')) def download(_: WhatsApp, msg: types.Message): msg.reply_document(msg.text, filename=msg.text.split('/')[-1]) # When a file fails to download/upload, the bot will reply with an error message. @wa.on_message_status(filters.failed_with(errors.MediaDownloadError, errors.MediaUploadError)) def on_media_download_error(_: WhatsApp, status: types.MessageStatus): status.reply(f"I can't download/upload this file: {status.error.details}") # Run the server with `pywa dev` ``` -------------------------------- ### Sign Up Form Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Demonstrates creating a sign-up screen with text input fields for first name, last name, and email. A 'Done' footer button is configured to complete the action with the collected data. ```python load_re_engagement = FlowJSON( version="2.1", screens=[ Screen( id="SIGN_UP", title="Finish Sign Up", terminal=True, data={}, layout=Layout( type=LayoutType.SINGLE_COLUMN, children=[ Form( name="form", children=[ first_name := TextInput( name="firstName", label="First Name", input_type=InputType.TEXT, required=True, visible=True, ), last_name := TextInput( name="lastName", label="Last Name", input_type=InputType.TEXT, required=True, visible=True, ), email := TextInput( name="email", label="Email Address", input_type=InputType.EMAIL, required=True, visible=True, ), Footer( label="Done", enabled=True, on_click_action=CompleteAction( payload={ "firstName": first_name.ref, "lastName": last_name.ref, "email": email.ref, }, ), ), ], ) ], ), ) ], ) ``` -------------------------------- ### Serve Documentation Locally Source: https://pywa.readthedocs.io/en/latest/content/contributing.html Run a local HTTP server to view the built documentation in your browser. ```bash python3 -m http.server 8000 -d docs/build/html ``` -------------------------------- ### If Flow Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Illustrates the use of the If component for conditional logic within a flow. This example requires the same imports as the Switch example. ```Python from pywa.types.flows import * if_ = FlowJSON( version="4.0", screens=[ Screen( id="SCREEN", title="Welcome", terminal=True, success=True, data=[value := ScreenData(key="value", example=True)], layout=Layout( children=[ animal := TextInput( name="animal", label="Animal", helper_text="Type: cat", ), If( condition=value.ref & (animal.ref == "cat"), then=[TextHeading(text="It is a cat")], else_=[TextHeading(text="It is not a cat")], ), Footer( label="Complete", on_click_action=CompleteAction(), ), ] ), ) ], ) ``` -------------------------------- ### WhatsApp Client Initialization with Full Parameters Source: https://pywa.readthedocs.io/en/latest/content/client/overview.html Demonstrates initializing the WhatsApp client with various parameters including phone ID, token, callback URL, and app credentials. Ensure all imports come from the same package (pywa or pywa_async) for optimal type checking. ```python from pywa import WhatsApp, filters, types, utils wa = WhatsApp( phone_id="1234567890", token="EAAJB...", callback_url=utils.start_ngrok_tunnel(...), verify_token="xyzxyz", app_id=1234567890, app_secret="41678a4f...", ) ``` -------------------------------- ### Create Marketing and Authentication Templates Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Demonstrates how to create marketing and authentication templates using the Template class. Includes examples of HeaderText, BodyText, FooterText, Buttons, QuickReplyButton, URLButton, OneTapOTPButton, and AuthenticationBody components. ```python from pywa.types.templates import * my_template = Template( name="my_template", language=TemplateLanguage.ENGLISH_US, category=TemplateCategory.MARKETING, components=[ HeaderText(text="Welcome to our service!"), BodyText(text="Hello {{name}}, thank you for joining us!", name="John"), FooterText(text="Best regards, The Team"), Buttons( buttons=[ QuickReplyButton(text="Get Started"), URLButton(text="Visit Website", url="https://website.com?ref={{1}}") ] ) ], parameter_format=ParamFormat.NAMED, ) auth_template = Template( name="auth_template", language=TemplateLanguage.ENGLISH_US, category=TemplateCategory.AUTHENTICATION, components=[ AuthenticationBody(add_security_recommendation=True), AuthenticationFooter(code_expiration_minutes=5), Buttons( buttons=[ OneTapOTPButton( text="Autofill Code", autofill_text="Autofill", supported_apps=[ OTPSupportedApp( package_name="com.example.myapp", signature_hash="12345678901" ) ] ), ] ) ], ) ``` -------------------------------- ### Question 1 Navigation Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html This snippet shows the navigation configuration for the first question, including how to pass selected values to the next step. ```json { "type": "Footer", "label": "Continue", "on-click-action": { "name": "navigate", "next": { "type": "screen", "name": "QUESTION_TWO" }, "payload": { "question1Checkbox": "${form.question1Checkbox}" } } } ``` -------------------------------- ### Screen Navigation Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Demonstrates setting up screen navigation with a footer button. The button navigates to the next screen and passes payload data. ```python Screen( id="QUESTION_TWO", title="Question 2 of 3", data=[ question1_checkbox := ScreenData( key="question1Checkbox", example=["Example", "Example2"] ), ], layout=Layout( type=LayoutType.SINGLE_COLUMN, children=[ Form( name="form", children=[ TextHeading( text="Its your birthday in two weeks, how might you prepare?" ), question2_radio_buttons := RadioButtonsGroup( name="question2RadioButtons", label="Choose all that apply:", required=True, data_source=[ DataSource(id="0", title="Buy something new"), DataSource(id="1", title="Wear the same, as usual"), DataSource(id="2", title="Look for a deal online"), ], ), Footer( label="Continue", on_click_action=NavigateAction( next=Next( type=NextType.SCREEN, name="QUESTION_THREE", ), payload={ "question2RadioButtons": question2_radio_buttons.ref, "question1Checkbox": question1_checkbox.ref, }, ), ), ], ) ], ), ), Screen( id="QUESTION_THREE", title="Question 3 of 3", data=[ question2_radio_buttons := ScreenData( key="question2RadioButtons", example="Example" ), question1_checkbox := ScreenData( key="question1Checkbox", example=["Example", "Example2"] ), ], terminal=True, layout=Layout( type=LayoutType.SINGLE_COLUMN, children=[ Form( name="form", children=[ TextHeading(text="What's the best gift for a friend?"), question3_checkbox := CheckboxGroup( name="question3Checkbox", label="Choose all that apply:", required=True, data_source=[ DataSource(id="0", title="A gift voucher"), DataSource(id="1", title="A new outfit "), DataSource(id="2", title="A bouquet of flowers"), DataSource(id="3", title="A meal out together"), ], ), Footer( label="Done", on_click_action=CompleteAction( payload={ "question1Checkbox": question1_checkbox.ref, }, ), ), ], ) ], ), ) ``` -------------------------------- ### Example State Data Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html This example shows the structure for state data, including its ID and title. ```json { "id": "1", "title": "USA" } ``` -------------------------------- ### Navigation and Data Display Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Demonstrates setting up a navigation list with insurance options. Each item includes a title, metadata, and an action to perform on click. ```python insurances := ScreenData( key="insurances", example=[ NavigationItem( id="home", main_content=NavigationItemMainContent( title="Home Insurance", metadata="Safeguard your home against natural disasters, theft, and accidents.", ), on_click_action=DataExchangeAction( payload={"selection": "home"}, ), ), NavigationItem( id="health", main_content=NavigationItemMainContent( title="Health Insurance", metadata="Get essential coverage for doctor visits, prescriptions, and hospital stays.", ), on_click_action=DataExchangeAction( payload={"selection": "health"}, ), ), ], ), ], layout=Layout( type=LayoutType.SINGLE_COLUMN, children=[ NavigationList( name="insurances", list_items=insurances.ref, ) ], ), ) ``` -------------------------------- ### Opt-In Component Example Source: https://pywa.readthedocs.io/en/latest/content/flows/flow_json.html Demonstrates how to create an OptIn component with a name, label, and required status. The init_value is set to True. ```python >>> OptIn( ... name='opt_in', ... label='I agree to the terms and conditions', ... required=True, ... init_value=True ... ) ``` -------------------------------- ### Install ngrok Package Source: https://pywa.readthedocs.io/en/latest/content/handlers/overview.html Install the 'ngrok' Python package using pip before using the `start_ngrok_tunnel` helper function. ```bash pip install ngrok ``` -------------------------------- ### Build Documentation Locally Source: https://pywa.readthedocs.io/en/latest/content/contributing.html Build the project documentation locally to preview changes before committing. ```bash make -C docs html ``` -------------------------------- ### Install Pywa with cryptography support Source: https://pywa.readthedocs.io/en/latest/content/getting-started.html Install pywa with the 'cryptography' extra for Flow features, including default encryption and decryption. ```bash pip3 install -U "pywa[cryptography]" ``` -------------------------------- ### Example Handler Module Source: https://pywa.readthedocs.io/en/latest/content/client/client_reference.html An example of a Python module defining message and callback button handlers using pywa decorators. ```python 1from pywa import WhatsApp, types, filters as fil 2 3@WhatsApp.on_message(fil.text) 4def on_text_message(wa: WhatsApp, msg: types.Message): 5 ... 6 7@WhatsApp.on_callback_button 8def on_callback_button(wa: WhatsApp, msg: types.CallbackButton): 9 ... ``` -------------------------------- ### Install Pywa Cryptography Dependency Source: https://pywa.readthedocs.io/en/latest/content/flows/overview.html Install the necessary dependencies for pywa to handle encryption and decryption for dynamic flows. The cryptography library is required. ```bash pip3 install "pywa[cryptography]" ``` -------------------------------- ### Configure Data Sources with Actions Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Demonstrates how to configure data sources with select and unselect actions, including nested data sources and visibility updates. ```python DataSource( id="california", title="California", on_unselect_action=UpdateDataAction( payload=[ pincode_visibility.update( new_value=False ) ], ), on_select_action=UpdateDataAction( payload=[ pincode.update( new_value=[ DataSource( id="90019", title="90019", ), DataSource( id="93504", title="93504", ), ] ), pincode_visibility.update( new_value=True ), ], ), ) ), ``` ```python DataSource( id="2", title="Canada", on_select_action=UpdateDataAction( payload=[ states.update( new_value=[ DataSource( id="ontario", title="Ontario", on_unselect_action=UpdateDataAction( payload=[ pincode_visibility.update( new_value=False ) ], ), ) ], ) ], ), ), ``` -------------------------------- ### Filter for 'start' command Source: https://pywa.readthedocs.io/en/latest/content/filters/message_filters.html Use the text command filter to trigger a handler when a message contains the 'start' command. This is commonly used for welcome messages. ```python @wa.on_message(fil.text.command("start")) def on_hi_msg(_: WhatsApp, m: types.Message): print("This is a welcome message!") ``` -------------------------------- ### Handle Sign-in, Sign-up, and Password Reset Flows Source: https://pywa.readthedocs.io/en/latest/content/flows/overview.html This comprehensive example demonstrates how to handle user authentication flows, including sign-in, sign-up, and password reset. It utilizes Pywa's flow request decorators to manage different stages of the user interaction. ```python import datetime import re import dataclasses from pywa import WhatsApp from pywa.types import FlowRequest, FlowResponse @dataclasses.dataclass class User: email: str password: str first_name: str last_name: str offer_acceptance: bool forget_password_requested: datetime.datetime | None = None is_signed_in: bool = False class DemoDatabase: def __init__(self): self.users: dict[str, User] = {} def get_user(self, email: str) -> User | None: return self.users.get(email) def add_user(self, user: User) -> None: self.users[user.email] = user def is_forget_password_available(self, email: str) -> bool: user = self.get_user(email) if not user: return True if user.forget_password_requested and user.forget_password_requested > (datetime.datetime.now() - datetime.timedelta(hours=24)): return False return True db = DemoDatabase() wa = WhatsApp( ..., business_private_key=open("private.pem").read(), # provide your business private key ) @wa.on_flow_request(endpoint="/signin") def handle_signin_flow(_: WhatsApp, req: FlowRequest) -> FlowResponse: raise NotImplementedError(req) @handle_signin_flow.on_init def on_init(_: WhatsApp, req: FlowRequest) -> FlowResponse: return req.respond( screen=signin_screen, data={ welcome.key: "Welcome to our service! Please sign in to continue.", default_email.key: "", }, ) @handle_signin_flow.on_data_exchange(screen=signin_screen) def on_sign_in(_: WhatsApp, req: FlowRequest) -> FlowResponse: user = db.get_user(req.data["email"]) if not user: return req.respond( screen=signin_screen, error_message="User not found. Please sign up first.", data={ welcome.key: "Welcome to our service! Please sign in to continue.", default_email.key: "", }, ) if user.password != req.data["password"]: return req.respond( screen=signin_screen, error_message="Incorrect password. Please try again.", data={ welcome.key: "Welcome to our service! Please sign in to continue.", default_email.key: user.email, }, ) user.is_signed_in = True return req.respond(close_flow=True) @handle_signin_flow.on_data_exchange(screen=signup_screen) def on_sign_up(_: WhatsApp, req: FlowRequest) -> FlowResponse: if not re.match(r"^(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$", req.data["password"]): return req.respond( screen=signup_screen, error_message="Password must be at least 8 characters long and contain at least one number and one special character.", ) if req.data["password"] != req.data["confirm_password"]: return req.respond( screen=signup_screen, error_message="Passwords do not match. Please try again.", ) user = User( email=req.data["email"], password=req.data["password"], first_name=req.data["first_name"], last_name=req.data["last_name"], offer_acceptance=req.data["offers_acceptance"], is_signed_in=False ) db.add_user(user) return req.respond( screen=signin_screen, data={ welcome.key: "Thank you for signing up! You can now sign in with your new account.", default_email.key: user.email, }, ) @handle_signin_flow.on_data_exchange(screen=forgot_password_screen) def on_forgot_password(_: WhatsApp, req: FlowRequest) -> FlowResponse: if not db.is_forget_password_available(req.data["email"]): return req.respond( screen=forgot_password_screen, error_message="You can't request a password reset at this time. Please try again later.", ) ### SEND PASSWORD RESET EMAIL HERE ### return req.respond( screen=signin_screen, data={ welcome.key: "A password reset link has been sent to your email address. Please check your inbox.", default_email.key: req.data["email"], }, ) ``` -------------------------------- ### Get Media File as Bytes Source: https://pywa.readthedocs.io/en/latest/content/client/client_reference.html Get media file as bytes directly from WhatsApp servers. Use this when you need the entire media content in memory. ```python >>> wa = WhatsApp() >>> media_bytes = wa.get_media_bytes( ... url='https://mmg-fna.whatsapp.net/d/f/Amc.../v2/1234567890', ... ) ``` -------------------------------- ### Open URL Example Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Demonstrates how to open an external URL using the 'open_url' action. This can be used for links, opt-in agreements, or other external resources. ```json { "version": "6.0", "screens": [ { "id": "DEMO_SCREEN", "terminal": true, "title": "Demo screen", "layout": { "type": "SingleColumnLayout", "children": [ { "type": "EmbeddedLink", "text": "This is an external link.", "on-click-action": { "name": "open_url", "url": "https://pywa.readthedocs.io/" } }, { "type": "OptIn", "label": "I agree to the terms.", "name": "T&Cs", "on-click-action": { "name": "open_url", "url": "https://pywa.readthedocs.io/" } }, { "type": "Footer", "label": "Footer", "on-click-action": { "name": "complete", "payload": {} } } ] } } ] } ``` -------------------------------- ### Replace ChatOpened Entry Points Source: https://pywa.readthedocs.io/en/latest/content/migration.html Replace the `@wa.on_chat_opened` decorator with `@wa.on_message(filters.command("start"))` for starting conversations and `@wa.on_callback_button` for handling button interactions. ```python ########################## OLD CODE ########################## from pywa import WhatsApp, types wa = WhatsApp(...) @wa.on_chat_opened def opened_chat(_: WhatsApp, update: types.ChatOpened): wa.send_message(to=update.from_user.wa_id, text="Welcome!") ########################## NEW CODE ########################## from pywa import WhatsApp, filters, types wa = WhatsApp(...) @wa.on_message(filters.command("start")) def start(_: WhatsApp, msg: types.Message): msg.reply("Welcome!") @wa.on_callback_button(filters.matches("start")) def start_clicked(_: WhatsApp, clb: types.CallbackButton): clb.reply_text("Welcome!") ``` -------------------------------- ### Screen Example Source: https://pywa.readthedocs.io/en/latest/content/flows/flow_json.html Demonstrates how to create a Screen object for a WhatsApp flow. This includes setting an ID, title, data, terminal state, layout, and refresh behavior on back navigation. ```python >>> Screen( ... id='START', ... title='Welcome', ... data=[ScreenData(key='welcome', example='Welcome to my store!')], ... terminal=True, ... layout=Layout(children=[Form(children=[...])]), ... refresh_on_back=True ... ) ``` -------------------------------- ### Initialize WhatsApp Client Source: https://pywa.readthedocs.io/en/latest/content/updates/raw_update.html Initialize the WhatsApp client with your credentials. ```python >>> wa = WhatsApp(...) ``` -------------------------------- ### Initialize WhatsApp and Handle Image Messages Source: https://pywa.readthedocs.io/en/latest/content/updates/message.html This snippet shows how to initialize the WhatsApp client and set up a handler for incoming image messages. It demonstrates downloading the media of a received image to a specified path and filename. ```python >>> from pywa import WhatsApp, types, filters >>> wa = WhatsApp(...) >>> @wa.on_message(filters.image) ... def on_message(_: WhatsApp, msg: types.Message): ... msg.download_media(path=pathlib.Path('/path/to/save'), filename='my_image.jpg') ``` -------------------------------- ### Get Media URL Source: https://pywa.readthedocs.io/en/latest/content/client/client_reference.html Get a media URL for a given media ID. Note that the URL is valid for 5 minutes and requires an access token for actual media retrieval. ```python >>> wa = WhatsApp() >>> wa.get_media_url(media_id='wamid.XXX=') ``` -------------------------------- ### Get a Quote Flow Definition Source: https://pywa.readthedocs.io/en/latest/content/examples/flows.html Defines a 'Get a Quote' flow with versioning and data API details. It specifies routing between different stages like DETAILS, COVER, QUOTE, and TERMS_AND_CONDITIONS. ```python get_a_quote = FlowJSON( version="2.1", data_api_version="3.0", data_channel_uri="https://example.com", routing_model={ "DETAILS": ["COVER"], "COVER": ["QUOTE"], "QUOTE": ["TERMS_AND_CONDITIONS"], "TERMS_AND_CONDITIONS": [], }, screens=[ Screen( id="DETAILS", title="Your details", data=[ city := ScreenData( key="city", example=[DataSource(id="1", title="Light City, SO")] ), ], layout=Layout( type=LayoutType.SINGLE_COLUMN, children=[ Form( name="details_form", children=[ name := TextInput( label="Your name", input_type=InputType.TEXT, name="name", required=True, ), address := TextInput( ``` -------------------------------- ### Decrypt Media from Flow Request Source: https://pywa.readthedocs.io/en/latest/content/flows/flow_types.html Decrypt encrypted media data received in a flow request. The `FlowRequest.decrypt_media()` method is the recommended way to handle this. Ensure cryptography is installed (`pip3 install ‘pywa[cryptography]’`). ```python from pywa import WhatsApp, types wa = WhatsApp(...) @wa.on_flow_request("/media-upload") def on_media_upload_request(_: WhatsApp, req: types.FlowRequest) -> types.FlowResponse | None: dec = req.decrypt_media(key="driver_license", index=0) with open(dec.filename, "wb") as file: file.write(dec.data) return req.respond(...) ``` -------------------------------- ### Run Webhooks with Built-in Server Source: https://pywa.readthedocs.io/en/latest/content/migration.html Replace external frameworks like FastAPI or Flask with Pywa's built-in server for hosting webhooks. This example shows setting up ngrok and initializing WhatsApp. ```python from pywa import WhatsApp, filters, types, utils callback_url = utils.start_ngrok_tunnel( auth_token="NGROK_AUTH_TOKEN", domain="your-domain.ngrok-free.app", ) wa = WhatsApp( phone_id="1234567890", token="EAA...", app_id="1234567890", app_secret="********", callback_url=callback_url, verify_token="my-verify-token", ) @wa.on_message(filters.text) def echo(_: WhatsApp, msg: types.Message): msg.reply(msg.text) ``` -------------------------------- ### Run WhatsApp Server Source: https://pywa.readthedocs.io/en/latest/content/client/client_reference.html Starts a basic, blocking server for quick prototyping and testing. For advanced features like hot-reloading and cloud deployments, use the pywa CLI. ```python WhatsApp.run(_*_ , _host ='127.0.0.1'_, _port =8000_) ``` -------------------------------- ### ArrivedMedia.extension Source: https://pywa.readthedocs.io/en/latest/content/types/media.html Gets the file extension of the arrived media. ```APIDOC ## ArrivedMedia.extension ### Description Gets the file extension of the arrived media. ### Property extension: str ``` -------------------------------- ### Media.days_until_expiration Source: https://pywa.readthedocs.io/en/latest/content/types/media.html Gets the number of days remaining until the media expires. ```APIDOC ## Media.days_until_expiration ### Description Gets the number of days remaining until the media expires. ### Property days_until_expiration: int ``` -------------------------------- ### TextSubheading Component Source: https://pywa.readthedocs.io/en/latest/content/flows/flow_json.html Example of creating a TextSubheading component with text and visibility. ```python >>> TextSubheading(text='Subheading', visible=True) ``` -------------------------------- ### BodyText Preview Source: https://pywa.readthedocs.io/en/latest/content/templates/types.html Demonstrates how to get a preview of the body text content. ```python print(body_text.preview()) ``` -------------------------------- ### MediaURL.minutes_until_expiration Source: https://pywa.readthedocs.io/en/latest/content/types/media.html Gets the number of minutes remaining until the media URL expires. ```APIDOC ## MediaURL.minutes_until_expiration ### Description Gets the number of minutes remaining until the media URL expires. ### Property minutes_until_expiration: int ``` -------------------------------- ### Initialize WhatsApp Client Source: https://pywa.readthedocs.io/en/latest/content/flows/flow_types.html Instantiate the WhatsApp client. This is a prerequisite for using flow decorators. ```python >>> wa = WhatsApp(...) ``` -------------------------------- ### WhatsApp.update_qr_code() Source: https://pywa.readthedocs.io/en/latest/content/client/client_reference.html Updates an existing QR code, for example, to change the pre-filled message. ```APIDOC ## WhatsApp.update_qr_code() ### Description Updates an existing QR code. ### Method PATCH ### Endpoint /v1/qr_codes/{qr_code_id} ### Parameters #### Path Parameters - **qr_code_id** (string) - Required - The ID of the QR code. #### Request Body - **message** (string) - Optional - The new pre-filled message. ``` -------------------------------- ### Create a Sign-Up Flow Source: https://pywa.readthedocs.io/en/latest/content/examples/sign_up_flow.html Use `create_flow()` to initiate a new flow with specified name and categories. Ensure you have initialized the WhatsApp object with your credentials. ```python from pywa import WhatsApp from pywa.types.flows import FlowCategory wa = WhatsApp( phone_id="1234567890", token="abcdefg", waba_id="1234567890", # the ID of the WhatsApp Business Account ) flow_id = wa.create_flow( name="Sign Up Flow", categories=[FlowCategory.SIGN_IN, FlowCategory.SIGN_UP], ) ``` -------------------------------- ### start_ngrok_tunnel Source: https://pywa.readthedocs.io/en/latest/content/types/others.html Starts an ngrok tunnel. This is a utility function for development and testing purposes. ```APIDOC ## start_ngrok_tunnel() ### Description Starts an ngrok tunnel. This is a utility function for development and testing purposes. ```