Limited Time: Start your 14-day free trial, no credit card required
Back to Blog
Tutorials

WhatsApp Python API Tutorial: Send Messages Programmatically in 2026

Walytic TeamApril 29, 20269 min read

Why Use Python to Send WhatsApp Messages?

Python is the go-to language for automation scripts, data pipelines, backend services, and scheduled jobs. Connecting WhatsApp to Python lets you:

  • Send transactional messages triggered by events in your app (new orders, payments, signups)
  • Automate reminders, notifications, and follow-ups without touching a dashboard
  • Build chatbots that respond to incoming WhatsApp messages in real time
  • Integrate WhatsApp into your existing Python workflows in minutes

The easiest way to use the WhatsApp Python API in 2026 is through a REST-based service. Since Python's `requests` library makes HTTP calls trivial, no SDK or special package is required — just standard Python and an API key.

How the WhatsApp REST API Works

Walytic uses linked device technology — the same system that powers WhatsApp Web and Desktop — to connect your existing WhatsApp number to a REST API. This is fundamentally different from the official WhatsApp Business API:

Walytic (Linked Device)Official WhatsApp Business API
Approval requiredNo — connect in 2 minutesYes — Meta review process
Per-message feesNone — flat $5/mo$0.005–$0.08 per conversation
Template approvalNot requiredRequired for outbound messages
Python integrationREST API, no SDKREST API via BSP
Setup timeUnder 5 minutesDays to weeks

Prerequisites

Before you start, you need:

  1. A Walytic account (14-day free trial, no credit card)
  2. Python 3.7+ installed
  3. The `requests` library: `pip install requests`
  4. Your WhatsApp number connected to Walytic (scan a QR code in-app)

Step 1: Connect Your WhatsApp Number and Get Your API Key

  1. Sign up at app.walytic.com
  2. Go to Devices → Add Device
  3. Open WhatsApp on your phone: Settings → Linked Devices → Link a Device
  4. Scan the QR code — your number is connected in under 60 seconds
  5. Go to Settings → API Keys → Generate New Key
  6. Copy your API key and Instance ID

Store credentials as environment variables — never hardcode them in source files:

bash
export WALYTIC_API_KEY="your_api_key_here"
export WALYTIC_INSTANCE_ID="your_instance_id_here"

Step 2: Send a Text Message with Python

Sending a WhatsApp message using the Python WhatsApp API takes only a few lines with the `requests` library:

python
import requests
import os

API_KEY = os.environ["WALYTIC_API_KEY"]
INSTANCE_ID = os.environ["WALYTIC_INSTANCE_ID"]
BASE_URL = "https://api.walytic.com/api"

def send_whatsapp_text(phone: str, message: str) -> dict:
    response = requests.post(
        f"{BASE_URL}/messages/send",
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        json={
            "instanceId": INSTANCE_ID,
            "to": phone,
            "type": "text",
            "text": {"body": message},
        },
        timeout=10,
    )
    response.raise_for_status()
    return response.json()

# Example
result = send_whatsapp_text("14155552671", "Hello from Python! 👋")
print(result)

The phone number must be in E.164 format without the `+` sign (e.g., `14155552671` for a US number).

Step 3: Send Media Messages

The WhatsApp API Python integration supports images, PDFs, videos, and audio files:

Send an Image

python
def send_whatsapp_image(phone: str, image_url: str, caption: str = "") -> dict:
    response = requests.post(
        f"{BASE_URL}/messages/send",
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        json={
            "instanceId": INSTANCE_ID,
            "to": phone,
            "type": "image",
            "image": {"url": image_url, "caption": caption},
        },
        timeout=15,
    )
    response.raise_for_status()
    return response.json()

# Send an order shipped notification with image
send_whatsapp_image(
    "14155552671",
    "https://yourstore.com/shipped-banner.jpg",
    "Your order #1234 has shipped! 📦 Expected delivery: Friday.",
)

Send a Document (PDF Invoice, Receipt)

python
def send_whatsapp_document(phone: str, doc_url: str, filename: str) -> dict:
    response = requests.post(
        f"{BASE_URL}/messages/send",
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        json={
            "instanceId": INSTANCE_ID,
            "to": phone,
            "type": "document",
            "document": {"url": doc_url, "filename": filename},
        },
        timeout=15,
    )
    response.raise_for_status()
    return response.json()

# Send an invoice PDF
send_whatsapp_document(
    "14155552671",
    "https://yourapp.com/invoices/INV-2026-001.pdf",
    "Invoice-2026-001.pdf",
)

Step 4: Send Bulk Messages

To send to a list of contacts, use the broadcast endpoint with a built-in delay to respect WhatsApp's fair-use limits:

