How to Send a WhatsApp Message via the API (2026 Tutorial)

Send your first WhatsApp message via the Cloud API in 10 minutes. Copy-paste Node.js and Python code for text, media, and template messages.

Miki Palet

Last updated: May 27, 2026 by

·15 min read·

The WhatsApp Cloud API lets you send messages programmatically with a single HTTP POST to https://graph.facebook.com/v22.0/{phone-number-id}/messages. You need a Meta WhatsApp Business Account, an access token, and a recipient phone number.

The complications start when you need to send media, manage templates at scale, handle rate limits, or message users outside the 24-hour service window. This tutorial walks through both paths: the direct Meta Cloud API (free, more setup) and the Zernio WhatsApp API.

In this guide

TL;DR — 10-minute path

  1. Create a Meta Business Account
  2. Generate an access token under WhatsApp → API Setup
  3. Add your test recipient's phone number
  4. Run the curl command above
  5. You'll get a "hello_world" template message on WhatsApp

For production, you'll need template approval, webhook configuration, and a verified business number. Skip to the Common errors section if you hit issues, or jump to Zernio's managed setup to skip the infrastructure work.

Prerequisites

To follow along with this tutorial, ensure you have the following:

  • WhatsApp Account: An active WhatsApp account to receive and test messages sent via the API.
  • WhatsApp Business Account (WABA): Required to send messages and templates. You can create one via WhatsApp Business.
  • Node.js: A JavaScript runtime that allows you to run JavaScript code outside the browser. Download it from nodejs.org.
  • Code Editor: A software application used for writing and editing code. For example, Visual Studio Code is widely used for JavaScript development.

How do you set up the WhatsApp Cloud API?

Before sending messages programmatically, you need to set up the WhatsApp API on Meta. In this section, you will create an app, generate an access token, and send your first message.

To get started, visit Meta for Developers, sign in, and click the My Apps button at the top of the page.

my_apps.png

Next, enter your app details and select "Connect with customers through WhatsApp" as the use case.

connect_via_whatsapp.png

Verify the app details and create a new app.

verify_submit.png

After creating the app, configure it based on your use case.

customize_usecase.png

Select API Setup from the sidebar menu and click Generate access token to create your authentication token.

api_setup.png

Add a phone number to the recipients list.

select_recipient.png

Click Send message to test the API. You should receive a message on your test phone number.

send_message.png

Next, select Quickstart from the sidebar menu and click Message Templates.

create_temp.png

WhatsApp sends messages using templates. Templates allow you to create structured messages with placeholders (variables) that can be dynamically filled with user-specific data.

select_template-ezgif.com-video-to-gif-converter.gif

Finally, create a new template by adding content, buttons, and variables. This allows you to build reusable and customisable message templates.

edit_template-ezgif.com-video-to-gif-converter.gif

How to send WhatsApp messages with Node.js

In this section, you will learn how to integrate the WhatsApp API with Node.js to send text, media, interactive, and template messages directly from your application.

First, create a folder to hold your project files.

mkdir whatsapp-api
cd whatsapp-api

Run the following code snippet to create a package.json file within the project folder.

npm init -y

Next, install the project dependencies. We will use Axios for making HTTP requests to the WhatsApp API, Dotenv for managing environment variables securely, and Form-data to handle multipart form data when sending media or template messages.

npm install axios dotenv form-data

Create an index.js file within the project folder and import the newly installed packages into the file.

require("dotenv").config();
const FormData = require("form-data");
const axios = require("axios");
const fs = require("fs");

Add a .env file inside your project folder and add your credentials as environment variables.

WHATSAPP_TOKEN=<your_access_token>
WHATSAPP_PHONE_NUMBER_ID=<your_phone_number_ID>
WHATSAPP_RECIPIENT_PHONE_NUMBER=<recipient_whatsapp_number>

You can run your application at any time using the following command:

node index.js

Congratulations, your setup is complete!

Code integration examples

Add the following code snippet to the index.js file to send message templates directly from the application.

