· 4 min · TextMeFlow Team

Build a WhatsApp auto-reply bot in Python — Flask webhook tutorial

An auto-reply bot is the "hello world" of WhatsApp automation: someone messages your number, your code decides what to answer, and the reply arrives in their chat within seconds. This tutorial builds one in Python with Flask — around 60 lines, no Meta Business account, no template approval.

What you need

  • A TextMeFlow account with your WhatsApp number linked via QR (getting started guide)
  • Your API key and webhook secret from the portal
  • Python 3.10+ with flask and requests installed

Step 1 — receive incoming messages

TextMeFlow delivers every incoming message to your webhook URL as JSON, signed with HMAC-SHA256 so you can verify it genuinely came from us. The skeleton:

import hashlib
import hmac
import os

import requests
from flask import Flask, request, abort

app = Flask(__name__)

WEBHOOK_SECRET = os.environ["TMF_WEBHOOK_SECRET"]
API_KEY = os.environ["TMF_API_KEY"]
API_URL = "https://api.textmeflow.eu/v1/messages"


@app.post("/webhook")
def webhook():
    received = request.headers.get("X-TextMeFlow-Signature", "")
    expected = "sha256=" + hmac.new(
        WEBHOOK_SECRET.encode(), request.get_data(), hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(received, expected):
        abort(401)

    event = request.get_json()
    sender = event["from"]
    text = event.get("message", "").strip().lower()

    reply = make_reply(text)
    if reply:
        send_message(sender, reply)

    return {"ok": True}

The signature lives in the X-TextMeFlow-Signature header as sha256=<hex> — an HMAC-SHA256 digest of the raw request body. Always compute it over request.get_data() (the raw bytes, not re-encoded JSON) and compare with hmac.compare_digest (constant-time) before trusting the payload. The payload is TextMeBot-compatible (type, from, from_name, to, message, file); full details, including retry behaviour and idempotency, are in our webhook signature guide.

Step 2 — decide what to answer

Start with simple keyword routing. It's unglamorous and it works:

def make_reply(text: str) -> str | None:
    if text in ("hi", "hello", "hallo"):
        return "Hi! Reply OPENING for our hours, or PRICE for rates."
    if "opening" in text:
        return "We're open Mon-Fri 9:00-18:00, Sat 10:00-16:00."
    if "price" in text:
        return "A standard service is €95 incl. VAT. Reply BOOK to schedule."
    return None  # unknown input: stay silent, a human will follow up

Returning None for unrecognised input is deliberate. A bot that answers everything badly is worse than one that answers three things well and leaves the rest to a person.

Step 3 — send the reply

Sending is one POST request:

def send_message(to: str, text: str) -> None:
    resp = requests.post(
        API_URL,
        headers={"Authorization": f"Bearer {API_KEY}"},
        json={"to": to, "text": text},
        timeout=10,
    )
    resp.raise_for_status()

Note that replies count against your plan's monthly quota and the per-number rate limits (1 msg/sec) — for an auto-responder answering real customers, you'll stay far below both.

Step 4 — run it

export TMF_API_KEY=... TMF_WEBHOOK_SECRET=...
flask run --port 8000

Expose the port with a tunnel during development (ngrok or similar), set the tunnel URL as your webhook endpoint in the TextMeFlow portal, and message your own number. You should see the reply arrive within a second or two.

Two rules that keep your bot out of trouble

Respect STOP. TextMeFlow handles STOP keywords automatically at the API level — an opted-out recipient is blocked before your code even runs — but don't design flows that badger people into replying.

Never loop. If your bot can trigger on its own outgoing messages (group chats are a classic case), guard against replying to yourself. One boolean check saves you a very embarrassing infinite conversation.

Where to go from here

Swap the keyword table for an LLM call, connect a booking system, or forward unmatched messages to a human inbox — the webhook-in, POST-out structure stays identical. The free plan (50 messages/month, forever) is plenty for building and testing. Create your free account and have the bot answering in an afternoon.

Zelf WhatsApp-berichten versturen via API?

Gratis voor altijd tot 50 berichten/maand. QR scannen en binnen 5 minuten verstuur je je eerste bericht.

Gratis voor altijd