Send a WhatsApp Message with Python
Send WhatsApp messages from Python with requests: text, images and documents, error handling and delivery status, in a few lines.
This tutorial shows how to send a WhatsApp message from Python with the popular requests library. You'll build a tiny client you can import anywhere — a script, a Django or Flask app, a cron job or a Jupyter notebook — and use it to send text, images and documents, and to check delivery status.
You need Python 3.8 or newer.
Before you start
You need three things from your InstaMessage dashboard. It takes about five minutes:
- A free account. Sign up here — no card needed.
- A connected instance. Create an instance and scan its QR code with WhatsApp on your phone (Settings → Linked devices → Link a device), until its status shows Connected.
-
Your
instance_idandaccess_token. On the instance's page, generate an API credential. The token is shown only once, so copy it somewhere safe straight away.
Keep both out of your code: store them as environment variables, so they never end up in Git. On macOS or Linux:
export INSTAMESSAGE_INSTANCE_ID="your-instance-id"
export INSTAMESSAGE_TOKEN="your-access-token"
On Windows (PowerShell):
$env:INSTAMESSAGE_INSTANCE_ID = "your-instance-id"
$env:INSTAMESSAGE_TOKEN = "your-access-token"
+, spaces or leading
0. For example
+91 98765 43210 becomes 919876543210.
Step 1: Install requests
pip install requests
Step 2: Write a small client
Save this as instamessage.py. It reads your credentials from the environment, adds your token to every
request, and raises a clear error if the API says no:
import os
import requests
API_URL = "https://instamessage.in/api/v1"
INSTANCE_ID = os.environ["INSTAMESSAGE_INSTANCE_ID"]
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {os.environ['INSTAMESSAGE_TOKEN']}",
"Accept": "application/json",
})
class InstaMessageError(Exception):
pass
def _check(response):
data = response.json() if response.content else {}
if response.status_code != 200 or not data.get("success"):
raise InstaMessageError(data.get("error") or f"Request failed with HTTP {response.status_code}")
return data
def send_message(to, message=None, **extra):
"""Send a WhatsApp message. Extra fields (type, media_url, file_name) are passed through."""
payload = {"instance_id": INSTANCE_ID, "to": to, **extra}
if message is not None:
payload["message"] = message
# A long timeout, because the API may download a media file first.
return _check(session.post(f"{API_URL}/messages/send", json=payload, timeout=60))
def get_message(message_id):
"""Look up a sent message, including its delivery status."""
return _check(session.get(f"{API_URL}/messages/{message_id}", timeout=30))["message"]
Step 3: Send your first text message
Create send.py and put your own WhatsApp number in to test it:
from instamessage import send_message
result = send_message("919876543210", "Hello from Python! ๐")
print("Sent! Message ID:", result["message_id"])
python send.py
The message arrives within a second or two. result is the API's reply as a dictionary, for example
{"success": True, "message_id": "3EB0A1B2C3D4E5F6", "sent_via": "device", "fallback_status": None}.
Step 4: Handle errors
Catch InstaMessageError for problems the API reports, and requests.RequestException for network trouble:
import requests
from instamessage import InstaMessageError, send_message
try:
send_message("919876543210", "Your appointment is confirmed for 10:30 tomorrow.")
except InstaMessageError as error:
print("The API refused the message:", error)
except requests.RequestException as error:
print("Could not reach the API:", error)
Common reasons a message is refused:
- HTTP 401 — the access token is missing, wrong or revoked.
- "Instance is not connected" — reconnect the instance from your dashboard.
- "instance_id does not match this token" — the token belongs to another instance.
- "You've reached your plan's monthly message limit" — time to upgrade, or wait for next month.
- HTTP 429 — more than 30 send requests in a minute; slow down and retry.
Step 5: Send an image or a document
Pass a type and a public media_url. The text becomes an optional caption:
from instamessage import send_message
# An image with a caption (JPG, PNG or WebP, up to 5 MB)
send_message(
"919876543210",
"Just in: our new collection",
type="image",
media_url="https://example.com/images/new-arrival.jpg",
)
# A PDF, with the file name the recipient will see
send_message(
"919876543210",
"Here is your invoice.",
type="document",
media_url="https://example.com/invoices/42.pdf",
file_name="Invoice-42.pdf",
)
Videos, audio files and voice notes work the same way. The media rules list every type and size limit.
Step 6: Check if it was delivered and read
from instamessage import get_message, send_message
result = send_message("919876543210", "Did you get this?")
message = get_message(result["message_id"])
print(message["status"]) # pending, sent, delivered, read or failed
read only shows up if the recipient has read receipts switched on. If you'd rather be notified than
check, set a webhook on your instance and you'll receive an event each time a message is delivered or read.
Protect your WhatsApp number
WhatsApp can restrict or ban a number that looks like it's sending spam. Only message people who expect to hear from you, keep your volume steady, and avoid sending the same text to large lists. Read the full do's and don'ts before you go live.
Next steps
- See every field, error and limit in the API documentation.
- Receive incoming messages with a webhook, and get delivery updates on your server.
- Compare plans and message limits.