Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

To build a WhatsApp chatbot in Python, connect a WhatsApp Business Account to Meta’s Cloud API, expose an HTTPS webhook for incoming events, and use Python to send replies through the API. The basic bot below reads a text message and returns a deterministic response; it is a starting point, not a complete production service.

What you need before writing the bot

Meta’s WhatsApp Cloud API is the official WhatsApp Business Platform API. You need a Meta business portfolio, a WhatsApp Business Account (WABA), and a business phone number. These are platform prerequisites, not Python packages. Follow Meta’s Cloud API setup guide to create or select the assets and obtain the phone-number ID and access token used by your application.

You also need a public HTTPS endpoint to receive webhook notifications. A development server running only on your computer’s localhost cannot receive Meta’s requests directly. For local development, use a secure tunnel if you have one; for deployment, use an endpoint reachable over HTTPS with a valid certificate. Meta’s webhook documentation explains the callback setup and verification requirements.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose how to call the API

For a small tutorial bot, direct HTTPS requests from Python make the request and response flow visible. A third-party wrapper is another option: PyWa documents integrations with Flask and FastAPI. It is an abstraction over the platform, not an official Meta Python SDK. Choose a wrapper if its documented integration fits your application; otherwise, direct requests avoid adding a framework dependency.

Set up credentials and a Python project

Use Meta’s setup flow to obtain the phone-number ID and an access token. Meta’s WhatsApp Business Platform Postman collection notes that user access tokens expire after 24 hours; system-user tokens may be configured to last up to 60 days or permanently, depending on configuration. Check the current token settings for your account rather than treating any lifetime as universal. Keep tokens, app secrets, and webhook verification strings out of source code and public repositories. If a credential is exposed, revoke or rotate it through Meta’s account settings.

Create a virtual environment, then install Flask and Requests:

python -m venv .venv
# macOS or Linux:
source .venv/bin/activate
# Windows PowerShell:
.venvScriptsActivate.ps1
pip install Flask requests

Set the configuration as environment variables in your local shell or deployment environment. Use the current Graph API version shown in Meta’s documentation; the example deliberately reads it from configuration instead of freezing a version string in code.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
export WHATSAPP_TOKEN="your_access_token"
export PHONE_NUMBER_ID="your_phone_number_id"
export VERIFY_TOKEN="a_private_verification_string"
export GRAPH_API_VERSION="current_version_from_meta_docs"

On Windows PowerShell, set the same variables with $env:WHATSAPP_TOKEN="your_access_token", replacing the variable name as needed. Do not commit a real token or verification string to Git.

Create the webhook and reply handler

Meta uses a GET request to verify the callback URL and POST requests to deliver webhook notifications. Keep those responsibilities separate. The following Flask example verifies the callback, ignores status-only or unsupported events, extracts inbound text defensively, and sends one simple reply.

import os

import requests
from flask import Flask, request

app = Flask(__name__)

VERIFY_TOKEN = os.environ["VERIFY_TOKEN"]
WHATSAPP_TOKEN = os.environ["WHATSAPP_TOKEN"]
PHONE_NUMBER_ID = os.environ["PHONE_NUMBER_ID"]
GRAPH_API_VERSION = os.environ["GRAPH_API_VERSION"]


@app.get("/webhook")
def verify_webhook():
    mode = request.args.get("hub.mode")
    token = request.args.get("hub.verify_token")
    challenge = request.args.get("hub.challenge")

    if mode == "subscribe" and token == VERIFY_TOKEN and challenge:
        return challenge, 200
    return "Verification failed", 403


@app.post("/webhook")
def receive_webhook():
    payload = request.get_json(silent=True) or {}

    for entry in payload.get("entry", []):
        for change in entry.get("changes", []):
            value = change.get("value", {})
            for message in value.get("messages", []):
                if message.get("type") != "text":
                    continue

                sender = message.get("from")
                text = message.get("text", {}).get("body", "").strip()
                if sender and text:
                    reply_to_text(sender, text)

    return "EVENT_RECEIVED", 200