async function sendTemplateMessage() {
	const response = await axios({
		url: `https://graph.facebook.com/v22.0/${process.env.WHATSAPP_PHONE_NUMBER_ID}/messages`,
		method: "post",
		headers: {
			Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`,
			"Content-Type": "application/json",
		},
		data: JSON.stringify({
			messaging_product: "whatsapp",
			to: `${process.env.WHATSAPP_RECIPIENT_PHONE_NUMBER}`,
			type: "template",
			template: {
				name: "hello_world",
				language: {
					code: "en_US",
				},
			},
		}),
	});

	console.log(response.data);
}

sendTemplateMessage();

The sendTemplateMessage function sends the default template to the recipient using the credentials stored in the environment variables.

You can also send text messages directly from the API using the function below:

async function sendTextMessage() {
	const response = await axios({
		url: `https://graph.facebook.com/v22.0/${process.env.WHATSAPP_PHONE_NUMBER_ID}/messages`,
		method: "post",
		headers: {
			Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`,
			"Content-Type": "application/json",
		},
		data: JSON.stringify({
			messaging_product: "whatsapp",
			to: `${process.env.WHATSAPP_RECIPIENT_PHONE_NUMBER}`,
			type: "text",
			text: {
				body: "This is a text message",
			},
		}),
	});

	console.log(response.data);
}

sendTextMessage();

The sendTextMessage function has a type attribute set to "text" and includes a text object for sending plain text messages.

How to send media (images, video, documents) via the WhatsApp API

The Cloud API supports four media types: image, video, audio, and document. You can attach media in two ways: by hosted URL, or by uploading the file to WhatsApp first and using the returned media ID.

MethodWhen to useProsCons
Hosted URL (link)Image already lives on your CDNOne API call, no upload stepURL must be publicly reachable; WhatsApp caches it
Uploaded ID (id)Image lives on your server or user-uploadedFaster repeated sends, privateTwo API calls (upload + send)

To send images with captions via hosted URL, update the type property as follows:

async function sendMediaMessage() {
	const response = await axios({
		url: `https://graph.facebook.com/v22.0/${process.env.WHATSAPP_PHONE_NUMBER_ID}/messages`,
		method: "post",
		headers: {
			Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`,
			"Content-Type": "application/json",
		},
		data: JSON.stringify({
			messaging_product: "whatsapp",
			to: `${process.env.WHATSAPP_RECIPIENT_PHONE_NUMBER}`,
			type: "image",
			image: {
				link: "https://dummyimage.com/600x400/000/c0a&text=hi",
				caption: "Hi! This is an image message.",
			},
		}),
	});

	console.log(response.data);
}

sendMediaMessage();

You can also send images stored on your local computer. First upload the image to the API, retrieve its media ID, then send using that ID.

const fs = require("fs");

async function uploadImage() {
	const data = new FormData();
	data.append("messaging_product", "whatsapp");
	data.append("file", fs.createReadStream(process.cwd() + "/image.png"), {
		contentType: "image/png",
	});
	data.append("type", "image/png");

	const response = await axios({
		url: `https://graph.facebook.com/v22.0/${process.env.WHATSAPP_PHONE_NUMBER_ID}/media`,
		method: "post",
		headers: {
			Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`,
		},
		data: data,
	});

	console.log(response.data);
}

The uploadImage function uploads a local image to the WhatsApp API and logs the image id to the console. Then send using that ID:

async function sendMediaMessageById() {
	const response = await axios({
		url: `https://graph.facebook.com/v22.0/${process.env.WHATSAPP_PHONE_NUMBER_ID}/messages`,
		method: "post",
		headers: {
			Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`,
			"Content-Type": "application/json",
		},
		data: JSON.stringify({
			messaging_product: "whatsapp",
			to: `${process.env.WHATSAPP_RECIPIENT_PHONE_NUMBER}`,
			type: "image",
			image: {
				id: "8954**********",
				caption: "Hi! This is an image message.",
			},
		}),
	});

	console.log(response.data);
}

sendMediaMessageById();

How to send a WhatsApp message in Python

If you prefer Python, the same Cloud API call looks like this with the requests library:

import os
import requests

url = f"https://graph.facebook.com/v22.0/{os.environ['WHATSAPP_PHONE_NUMBER_ID']}/messages"

headers = {
    "Authorization": f"Bearer {os.environ['WHATSAPP_TOKEN']}",
    "Content-Type": "application/json",
}

payload = {
    "messaging_product": "whatsapp",
    "to": os.environ["WHATSAPP_RECIPIENT_PHONE_NUMBER"],
    "type": "template",
    "template": {"name": "hello_world", "language": {"code": "en_US"}},
}

response = requests.post(url, headers=headers, json=payload)
print(response.json())

The same pattern works for text and media messages. Swap the type field to "text" or "image" and add the matching body.

Stop building social integrations from scratch.

One API call to publish, schedule, and manage posts across 15+ platforms.

Common WhatsApp API errors and how to fix them

Error codeWhat it meansFix
(#131056) Recipient phone number not in allowed listYou haven't verified the recipient in your test appAdd the number under API Setup → Recipients
(#132000) Number of parameters does not match templateVariable count in your payload doesn't match the approved templateRe-read the template body and count {{1}}, {{2}} placeholders
(#131047) Re-engagement messageYou're sending a free-form message outside the 24-hour service windowSwitch to an approved template message
(#131026) Message undeliverableRecipient doesn't have WhatsApp, or hasn't accepted ToSVerify the number on whatsapp.com/business/api before retrying
(#133010) Phone number not registeredYour WhatsApp Business phone number isn't registered with Cloud APIRe-run the registration step in Meta Business Manager
400 Bad Request with no specific codeMalformed JSON or wrong API versionValidate JSON; confirm you're using v22.0 or later

When debugging, always log the full response body. WhatsApp returns useful error_data fields that get hidden if you only log the status code.

What's the easiest way to send WhatsApp messages?

Zernio gives you one API for WhatsApp and 13 other platforms. Instead of managing multiple APIs and authentication flows, you interact with a single interface that handles the platform-specific complexity for you.

In this section, you will configure Zernio for WhatsApp messaging and learn how to create, schedule, and send messages using its API and SDKs.

First, create a Zernio account and log into your dashboard.

dashboard.png

Select Connections from the sidebar menu and connect your WhatsApp account to Zernio.

connect_whatsapp.png

After clicking the WhatsApp Connect button, a pop-up appears where you can choose between getting a US number at a flat rate of $2 per month or connecting an existing WhatsApp Business account.

payment_option.png

Select an option and connect your WhatsApp number to Zernio.

connect_successful.png

From the sidebar menu, select Broadcast > Templates to create a new WhatsApp template based on your messaging needs.

create_whatsapp_template-ezgif.com-video-to-gif-converter.gif

You may need to wait up to 24 hours for Meta to approve your template. Once approved, you can start sending messages to your customers or contacts.

template_approve.png

Configuring the Zernio API and Node.js SDK

Before we proceed, copy your Zernio API key and WhatsApp account ID and save them into environment variables in the .env file.

ZERNIO_API_KEY=<your_api_key>
ZERNIO_WHATSAPP_ACCOUNT_ID=<WhatsApp_account_ID>

Select API keys from the sidebar menu to create a new API key.

create_zernio_key.png

Click the Copy icon under the WhatsApp connection to copy your account ID.

copy_whatsapp_id.png

Next, install the Zernio Node.js SDK.

npm install @zernio/node

Finally, import it into the index.js file as shown below:

const Zernio = require("@zernio/node").default;
const zernio = new Zernio({ apiKey: process.env.ZERNIO_API_KEY });

Sending WhatsApp messages with the Zernio SDK

Zernio allows you to group your contacts or customers into broadcast lists, making it easy to send or schedule bulk messages. This is useful for sharing updates such as new arrivals, price changes, or other important information.

Using the existing whatsapp-api Node.js project, add the following code snippet to your index.js file.

async function sendWithZernio() {
	const { data } = await zernio.whatsapp.sendWhatsAppBulk({
		body: {
			accountId: process.env.ZERNIO_WHATSAPP_ACCOUNT_ID,
			recipients: [
				{
					phone: `${process.env.WHATSAPP_RECIPIENT_PHONE_NUMBER}`,
					variables: { 1: "David", 2: "Bread and Butter" },
				},
			],
			template: {
				name: "order_ready",
				language: "en",
			},
		},
	});
	console.log(`Sent: ${data.summary.sent}, Failed: ${data.summary.failed}`);
}

sendWithZernio();

The sendWithZernio function uses the sendWhatsAppBulk method to send a template message to the phone numbers defined in the recipients array. It references the order_ready template and passes dynamic values through the variables object, which are inserted into the template before sending.

Once executed, the function sends the message to the specified contacts and logs a summary of successful and failed deliveries.

zernio_message_deliver.png

Next, let's create a WhatsApp broadcast to schedule and send messages to your contacts.

Add the following code snippet to create a new broadcast:

async function createBroadcastList() {
	const { data } = await zernio.whatsapp.createWhatsAppBroadcast({
		body: {
			accountId: process.env.ZERNIO_WHATSAPP_ACCOUNT_ID,
			name: "Monthly Newsletter",
			template: {
				name: "order_ready",
				language: "en",
				components: [
					{
						type: "body",
						parameters: [
							{ type: "text", text: "{{1}}" },
							{ type: "text", text: "{{2}}" },
						],
					},
				],
			},
			recipients: [
				{
					phone: `${process.env.WHATSAPP_RECIPIENT_PHONE_NUMBER}`,
					name: "David",
					variables: { 1: "David", 2: "Mac and Cheese" },
				},
			],
		},
	});
	console.log("Broadcast created:", data.broadcast.id);
}

The createBroadcastList function creates a new broadcast using an existing message template and a list of recipients. When executed, the function logs the broadcast ID to the console. This ID can then be used to send or schedule messages to all recipients in the broadcast list.

Copy the following code snippet to send an instant message to the contacts in the broadcast list.

async function sendInstantMessage() {
	const { data } = await zernio.whatsapp.sendWhatsAppBroadcast({
		path: { broadcastId: "YOUR_BROADCAST_ID" },
	});
	console.log(`Sent: ${data.sent}, Failed: ${data.failed}`);
}

sendInstantMessage();

Finally, you can schedule broadcast messages by providing a scheduledAt attribute with an ISO 8601 formatted timestamp.

async function scheduleBroadcast() {
	await zernio.whatsapp.scheduleWhatsAppBroadcast({
		path: { broadcastId: "YOUR_BROADCAST_ID" },
		body: { scheduledAt: "2026-03-22T19:36:00.000Z" },
	});
	console.log("Broadcast scheduled for 2026-03-22T19:36:00.000Z");
}

scheduleBroadcast();

scheduled_whatsapp.png

The scheduleBroadcast function schedules a broadcast using the broadcast ID and the specified time. Once executed, the broadcast will be sent automatically at the scheduled date and time.

If you want to interact with the Zernio API directly or use another programming language, check out the Zernio WhatsApp API documentation. It includes details on pricing, supported file formats and media requirements, and debugging and troubleshooting tips.

When should you use Zernio instead of the Cloud API?

When working with social media APIs, publishing content across multiple platforms gets messy when you're juggling multiple API endpoints — each with its own authentication method, request format, and media upload workflow.

Zernio gives you one API for WhatsApp and 13 other platforms. Below are the key differences:

Platform-specific authentication

Most social media platforms require different authentication mechanisms such as OAuth flows, app passwords, or API keys. Each method has its own setup process, token management system, and permission scopes.

Zernio handles the authentication process for you. Once your account is connected to Zernio, you can publish posts through the unified API without managing platform-specific tokens or authorisation flows.

Different API payload structures

Every social platform expects requests in a slightly different format. Zernio standardises these differences by allowing you to send a single payload format that works across supported platforms.

const response = await fetch("https://zernio.com/api/v1/posts", {
  method: "POST",
  headers: { "Authorization": `Bearer ${process.env.ZERNIO_API_KEY}` },
  body: JSON.stringify({
    text: "New feature drop!",
    platforms: ["twitter", "instagram", "linkedin"],
    mediaUrls: ["https://example.com/demo.mp4"],
    scheduledFor: "2025-01-15T09:00:00Z"
  })
});

Media upload complexity

Uploading images or videos is often one of the most complicated parts of social media integrations. Zernio handles the upload flow for you, allowing you to attach media to posts without handling the platform-specific upload process.

Rate limits and platform restrictions

Social media platforms typically enforce rate limits that restrict how frequently your application can interact with their APIs. Zernio helps manage these platform-specific constraints automatically.

Cloud API vs Zernio: which to choose

Meta Cloud API (direct)Zernio
Setup time2–4 weeks (Business verification, webhooks, hosting, templates)Under 30 minutes
Cost to sendMeta's per-template fee only ($0.0014–$0.0768 by country)Flat monthly plan, WhatsApp included free
Meta Business VerificationYou handle itZernio handles it
Other platforms supportedWhatsApp only15 platforms (Instagram, TikTok, LinkedIn, X, and 10 more)
Template managementMeta Business Manager dashboardAPI + Zernio dashboard with one-click approval flow
Rate limit handlingYou build retry logicAutomatic with exponential backoff
Bulk send / broadcastsBuild it yourselfNative broadcast API
WebhooksConfigure and host your own endpointManaged; Zernio normalizes events across platforms
AI agent integrationREST onlyREST + MCP server + CLI
Best forEngineering teams who want raw Meta rates and full controlTeams shipping fast, agencies, AI products needing WhatsApp + more

Use the Cloud API direct if WhatsApp is your only channel and you have engineers to maintain the infrastructure. Use Zernio if you need WhatsApp plus the other platforms developers and AI agents reach for, with one auth and one bill.

FAQ

Is the WhatsApp API free to use?

The Meta Cloud API itself is free. You only pay Meta's per-template message fee, which ranges from $0.0014 (India) to $0.0768 (Germany) depending on country and message category. Free-form messages and utility templates inside the 24-hour customer service window are free. See our Twilio WhatsApp pricing breakdown for a full cost comparison.

Do I need a WhatsApp Business Account to use the API?

Yes. You need a Meta WhatsApp Business Account (WABA) and a Meta Business Manager profile. The personal WhatsApp app and WhatsApp Business app are not the same as the WhatsApp Business API.

Can I send WhatsApp messages without writing code?

Yes, through managed platforms like Zernio you can send broadcasts and templates from a dashboard. The Cloud API itself requires code (or a no-code automation tool like n8n).

What's the difference between Meta Cloud API and Twilio WhatsApp API?

Meta Cloud API is WhatsApp's official API maintained by Meta — cheaper, but you handle hosting and templates. Twilio resells the same underlying API with a $0.005 per-message platform fee plus extra features like number provisioning. See our Twilio vs Zernio comparison.

Can I send media (images, videos) via the WhatsApp API?

Yes. You can attach media by hosted URL (set the link field) or by uploading the file first and using the returned media ID. The Cloud API supports images, video, audio, and documents.

How do I send WhatsApp messages in Python?

Use the requests library to POST to https://graph.facebook.com/v22.0/{phone-number-id}/messages with your access token in the Authorization header. See the Python code example above.

Conclusion

In this tutorial, you've learnt how to send WhatsApp messages and templates using both the Meta Cloud API and Zernio. You also explored how to send text, media, and template messages, as well as creating and scheduling broadcasts to reach multiple contacts efficiently using Zernio.

It's also important to note that Zernio includes WhatsApp messaging in your plan at no extra cost, while Meta charges per delivered template message directly to your WhatsApp Business Account.

Here are some helpful resources to explore next:

Sign up and get your free API key to enable automated posting, monitoring, and engagement across multiple platforms.

Learn more about this topic with AI