How to Send WhatsApp Messages with Python (2026 Guide)
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:
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
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
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
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:
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:
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:
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:
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')}")
raiseNext Steps
- Build a full chatbot with conversation state and media responses
- Set up webhooks for real-time message processing
- The same walkthrough in Node.js, if that is where your integration lives
- Explore the Quickstart guide to connect your first WhatsApp account
- Read the Python SDK guide and the send-a-text-message reference for every parameter