WhatsApp Operators DailyThe Blueticks DispatchSaturday, July 25, 2026
Productivity

How to Send a WhatsApp Message from an API (Python, Node & cURL, 2026)

Fire a WhatsApp message straight from your code with one POST. Working Python, Node, and cURL examples, how to schedule for later, and no Meta Business verification.

DRBy Daniel Roth · July 25, 2026 · 10 min read
How to Send a WhatsApp Message from an API (Python, Node & cURL, 2026)

You want to fire a WhatsApp message from a script. A signup confirmation, a shipping ping, a "your table is ready." What you do not want is a month of Meta onboarding, a Business Solution Provider contract, and a per-message meter running before you have sent a single "hello world." This guide gets you from zero to a delivered message with one POST request, in cURL, Python, and Node, then shows you how to schedule the same message for later.

What do you need before you can send a WhatsApp message from an API?

You need three things to send a WhatsApp message from an API with Blueticks: an API key, a WhatsApp number already linked to your account, and a recipient phone number in E.164 format (+15551234567). There is no Meta Business verification, no template approval, and no waiting period. One authenticated POST does it.

Here is the full pre-flight checklist:

  1. Get an API key. Open dev.blueticks.co, sign in, go to the API keys page, and click Create key. Copy it immediately, you only see it once. Live keys look like bt_live_... and are bearer tokens, so treat them like a password and keep them server-side.
  2. Link a WhatsApp number. Blueticks sends from your number, either through WhatsApp Web in your browser or a managed 24/7 gateway. If you have already connected a number in the app, you are set.
  3. Confirm the key works. Call GET https://api.blueticks.co/v1/ping with your key. Per the Blueticks API docs, it returns the account id the key belongs to plus the WhatsApp engines currently connected, so a 200 here means auth and a live number are both good.

The base URL for every call is https://api.blueticks.co, and every request carries an Authorization: Bearer <your key> header. If you want the conceptual background on why this is a WhatsApp REST API that runs on your own number, that companion piece covers the model in depth.

How do you send your first WhatsApp message with one API call? (cURL)

To send a WhatsApp message from an API with cURL, POST a JSON body of {type, text} to https://api.blueticks.co/v1/scheduled-messages/{recipient} with your bearer key — the recipient phone number is a path segment, not a body field. Omit the sendAt field and the message goes out immediately. The response comes back with an id and a status you can track. That is the entire whatsapp api send message flow.

curl -X POST https://api.blueticks.co/v1/scheduled-messages/+15551234567 \
  -H "Authorization: Bearer bt_live_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "text",
    "text": "Hello from the Blueticks API!"
  }'

You get back a message object with an id, a status, and a waMessageKey. For an immediate send the status comes back confirmed once WhatsApp accepts the message (with waMessageKey populated), and the delivery timestamps fill in as it advances. Two things trip people up on the first call:

  • The recipient goes in the URL path. It is a path segment, in E.164 with a leading + and country code, no spaces or dashes: .../scheduled-messages/+15551234567, not (555) 123-4567. The + works as-is, or URL-encode it as %2B. You can also target a WhatsApp chat id directly, like 12345@c.us for a person or 1234567890@g.us for a group. Posting to the bare /v1/scheduled-messages (no recipient) returns 410 Gone.
  • type is required. The body is a typed union, so you must say "type": "text" (or media, or poll). A bare {"text": "..."} is rejected. Text bodies max out at 4,096 characters.

How do you send a WhatsApp message from Python?

To send a WhatsApp message from Python, POST the same JSON to /v1/scheduled-messages/{recipient} using the requests library. Set the Authorization header to your bt_live_ key, put the recipient in the URL path, and pass {type, text} as JSON. It is about ten lines with no SDK required, hitting the plain whatsapp rest api directly.

import requests

API_KEY = "bt_live_YOUR_KEY_HERE"
TO = "+15551234567"  # recipient in E.164, as a path segment

resp = requests.post(
    f"https://api.blueticks.co/v1/scheduled-messages/{TO}",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "type": "text",
        "text": "Hello from Python!",
    },
    timeout=30,
)

resp.raise_for_status()
data = resp.json()
print("sent:", data["id"], "status:", data["status"])

python desk keyboard