def reply_to_text(recipient, incoming_text):
    normalized = incoming_text.casefold()
    if normalized in {"hello", "hi", "hey"}:
        reply = "Hello! How can I help?"
    else:
        reply = "Thanks for your message. What would you like help with?"

    url = (
        f"https://graph.facebook.com/{GRAPH_API_VERSION}/"
        f"{PHONE_NUMBER_ID}/messages"
    )
    headers = {
        "Authorization": f"Bearer {WHATSAPP_TOKEN}",
        "Content-Type": "application/json",
    }
    body = {
        "messaging_product": "whatsapp",
        "to": recipient,
        "type": "text",
        "text": {"body": reply},
    }

    response = requests.post(url, headers=headers, json=body, timeout=15)
    response.raise_for_status()

Run the app locally with flask --app app run --port 5000 if the file is named app.py. Your webhook URL will use the public HTTPS address that forwards to this server, followed by /webhook. Do not treat the built-in Flask development server as a production deployment.

What the handler does—and does not—process

Webhook notifications contain nested account, change, messaging-product, metadata, and event data. An inbound text appears under a message object, while a status notification can report states such as sent, delivered, read, failed, or deleted. The loop above only processes text messages; it safely skips other message types and events with no messages. Consult Meta’s webhook components reference when expanding event handling.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The example sends the response during request handling to keep the tutorial short. A deployed bot should acknowledge webhook deliveries promptly and move slower work—such as external lookups or lengthy business logic—to a background queue. Design processing to tolerate duplicate deliveries, for example by recording processed message IDs; exact delivery and retry behavior can depend on the platform’s current implementation.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Configure and verify the webhook in Meta

  1. Make the callback reachable. Start the Flask app and expose its /webhook route at a public HTTPS URL with a valid certificate.
  2. Enter the callback details. In the Meta app’s WhatsApp webhook configuration, provide the callback URL and the same private verification string used for VERIFY_TOKEN.
  3. Complete verification. Meta sends a GET request with verification parameters. The app must return the challenge only when the mode and verification token match. A failed check commonly means the callback URL, token, route, or public reachability does not match.
  4. Subscribe to the WABA events. Subscribe the app to the WhatsApp Business Account and the message events your bot needs. Configuring the callback alone does not replace the WABA subscription.
  5. Send a test message. Check your server logs and confirm that the POST route receives the expected event. If no event arrives, recheck HTTPS reachability, the app’s WABA subscription, and the selected event fields.

Send messages through the Cloud API

The reply_to_text function posts to the messages endpoint associated with the phone-number ID. It authenticates with a bearer token and identifies WhatsApp as the messaging product. Meta’s current setup and API documentation should be used for the active Graph API version, endpoint details, and permissions; those can change, so the sample does not prescribe a permanent version number or permission list.

Understand the conversation-template rule

Under Meta’s WhatsApp Business Messaging Policy, a business may initiate a conversation only using an approved message template. A bot replying to a customer’s inbound message is different from a business-initiated message. If your product needs to contact a person first, create and use an approved template according to Meta’s current policy and API instructions.

Check pricing before launch

WhatsApp Business API fees follow Meta’s rate card and pricing rules, which Meta may update. Costs depend on the applicable current pricing terms; check the rate card for your market before estimating operating expenses rather than relying on an old static price.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Prepare the chatbot for real users

  • Handle more message types: provide an intentional fallback for images, buttons, interactive replies, and other unsupported content instead of silently assuming every inbound message is text.
  • Validate incoming data: check that the expected objects and fields exist, and avoid logging message contents or credentials unnecessarily.
  • Check API failures: catch request timeouts and HTTP errors, record useful diagnostic details without exposing secrets, and avoid retrying indefinitely.
  • Prevent duplicate work: persist inbound message IDs and make business actions idempotent so repeated webhook deliveries do not repeat an order or payment action.
  • Separate development from production: use a stable HTTPS deployment, managed secret storage, monitored logs, and an operational process for rotating tokens.
  • Revisit Meta’s documentation: confirm current endpoint versions, access settings, webhook fields, policy rules, and regional rates whenever you change or launch the integration.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.