WhatsApp Python API Tutorial: Send Messages Programmatically in 2026
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 required | No — connect in 2 minutes | Yes — Meta review process |
| Per-message fees | None — flat $5/mo | $0.005–$0.08 per conversation |
| Template approval | Not required | Required for outbound messages |
| Python integration | REST API, no SDK | REST API via BSP |
| Setup time | Under 5 minutes | Days to weeks |
Prerequisites
Before you start, you need:
- A Walytic account (14-day free trial, no credit card)
- Python 3.7+ installed
- The `requests` library: `pip install requests`
- Your WhatsApp number connected to Walytic (scan a QR code in-app)
Step 1: Connect Your WhatsApp Number and Get Your API Key
- Sign up at app.walytic.com
- Go to Devices → Add Device
- Open WhatsApp on your phone: Settings → Linked Devices → Link a Device
- Scan the QR code — your number is connected in under 60 seconds
- Go to Settings → API Keys → Generate New Key
- Copy your API key and Instance ID
Store credentials as environment variables — never hardcode them in source files:
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:
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
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)
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:
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:
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:
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:
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 FalseAPI Rate Limits
| Endpoint | Rate Limit |
|---|---|
| Send message | 60 requests/min |
| Broadcast | 10 requests/min |
| Get status | 120 requests/min |
Common Python + WhatsApp Use Cases
| Use Case | Trigger | Script Type |
|---|---|---|
| Payment reminders | Overdue invoice in DB | Cron job (every morning) |
| Order notifications | New order webhook | Flask endpoint |
| Appointment reminders | Calendar event | Scheduled task |
| Lead follow-up | New CRM contact | Event-driven |
| CI/CD alerts | Pipeline failure | CLI script |
| Abandoned cart | User idle 30 minutes | Background 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