The resp.json() payload is the same message object cURL returned. Grab data["id"] and hold onto it, that is the handle you use later to check delivery. If the number is not connected or the key is wrong, you get a 401 or 4xx with an error envelope explaining why, which is exactly why the raise_for_status() call is there.

How do you send a WhatsApp message from Node.js?

To send a WhatsApp message from Node.js, use the built-in fetch (Node 18+) to POST {type, text} to /v1/scheduled-messages/{recipient} with your bearer key. No dependencies, no SDK install. Same endpoint, same body, same response as the Python and cURL versions.

const API_KEY = "bt_live_YOUR_KEY_HERE";
const TO = "+15551234567"; // recipient in E.164, as a path segment

const resp = await fetch(`https://api.blueticks.co/v1/scheduled-messages/${TO}`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    type: "text",
    text: "Hello from Node!",
  }),
});

if (!resp.ok) throw new Error(`Send failed: ${resp.status}`);
const data = await resp.json();
console.log("sent:", data.id, "status:", data.status);

The pattern generalizes. Want to send a PDF instead of text? Swap the body for {"type": "media", "mediaUrl": "https://cdn.example.com/receipt.pdf", "mediaKind": "document"}, with the recipient still in the URL path. Want a poll? Use {"type": "poll", "pollQuestion": "...", "pollOptions": ["A", "B"]}. The endpoint is one door with three shapes behind it.

How do you schedule that same message for later instead of sending it now?

To schedule a WhatsApp message through the API, add a sendAt timestamp to the same POST body. Blueticks then queues the message instead of sending it immediately. Use an RFC 3339 / ISO 8601 datetime with an offset, at least 10 seconds in the future and no more than 365 days out. This is how you schedule whatsapp messages api-side without a separate endpoint.

Here is the whatsapp api python schedule version, sending a reminder for 9:00 AM UTC tomorrow:

import requests
from datetime import datetime, timedelta, timezone

API_KEY = "bt_live_YOUR_KEY_HERE"
TO = "+15551234567"
send_at = (datetime.now(timezone.utc) + timedelta(days=1)).replace(
    hour=9, minute=0, second=0, microsecond=0
).isoformat()

resp = requests.post(
    f"https://api.blueticks.co/v1/scheduled-messages/{TO}",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "type": "text",
        "text": "Reminder: your appointment is at 10am.",
        "sendAt": send_at,  # e.g. 2026-07-26T09:00:00+00:00
    },
    timeout=30,
)
resp.raise_for_status()
print("scheduled:", resp.json()["id"])

The response comes back with status: "pending" — the message is accepted and waiting in the queue rather than dispatched. One gotcha worth calling out: sendAt is timezone-sensitive. Send it in UTC with a Z or an explicit offset, never a naked local time, or your 9 AM turns into someone else's 4 AM. Changed your mind before it fires? POST /v1/scheduled-messages/{id}/cancel pulls it back out of the queue. For the deeper patterns, our guide on how to send and schedule WhatsApp messages via API walks through recurring sends and edits.

Ready to send your first one? Grab a free API key and send a live WhatsApp message with a single POST. No Meta Business verification, no template approval queue, no per-message fees, straight from your own number.

Why does this API send from your own WhatsApp number instead of the Meta Cloud API?

Blueticks drives the WhatsApp number you already own, over WhatsApp Web or a managed 24/7 gateway, rather than routing through Meta's Cloud API. That is why there are no per-message fees, no template pre-approval, and no Business Verification step. The tradeoff is that you own recipient consent and there is no contractual guarantee against a ban.

The contrast is stark. On the official Meta Cloud API, Meta charges per delivered template message as of July 1, 2025, and every business-initiated template has to clear a template categorization and approval process before it can send. Scaling past a starter tier pulls in messaging limits and Business Verification, where unverified accounts are capped at 250 unique business-initiated recipients in a rolling 24 hours. For system-generated, high-volume messaging to strangers, that structure exists for good reason.

Sending from your own number is the right fit when a human would happily type each of these messages but does not have the time: appointment reminders, order updates to your existing customers, follow-ups to people who opted in. It is the wrong fit for cold blasting thousands of people who never asked to hear from you. WhatsApp's spam detection does not care which API you used, and consent is your job either way.