python
def send_whatsapp_broadcast(phones: list[str], message: str, delay_seconds: int = 10) -> dict:
    response = requests.post(
        f"{BASE_URL}/messages/broadcast",
        headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
        json={
            "instanceId": INSTANCE_ID,
            "contacts": phones,
            "type": "text",
            "text": {"body": message},
            "options": {"delay": delay_seconds},
        },
        timeout=30,
    )
    response.raise_for_status()
    return response.json()

# Send a payment reminder to overdue accounts
overdue_phones = ["14155552671", "14155552672", "14155552673"]
send_whatsapp_broadcast(
    overdue_phones,
    "Hi! This is a reminder that your invoice is due today. Reply PAID to confirm payment.",
    delay_seconds=10,
)

Walytic's built-in throttling spaces out messages automatically — the `delay` parameter adds an additional buffer between sends.

Step 5: Check Message Delivery Status

Track whether a message was delivered and read:

python
def get_message_status(message_id: str) -> dict:
    response = requests.get(
        f"{BASE_URL}/messages/{message_id}/status",
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=10,
    )
    response.raise_for_status()
    return response.json()

status = get_message_status("MSG_ID_HERE")
print(status)
# {"status": "read", "deliveredAt": "2026-04-29T10:30:02Z", "readAt": "2026-04-29T10:31:15Z"}

Step 6: Receive Incoming Messages via Webhooks

To respond to incoming WhatsApp messages in Python, set up a Flask webhook endpoint:

python
from flask import Flask, request, jsonify
import hmac
import hashlib
import os

app = Flask(__name__)
WEBHOOK_SECRET = os.environ["WALYTIC_WEBHOOK_SECRET"]

@app.route("/webhook", methods=["POST"])
def handle_webhook():
    # Verify Walytic webhook signature
    signature = request.headers.get("X-Walytic-Signature", "")
    payload = request.get_data()
    expected = hmac.new(WEBHOOK_SECRET.encode(), payload, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(signature, expected):
        return jsonify({"error": "Invalid signature"}), 401

    data = request.json
    if data.get("event") == "message.received":
        phone = data["from"]
        body = data["body"].lower()

        if "help" in body:
            send_whatsapp_text(phone, "Hi! Reply 1 for support, 2 for sales, 3 for billing.")
        elif body == "1":
            send_whatsapp_text(phone, "Connecting you to our support team now...")

    return jsonify({"status": "ok"}), 200

if __name__ == "__main__":
    app.run(port=5000)

In your Walytic dashboard, go to Settings → Webhooks and enter your public URL (e.g., `https://yourdomain.com/webhook`). Webhooks are strongly preferred over polling for production systems — they're real-time, efficient, and don't consume extra API calls.

Error Handling for Production

Wrap API calls with proper error handling:

python
from requests.exceptions import Timeout, HTTPError, ConnectionError

def safe_send(phone: str, message: str) -> bool:
    try:
        result = send_whatsapp_text(phone, message)
        return result.get("status") == "sent"
    except Timeout:
        print(f"Timeout sending to {phone} — will retry later")
    except HTTPError as e:
        code = e.response.status_code
        if code == 429:
            print("Rate limited — add a delay between requests")
        elif code == 401:
            print("Invalid API key — check WALYTIC_API_KEY environment variable")
        elif code == 400:
            print(f"Bad request — check phone format: {e.response.json()}")
    except ConnectionError:
        print("Network error — check connectivity")
    return False

API Rate Limits

EndpointRate Limit
Send message60 requests/min
Broadcast10 requests/min
Get status120 requests/min

Common Python + WhatsApp Use Cases

Use CaseTriggerScript Type
Payment remindersOverdue invoice in DBCron job (every morning)
Order notificationsNew order webhookFlask endpoint
Appointment remindersCalendar eventScheduled task
Lead follow-upNew CRM contactEvent-driven
CI/CD alertsPipeline failureCLI script
Abandoned cartUser idle 30 minutesBackground worker

Start Using the WhatsApp Python API Today

Integrating WhatsApp with Python is straightforward: a few `requests` calls and you're sending messages in minutes. No SDK, no approval process, no per-message fees.

Start your free 14-day Walytic trial, connect your WhatsApp number with a QR code scan, and send your first Python-triggered message in under 5 minutes. Your plan starts at $5/mo flat — no surprises as your volume grows.

For the full REST API reference and more code examples, see the Walytic API documentation.

Ready to Automate WhatsApp?

Start sending bulk messages, automate follow-ups, and build chatbots, all with flat-rate pricing. No per-message fees.

Start Free 14-Day Trial