Order confirmations, appointment reminders, payment alerts, login codes: if your app sends it by email or SMS today, your customers would probably rather get it on WhatsApp. The catch is the setup. The official route means a Meta developer app, business verification and pre-approved templates before you send a single message.
This guide skips that. You'll send WhatsApp messages via API from your own number, with copy-ready examples in cURL, Python and Node.js. You'll send plain text, attach images and PDFs, and send to a list. Every example uses SyncMate by Assistro, so there's no BSP verification and no template approval.
Two Ways to Send WhatsApp Messages via API
There are two main routes, and the right one depends on what you're sending and who you're sending it to.
The official WhatsApp Cloud API
Meta's Cloud API is the official route. To use it you need a Meta developer app, a business portfolio, a phone number ID and a long-lived system-user access token. Then two rules shape everything you send:
- The 24-hour window. You can send free-form messages only within 24 hours of the customer's last message to you. Outside that window, you can only send pre-approved message templates.
- Per-message pricing. Since 1 July 2025, Meta charges for each delivered message. Each number gets 1,000 free service messages a month, and from 1 October 2026 utility messages sent inside the window are billable too. See the official WhatsApp API pricing breakdown for current rates.
The official API is the right choice when you need the verified business badge, very high volumes, or interactive buttons and lists.
SyncMate: an API for your own number
SyncMate connects your existing WhatsApp or WhatsApp Business number when you scan a QR code. Your app then sends through SyncMate's API, and messages go out from your number like any other chat. This is WhatsApp API without BSP verification.
Official Cloud API
SyncMate
Setup
Meta developer app, business portfolio, verification
Scan a QR code
Sender
A number registered to the Cloud API
Your existing WhatsApp or WhatsApp Business number
First message to a customer
Approved template only
Any text you like
Message cost
Meta per-message rates
Included in your SyncMate plan
Groups
Groups API: up to 8 people per group
Any group your number can post in
Verified business badge
Yes
No
SyncMate can also connect a Meta Cloud API number, so you can start with your own number and move to the official API later without rewriting your app.
Before You Start
You need four things:
- A SyncMate account. You can start free with 450 messages a month. See SyncMate pricing for paid plans.
- Your WhatsApp number connected. Follow the guide to connect your WhatsApp number. For API use, choose the cloud-based Assistro Standard connection so sending doesn't depend on a browser staying open.
- An API token. Here's how to get your API key or access token. Save it as an environment variable named SYNCMATE_API_TOKEN. Never paste it into code you commit.
- Recipient numbers in international format. Country code first, digits only, no +, spaces or leading zero. An Indian number is 919876543210; a UK number is 447700900123.
Prefer clicking through the dashboard first? Follow the guide to connect a custom app to the WhatsApp API, or watch the custom application video tutorial.
The Request Format
SyncMate's API is small. There are two endpoints, and both take the same JSON body.
Endpoint
Use it for
POST https://app.assistro.co/api/v1/whatsapp/messages/text
A text message to a person or a group
POST https://app.assistro.co/api/v1/whatsapp/messages/media
An image, video, audio file or document from a public link
Every request carries three headers: Authorization: Bearer YOUR_API_TOKEN, Integration: custom and Content-Type: application/json. A text message looks like this:
{ "to": "919876543210", "text": "Hi Priya, your order #1042 has shipped." }
Field
What it is
to
A group ID (ends in @g.us), or a person's number with country code, digits only (919876543210).
text
The text to send. Write line breaks as \n.
mentions
Optional. Numbers to tag in a group; also write @ and the number in text.
quoted
Optional. A message to reply to, as {key, text}.
kind (media)
image, video, audio or document
media (media)
{url, mime_type, file_name}: a public link to the file
caption (media)
Optional text shown under the file
Send a WhatsApp Message with cURL
cURL is the fastest way to check that your token and number work. Run this in your terminal:
curl -X POST "https://app.assistro.co/api/v1/whatsapp/messages/text" \ -H "Authorization: Bearer $SYNCMATE_API_TOKEN" \ -H "Integration: custom" \ -H "Content-Type: application/json" \ -d '{"to":"919876543210","text":"Hello from cURL"}'
If the message arrives on the phone, your setup is done. A successful call returns the sent message's key, which you can store to reply to, edit or delete that message later:
{ "success": true, "status": 1, "data": { "success": true, "data": { "key": { "remoteJid": "[email protected]", "fromMe": true, "id": "3EB0C4F1A2B3C4D5E6F7" }, "messageTimestamp": 1761800000 } } }
Everything below is the same request written in other languages. The WhatsApp API for developers page has every endpoint with samples in eight languages, and lets you try them with your own token.
Send a PDF or image with cURL
Files are sent by link: host the file somewhere public (your server, S3 or a CDN) and pass its URL:
curl -X POST "https://app.assistro.co/api/v1/whatsapp/messages/media" \ -H "Authorization: Bearer $SYNCMATE_API_TOKEN" \ -H "Integration: custom" \ -H "Content-Type: application/json" \ -d '{"to":"919876543210","kind":"document","media":{"url":"https://example.com/invoices/1042.pdf","mime_type":"application/pdf","file_name":"invoice.pdf"},"caption":"Your invoice is attached."}'
Keep the extension in file_name so WhatsApp shows the right preview. Media sends can take up to a minute. File size limits depend on your plan; current plans allow 2 MB to 8 MB per file.
Send a WhatsApp Message with Python
Install requests with pip install requests, then use this module. It handles text, files and sending to a list:
import os import requests BASE_URL = "https://app.assistro.co/api/v1/whatsapp/messages" HEADERS = { "Authorization": f"Bearer {os.environ['SYNCMATE_API_TOKEN']}", "Integration": "custom", } def post(endpoint, payload, timeout=30): response = requests.post(f"{BASE_URL}/{endpoint}", json=payload, headers=HEADERS, timeout=timeout) response.raise_for_status() return response.json() def send_message(to, text): return post("text", {"to": to, "text": text}) def send_file(to, url, file_name, mime_type, kind="document", caption=""): media = {"url": url, "file_name": file_name, "mime_type": mime_type} return post("media", {"to": to, "kind": kind, "media": media, "caption": caption}, timeout=90) if __name__ == "__main__": send_message("919876543210", "Hi Priya, your order #1042 has shipped.") send_file("919876543210", "https://example.com/invoices/1042.pdf", "invoice.pdf", "application/pdf", caption="Your invoice is attached.")
json= sets the Content-Type header for you, and raise_for_status() turns a failed request (a bad token, say) into an exception you can catch and log.
Send to a list with Python
For reminders or notices to a list, loop through it and pause between sends. The API accepts up to 60 requests a minute, and steady pacing also keeps your number safe:
import time def send_to_list(messages, pause_seconds=3): results = [] for number, text in messages: results.append(send_message(number, text)) time.sleep(pause_seconds) # stay well under 60 requests a minute return results send_to_list([ ("919876543210", "Hi Priya, your appointment is tomorrow at 10 AM."), ("447700900123", "Hi Tom, your appointment is tomorrow at 2 PM."), ])
Build the list from your database or a CSV, and keep each batch small. The best practices section explains why.
Send a WhatsApp Message with Node.js
Node.js 18 and later have fetch built in, so there's nothing to install. Save this as whatsapp.mjs:
const BASE_URL = "https://app.assistro.co/api/v1/whatsapp/messages"; const HEADERS = { Authorization: `Bearer ${process.env.SYNCMATE_API_TOKEN}`, Integration: "custom", "Content-Type": "application/json", }; async function post(endpoint, payload) { const res = await fetch(`${BASE_URL}/${endpoint}`, { method: "POST", headers: HEADERS, body: JSON.stringify(payload), }); if (!res.ok) { throw new Error(`SyncMate API error ${res.status}: ${await res.text()}`); } return res.json(); } export const sendMessage = (to, text) => post("text", { to, text }); export const sendFile = (to, url, fileName, mimeType, kind = "document", caption = "") => post("media", { to, kind, media: { url, file_name: fileName, mime_type: mimeType }, caption }); export async function sendToList(messages, pauseMs = 3000) { for (const [number, text] of messages) { await sendMessage(number, text); await new Promise((resolve) => setTimeout(resolve, pauseMs)); // stay under 60 requests a minute } } await sendMessage("919876543210", "Hi Priya, your order #1042 has shipped.");
Run it with node whatsapp.mjs. sendFile() takes a public file link, and sendToList() takes a list of [number, text] pairs, exactly like the Python version.
Sending to WhatsApp Groups
The same endpoint posts to groups. Only the to field changes:
You can get a group's ID with the free WhatsApp Group ID finder. For full group examples, see how to send messages to a WhatsApp group via API. WhatsApp Channels aren't supported by the API yet.
Where to Trigger Messages in a Real App
The code above becomes useful when an event in your system calls it. Common places:
- After checkout: send an order confirmation with the invoice PDF attached. On Shopify or WooCommerce you don't need code at all; use the WhatsApp Shopify integration or the WhatsApp WooCommerce integration.
- On a payment webhook: confirm a payment, or chase a failed one, from your Stripe or Razorpay webhook handler.
- On a schedule: a daily cron job that sends tomorrow's appointment reminders with the list loop above.
- From your CRM: when a deal changes stage, message the lead. HubSpot users can do this from workflows with the WhatsApp HubSpot integration.
- From an automation tool: no backend? Zapier, Make and n8n call the same API for you. See the WhatsApp Zapier integration and how to send WhatsApp messages from n8n.
To receive WhatsApp events back in your app, set up webhooks for WhatsApp events.
Troubleshooting Common Errors
Problem
Likely cause
Fix
401 or 403 error
Token is missing, wrong or was regenerated
Check the Authorization: Bearer header, or regenerate your token
Request succeeds, message never arrives
Number format is wrong, or the number isn't on WhatsApp
Use country code + digits only; see message not received or not sent
Messages queue up or arrive late
Your WhatsApp connection dropped
Check if WhatsApp is connected, then see messages stuck in queue
Sends fail after working all day
Plan's message limit reached
See messages failed due to daily limit or add more message credits
Attachment missing or broken
File too large, or file_name has no extension
Check your plan's size limit; use names like invoice.pdf
For anything else, start with resolving message sending failures.
Best Practices for Sending at Scale
Because SyncMate sends from your real number, WhatsApp judges your API messages the way it judges anything else you send. These habits keep your number in good standing:
- Message people who expect it. Customers who ordered, booked or opted in. Never buy or scrape lists.
- Personalise every message. Use the customer's name and order details. Identical text sent to hundreds of people looks like spam.
- Pace your sends. Split large lists into small batches with pauses between them, and grow volume gradually.
- Retry with backoff. If a request fails, wait a few seconds before retrying, and double the wait each time. Don't retry in a tight loop.
- Log every send. Store the number, the message and the API response, so you can trace any complaint.
- Keep your token secret. Use environment variables or a secrets manager, and regenerate the token if it ever leaks.
Read the full guide on how to keep your WhatsApp account safe and avoid bans.
Start Sending WhatsApp Messages via API
You now have working cURL, Python and Node.js code to send text, files and messages to a list from your own WhatsApp number. Run the cURL test, paste a function into your app, and connect it to the event that matters most to your customers.
Get your free API token
Connect the WhatsApp number you already use, link your store or CRM, and send your first automated message today.
Browse the developer guide
Frequently Asked Questions
Can I send WhatsApp messages via API without the WhatsApp Business API?
Yes. SyncMate connects your existing WhatsApp or WhatsApp Business number and gives you an API to send from it. You don't need Meta verification, a BSP or approved templates.
Do I need message templates to send a WhatsApp message via API?
On the official Cloud API, yes, whenever the customer hasn't messaged you in the last 24 hours. With SyncMate you send any text, because messages go out from your own number like a normal chat.
Can I send images and PDFs through the API?
Yes. Host the file at a public link and send it to the media endpoint with kind set to image, video, audio or document. The maximum file size depends on your plan.
Which programming languages can I use?
Any language that can send an HTTPS POST request with JSON. This guide covers cURL, Python and Node.js; PHP, Java, Go and C# work the same way.
How many WhatsApp messages can I send through the API?
Your SyncMate plan sets the monthly limit: 450 messages on the Free and Personal plans, up to 10,000 on Business. See SyncMate pricing for current plans.
Is it free to send WhatsApp messages via API?
You can start free with 450 messages a month, with Assistro branding added to each message. Paid plans remove the branding and raise the limit.