What breaks: because this rides your real WhatsApp session, that session has to stay linked. If you send over WhatsApp Web and you close the tab or your laptop sleeps, queued messages stall until it reconnects. The managed gateway exists precisely to keep a number online 24/7 so your scheduled sends fire whether or not your machine is awake.

How do you confirm the message actually delivered after the API call returns?

The POST returns the moment the message is accepted, not when it lands. To confirm delivery, poll GET /v1/scheduled-messages/{id} and watch the status field climb through pendingconfirmedreceivedread, or drop to failed with a failureReason explaining what went wrong.

phone notification check

Those statuses map onto the ticks you already know from the app. confirmed means WhatsApp accepted the message (it now carries a waMessageKey), received is the two grey checks WhatsApp shows once a message reaches the recipient's phone, and read is the two blue checks that appear once they open it (assuming they have read receipts on). A voice note that gets listened to advances one step further, to played. A quick Python poll:

status = requests.get(
    f"https://api.blueticks.co/v1/scheduled-messages/{msg_id}",
    headers={"Authorization": f"Bearer {API_KEY}"},
).json()
print(status["status"], status.get("failureReason"))

Polling is fine for a handful of messages. At volume, do not hammer the endpoint in a tight loop. Register a webhook instead so Blueticks pushes status changes to you as they happen. Our walkthrough on WhatsApp API webhooks and auto-replies covers the event payloads. One nuance: the message's waMessageKey (WhatsApp's own wire id) is null until the message reaches confirmed, and only populates once the engine actually dispatches it, so build your tracking around the id you got back from the send.

When one API call is not enough: audiences, campaigns, and retries

When you are messaging hundreds of people, stop looping the send endpoint. Blueticks exposes /v1/audiences and /v1/campaigns so you upload a contact list once and dispatch a single paced campaign, with retries handled for you. A metered campaign keeps you far below WhatsApp's spam radar better than a for-loop firing sends as fast as your network allows.

The failure mode here is real and common. A naive script that POSTs 500 sends in a tight loop looks, from WhatsApp's side, exactly like a spam bot, and that is one of the fastest ways to get a number flagged. As one operator running reminder blasts for a clinic put it: "The moment I switched from a raw loop to a paced campaign, the delivery problems just stopped. Same messages, same number, spread over an hour instead of a minute."

Practically, a campaign gives you three things a bare loop does not:

  • Pacing. Sends are spread over a window instead of a burst.
  • Retries. A transient failure gets another attempt instead of silently vanishing.
  • One handle for the batch. You track a campaign id, not 500 individual message ids.

You still own consent, opt-in, and the content. The API removes the plumbing, not the responsibility.

FAQ

Is this the official WhatsApp Business API? No. Blueticks is a WhatsApp REST API that drives your own linked number over WhatsApp Web or a managed gateway. It is distinct from Meta's Cloud API, which is the official WhatsApp Business Platform and bills per delivered template message. The upside is no per-message fees and no template approval; the tradeoff is no contractual delivery or anti-ban guarantee.

Do I need Meta Business verification to send a WhatsApp message from an API this way? No. Because you send from a number you already control, there is no Business Verification, no BSP contract, and no template review. You create an API key at dev.blueticks.co and send. Verification only enters the picture on Meta's own Cloud API.

What does a Blueticks API key look like? Live keys start with bt_live_ and are sent as a bearer token in the Authorization: Bearer <key> header. Copy it when you create it, because it is shown only once, and keep it on your server, never in client-side or mobile code.

Can I schedule a recurring message through the API? The send endpoint schedules a single message via sendAt. For repeating sends, either script the recurrence yourself (compute the next sendAt each cycle) or use the recurring scheduler in the Blueticks app. The one-shot sendAt accepts anything from 10 seconds to 365 days out.

Will sending through my own number get it banned? It can if you misuse it. WhatsApp bans numbers that behave like spam bots regardless of the tool. Message people who opted in, pace bulk sends through a campaign rather than a tight loop, and keep content relevant. There is no guaranteed no-ban, and consent is always the sender's responsibility.

Email

The Dispatch, every week.

One sharp WhatsApp growth tactic in your inbox each week. Joined by 238,000+ founders, marketers and support leads.

Free forever. No spam, unsubscribe in one click.