cd /blog
GET/blog/send-whatsapp-messages-python-2026—200OK
pythontutorialapi

How to Send WhatsApp Messages with Python (2026 Guide)

April 1, 2026|8 min read

Sending WhatsApp messages programmatically opens up powerful automation possibilities, from customer notifications to full chatbot flows. This guide shows you how to send WhatsApp messages using Python and the WSAPI REST API, with no per-message fees and no Meta Business verification required.

Prerequisites

  • Python 3.8+ installed
  • A WSAPI Cloud account (or self-hosted instance): start a free 14-day trial
  • Your API key and instance ID from the WSAPI dashboard
  • A WhatsApp account connected via QR code

Quick Start: Send a Text Message

The fastest way to send a WhatsApp message with Python is a single POST request using the requests library:

send_message.py
import requests

API_URL = "https://api.wsapi.chat"
HEADERS = {
    "x-api-key": "your-api-key",
    "x-instance-id": "your-instance-id",
    "Content-Type": "application/json"
}

response = requests.post(f"{API_URL}/messages/text", headers=HEADERS, json={
    "to": "1234567890",
    "text": "Hello from Python! 🐍"
})

print(response.json())

That's it: a working WhatsApp message in 10 lines of Python. The to field accepts a phone number in international format (no + prefix), and text is the message body.

Sending Different Message Types

WSAPI supports 8 media types beyond plain text. Here are the most common ones:

Images

send_image.py
requests.post(f"{API_URL}/messages/image", headers=HEADERS, json={
    "to": "1234567890",
    "url": "https://example.com/product.jpg",
    "caption": "Check out our new product!"
})

Documents

send_document.py
requests.post(f"{API_URL}/messages/document", headers=HEADERS, json={
    "to": "1234567890",
    "url": "https://example.com/invoice.pdf",
    "filename": "Invoice-2026-001.pdf",
    "caption": "Your invoice for March 2026"
})

Location

send_location.py
requests.post(f"{API_URL}/messages/location", headers=HEADERS, json={
    "to": "1234567890",
    "latitude": 37.7749,
    "longitude": -122.4194,
    "description": "Our San Francisco Office"
})

Receiving Messages with Webhooks

Sending messages is only half the story. To build interactive flows, you need to receive incoming messages via webhooks. Here's a minimal Flask receiver:

webhook_server.py
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/webhook", methods=["POST"])
def webhook():
    payload = request.json
    event = payload["event"]
    data = payload["data"]

    if event == "message" and not data.get("fromMe"):
        print(f"New message from {data['from']}: {data['body']}")

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

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

Or with FastAPI for async support:

webhook_fastapi.py
from fastapi import FastAPI, Request

app = FastAPI()

@app.post("/webhook")
async def webhook(request: Request):
    payload = await request.json()
    event = payload["event"]
    data = payload["data"]

    if event == "message" and not data.get("fromMe"):
        print(f"New message from {data['from']}: {data['body']}")

    return {"status": "ok"}

Building an Auto-Reply Bot

Combining sending and receiving, here's a complete auto-reply bot that responds to keywords:

auto_reply_bot.py
import requests
from fastapi import FastAPI, Request

app = FastAPI()

API_URL = "https://api.wsapi.chat"
HEADERS = {
    "x-api-key": "your-api-key",
    "x-instance-id": "your-instance-id",
    "Content-Type": "application/json"
}

REPLIES = {
    "pricing": "Check our plans at https://wsapi.chat/pricing",
    "help": "Available commands: pricing, docs, demo",
    "docs": "Read our docs at https://docs.wsapi.chat",
    "demo": "Schedule a demo at https://wsapi.chat/contact",
}

def send_reply(to: str, text: str):
    requests.post(f"{API_URL}/messages/text", headers=HEADERS, json={
        "to": to, "text": text
    })

@app.post("/webhook")
async def webhook(request: Request):
    payload = await request.json()

    if payload["event"] != "message":
        return {"status": "ok"}

    data = payload["data"]
    if data.get("fromMe"):
        return {"status": "ok"}

    body = data["body"].lower().strip()
    reply = REPLIES.get(body, "Type 'help' to see available commands.")
    send_reply(data["from"], reply)

    return {"status": "ok"}

Error Handling

Production code should handle API errors gracefully. WSAPI returns standard HTTP status codes with JSON error bodies:

error_handling.py
import requests

def send_message(to: str, text: str) -> dict:
    try:
        response = requests.post(
            f"{API_URL}/messages/text",
            headers=HEADERS,
            json={"to": to, "text": text},
            timeout=10
        )
        response.raise_for_status()
        return response.json()
    except requests.exceptions.Timeout:
        print("Request timed out, retrying...")
        return send_message(to, text)
    except requests.exceptions.HTTPError as e:
        error = e.response.json()
        print(f"API error {e.response.status_code}: {error.get('detail', 'Unknown')}")
        raise

Next Steps