WhatsApp For Business API
When to choose WhatsApp for Business API
Choose the WhatsApp for Business API when your customer engagement needs a WhatsApp-native channel for approved templates, customer replies, media messages, and WhatsApp delivery callbacks; choose SMS APIs when you need handset reach outside WhatsApp or a simpler SMS-only workflow.
Overview
Our WhatsApp Business Platform (WAB) API allows you to interact with WhatsApp users via your WhatsApp Business Account.
This is a quick overview to guide you through the sign up and on-boarding process for WhatsApp Business API. Contact your existing Messaging Platform solutions provider for an overview of WhatsApp Business application features and services.
What the API can do
- Send WhatsApp messages to individual recipients
- Broadcast supported WhatsApp messages to multiple recipients
- Upload media for use in WhatsApp messages
- Retrieve outbound and inbound WhatsApp message records
- Receive inbound message callbacks from WhatsApp users
- Receive DLR callbacks for WhatsApp message status updates
How it works
In practice, the API follows a simple workflow:
- Complete onboarding for your WhatsApp Business Account.
- Configure your Mobile Gateway WhatsApp Business API application.
- Create and manage any required WhatsApp message templates.
- Send messages through the WAB API endpoints using JSON over HTTPS.
- Use webhooks and callbacks to receive inbound messages and delivery status updates.
When to use WhatsApp for Business API
Use WhatsApp for Business API when your application needs to communicate with customers through WhatsApp using your WhatsApp Business Account. It is useful for approved notification templates, service conversations, customer replies, and media-rich interactions where WhatsApp is the preferred customer channel.
This API is not a replacement for SMS reach. If recipients may not use WhatsApp, or if you need a simpler mobile messaging workflow without WhatsApp onboarding and template rules, review the SMS REST APIs instead.
Before you start
Before making your first request, confirm the following:
- Your WhatsApp Business API application has been provisioned.
- Your WhatsApp Business onboarding is complete.
- Any required message templates have been created and approved.
- You have API credentials for the WAB endpoints.
- Your callback URLs are configured if you need inbound message or delivery status events.
First successful request path
For most implementations, the fastest way to validate connectivity and configuration is:
- Authenticate using your WhatsApp API credentials.
- Submit a simple POST request to
/messageswith a valid destination, source, type, and message body. - Confirm the
202 Acceptedresponse and store the returned message ID. - Retrieve the message with
GET /messages?id={message_id}or reconcile status through the configured DLR callback.
Onboarding Process
For WhatsApp Business API pricing, and to sign up to our WhatsApp Business API, contact your Account Manager.
Our provisioning team will provision your Mobile Gateway WhatsApp Business API in our system.
You will need to assign a User who has access to your businesses Facebook account.
Our provisioning team will email your designated User a URL link. This will direct the User to our interface, and guide you through the Embedded Sign Up process.
Developer Information
Please see our API Documentation for details and code samples.
Embedded Sign Up
Visit Embedded Sign Up process documentation for details on the process and the role we play as your WhatsApp Solution Provider.
Message Templates
For more information on managing Message Templates within your existing WhatsApp Business Application, visit the Message Template Guidelines or the Business Management API Guide - Templates documentation by Meta.
Webhooks
Visit this link for more information on managing Webhooks within your existing WhatsApp Business Application, or contact your existing Messaging Platform solutions provider.
Sending WhatsApp Messages
You can send a WhatsApp message to the following endpoints using the cURL utility.
Send WhatsApp Message Example
POST /messages is the endpoint to send (create) new WhatsApp MT messages.
curl -X POST \
--url https://{apiDomainName}/rest/wab/v1/messages \
-H 'accept: application/json' \
-H 'authorization: Basic <token>' \
-H 'content-type: application/json' \
-d '{
"destination": "+64123456879",
"type": "text",
"text": {
"body": "Hello"
},
"source": "1234567890"
}'
const response = await fetch("https://{apiDomainName}/rest/wab/v1/messages", {
method: "POST",
headers: {
"accept": "application/json",
"authorization": "Basic <token>",
"content-type": "application/json"
},
body: JSON.stringify({
destination: "+64123456879",
type: "text",
text: {
body: "Hello"
},
source: "1234567890"
})
});
const result = await response.json();import requests
response = requests.post(
"https://{apiDomainName}/rest/wab/v1/messages",
headers={
"accept": "application/json",
"authorization": "Basic <token>",
"content-type": "application/json",
},
json={
"destination": "+64123456879",
"type": "text",
"text": {
"body": "Hello",
},
"source": "1234567890",
},
)
result = response.json()<?php
$payload = json_encode([
"destination" => "+64123456879",
"type" => "text",
"text" => [
"body" => "Hello"
],
"source" => "1234567890"
]);
$ch = curl_init("https://{apiDomainName}/rest/wab/v1/messages");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"accept: application/json",
"authorization: Basic <token>",
"content-type: application/json"
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>
require "json"
require "net/http"
require "uri"
uri = URI("https://{apiDomainName}/rest/wab/v1/messages")
request = Net::HTTP::Post.new(uri)
request["accept"] = "application/json"
request["authorization"] = "Basic <token>"
request["content-type"] = "application/json"
request.body = {
destination: "+64123456879",
type: "text",
text: {
body: "Hello"
},
source: "1234567890"
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
endimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
String payload = """
{
"destination": "+64123456879",
"type": "text",
"text": {
"body": "Hello"
},
"source": "1234567890"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{apiDomainName}/rest/wab/v1/messages"))
.header("accept", "application/json")
.header("authorization", "Basic <token>")
.header("content-type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());using System.Text;
using var client = new HttpClient();
var request = new HttpRequestMessage(
HttpMethod.Post,
"https://{apiDomainName}/rest/wab/v1/messages");
request.Headers.Add("accept", "application/json");
request.Headers.TryAddWithoutValidation("authorization", "Basic <token>");
request.Content = new StringContent(
"""{"destination":"+64123456879","type":"text","text":{"body":"Hello"},"source":"1234567890"}""",
Encoding.UTF8,
"application/json");
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();202 response:
[
{
"id": "b95fc11e-37f0-4770-a082-6ea22d4c4d12",
"status": "accepted",
"reference": ""
}
]
400 response:
{
"error": "bad request error message",
"message": "WhatsApp Cloud API error",
"statusCode": 400
}
Broadcast WhatsApp Message Example
POST /messages/broadcast
curl \
-X POST 'https://{apiDomainName}/rest/wab/v1/messages/broadcast' \
-H 'accept: application/json' \
-H 'authorization: Basic <token>' \
-H 'content-type: application/json' \
-d '{
"destination": [
"+64123456789",
"+64223456788"
],
"type": "text",
"text": {
"body": "Hello"
},
"source": "1234567890"
}'
const response = await fetch("https://{apiDomainName}/rest/wab/v1/messages/broadcast", {
method: "POST",
headers: {
"accept": "application/json",
"authorization": "Basic <token>",
"content-type": "application/json"
},
body: JSON.stringify({
destination: [
"+64123456789",
"+64223456788"
],
type: "text",
text: {
body: "Hello"
},
source: "1234567890"
})
});
const result = await response.json();import requests
response = requests.post(
"https://{apiDomainName}/rest/wab/v1/messages/broadcast",
headers={
"accept": "application/json",
"authorization": "Basic <token>",
"content-type": "application/json",
},
json={
"destination": [
"+64123456789",
"+64223456788",
],
"type": "text",
"text": {
"body": "Hello",
},
"source": "1234567890",
},
)
result = response.json()<?php
$payload = json_encode([
"destination" => [
"+64123456789",
"+64223456788"
],
"type" => "text",
"text" => [
"body" => "Hello"
],
"source" => "1234567890"
]);
$ch = curl_init("https://{apiDomainName}/rest/wab/v1/messages/broadcast");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"accept: application/json",
"authorization: Basic <token>",
"content-type: application/json"
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>
require "json"
require "net/http"
require "uri"
uri = URI("https://{apiDomainName}/rest/wab/v1/messages/broadcast")
request = Net::HTTP::Post.new(uri)
request["accept"] = "application/json"
request["authorization"] = "Basic <token>"
request["content-type"] = "application/json"
request.body = {
destination: [
"+64123456789",
"+64223456788"
],
type: "text",
text: {
body: "Hello"
},
source: "1234567890"
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
endimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
String payload = """
{
"destination": [
"+64123456789",
"+64223456788"
],
"type": "text",
"text": {
"body": "Hello"
},
"source": "1234567890"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{apiDomainName}/rest/wab/v1/messages/broadcast"))
.header("accept", "application/json")
.header("authorization", "Basic <token>")
.header("content-type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());using System.Text;
using var client = new HttpClient();
var request = new HttpRequestMessage(
HttpMethod.Post,
"https://{apiDomainName}/rest/wab/v1/messages/broadcast");
request.Headers.Add("accept", "application/json");
request.Headers.TryAddWithoutValidation("authorization", "Basic <token>");
request.Content = new StringContent(
"""{"destination":["+64123456789","+64223456788"],"type":"text","text":{"body":"Hello"},"source":"1234567890"}""",
Encoding.UTF8,
"application/json");
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();202 response:
[
{
"destination": "+64123456789",
"id": "a6c566d8-59f8-4187-9906-c296ae41bf13",
"status": "accepted"
},
{
"destination": "+64223456788",
"id": "cd415c6d-2fe8-4cb0-b5d7-135674fcf5e5",
"status": "accepted"
}
]
Upload WhatsApp Media Example
POST /media
curl \
-X POST 'https://{apiDomainName}/rest/wab/v1/media?source=string' \
-H 'accept: application/json' \
-H 'authorization: Basic <token>' \
-H 'x-xsrf-token: string' \
-F file=string
const formData = new FormData();
formData.append("file", "string");
const response = await fetch("https://{apiDomainName}/rest/wab/v1/media?source=string", {
method: "POST",
headers: {
"accept": "application/json",
"authorization": "Basic <token>",
"x-xsrf-token": "string"
},
body: formData
});
const media = await response.json();import requests
response = requests.post(
"https://{apiDomainName}/rest/wab/v1/media?source=string",
headers={
"accept": "application/json",
"authorization": "Basic <token>",
"x-xsrf-token": "string",
},
files={
"file": (None, "string"),
},
)
media = response.json()<?php
$ch = curl_init("https://{apiDomainName}/rest/wab/v1/media?source=string");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"accept: application/json",
"authorization: Basic <token>",
"x-xsrf-token: string"
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, [
"file" => "string"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>
require "net/http"
require "securerandom"
require "uri"
uri = URI("https://{apiDomainName}/rest/wab/v1/media?source=string")
boundary = "----RubyFormBoundary#{SecureRandom.hex}"
body = [
"--#{boundary}",
'Content-Disposition: form-data; name="file"',
"",
"string",
"--#{boundary}--",
""
].join("\r\n")
request = Net::HTTP::Post.new(uri)
request["accept"] = "application/json"
request["authorization"] = "Basic <token>"
request["x-xsrf-token"] = "string"
request["Content-Type"] = "multipart/form-data; boundary=#{boundary}"
request.body = body
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
endimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.UUID;
String boundary = "----JavaFormBoundary" + UUID.randomUUID();
String body = "--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"file\"\r\n\r\n"
+ "string\r\n"
+ "--" + boundary + "--\r\n";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{apiDomainName}/rest/wab/v1/media?source=string"))
.header("accept", "application/json")
.header("authorization", "Basic <token>")
.header("x-xsrf-token", "string")
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());using var client = new HttpClient();
using var content = new MultipartFormDataContent();
content.Add(new StringContent("string"), "file");
var request = new HttpRequestMessage(
HttpMethod.Post,
"https://{apiDomainName}/rest/wab/v1/media?source=string");
request.Headers.Add("accept", "application/json");
request.Headers.TryAddWithoutValidation("authorization", "Basic <token>");
request.Headers.Add("x-xsrf-token", "string");
request.Content = content;
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();200 response:
[
{
"id": "string"
}
]
422 response:
{
"errors": [
{
"field": "",
"code": "",
"description": "Unprocessable Entity"
}
]
}
Get WhatsApp Message Example
GET /messages
curl 'https://{apiDomainName}/rest/wab/v1/messages?id=uuid' \
-H 'accept: application/json' \
-H 'authorization: Basic <token>'
const response = await fetch("https://{apiDomainName}/rest/wab/v1/messages?id=uuid", {
method: "GET",
headers: {
"accept": "application/json",
"authorization": "Basic <token>"
}
});
const message = await response.json();import requests
response = requests.get(
"https://{apiDomainName}/rest/wab/v1/messages?id=uuid",
headers={
"accept": "application/json",
"authorization": "Basic <token>",
},
)
message = response.json()<?php
$ch = curl_init("https://{apiDomainName}/rest/wab/v1/messages?id=uuid");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"accept: application/json",
"authorization: Basic <token>"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>
require "json"
require "net/http"
require "uri"
uri = URI("https://{apiDomainName}/rest/wab/v1/messages?id=uuid")
request = Net::HTTP::Get.new(uri)
request["accept"] = "application/json"
request["authorization"] = "Basic <token>"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
message = JSON.parse(response.body)import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://{apiDomainName}/rest/wab/v1/messages?id=uuid"))
.header("accept", "application/json")
.header("authorization", "Basic <token>")
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());using var client = new HttpClient();
var request = new HttpRequestMessage(
HttpMethod.Get,
"https://{apiDomainName}/rest/wab/v1/messages?id=uuid");
request.Headers.Add("accept", "application/json");
request.Headers.TryAddWithoutValidation("authorization", "Basic <token>");
var response = await client.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();200 response (MT):
{
"id":"53a3e147-0cc5-4001-874a-000000000000",
"source":"167141142137144145111111",
"destination":"+64123456789",
"direction":"MT",
"reference":"c15e301d-ab04-46a0-8a76-9bfb589a5df9",
"content":"{\"messaging_product\":\"whatsapp\",\"to\":\"+64123456789\",\"type\":\"template\",\"template\":{\"name\":\"sample_flight_confirmation\",\"language\":{\"policy\":\"\",\"code\":\"en_US\"},\"components\":[{\"type\":\"header\",\"parameters\":[{\"type\":\"document\",\"parameter_name\":\"\",\"text\":\"\",\"document\":{\"link\":\"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf\"}}]},{\"type\":\"body\",\"parameters\":[{\"type\":\"text\",\"parameter_name\":\"\",\"text\":\"Home\"},{\"type\":\"text\",\"parameter_name\":\"\",\"text\":\"Away\"},{\"type\":\"text\",\"parameter_name\":\"\",\"text\":\"December 23rd\"}]}]},\"biz_opaque_callback_data\":\"53a3e147-0cc5-4001-874a-000000000000\"}"
}
200 response (MO):
{
"id":"c1fc05e6-863e-43bf-86dc-000000000000",
"source":"+64123456789",
"destination":"167141142137144145111111",
"direction":"MO",
"reference":"",
"content":"{\"errors\":null,\"from\":\"+64123456789\",\"id\":\"wamid.e53f1ea5-bec5-4376-9470-b06a90e4b260\",\"order\":null,\"reaction\":null,\"text\":{\"preview_url\":false,\"body\":\"This is an automated reply from the mock API\"},\"timestamp\":\"1767739600\",\"type\":\"text\"}"
}
422 response:
{
"errors": [
{
"field": "",
"code": "",
"description": "Unprocessable Entity"
}
]
}
MO Callback
You will only receive MO messages if you have configured an MO callback URL within your API Configuration.
We recommend using https:// for your callback URLs.
When a MO message is received for you a POST request is made to the MO callback URL, this callback will include the MO message detail as a JSON object in the body of the POST request.
POST callback-url
{
"id": str:id,
"source": str:source,
"Destination": str:destination,
"content": obj:content,
}
These are notifications which will be included in content - WhatsApp Message Notification
| Message type | Description |
|---|---|
| Audio | Audio / voice note. |
| Button | Represents a button reply selected by the user in response to a button message sent by your business. |
| Context | Provides information about the message this message is replying to (threading). |
| Document | Document / file (e.g. PDF, etc.). |
| Errors | Lists any errors associated with sending a message, typically included when status is failed. |
| Identity | Indicates a change in user identity information, such as phone number or profile. |
| Image | An image sent by user. Payload includes media metadata. |
| Interactive | Interaction type messages (e.g. replies to interactive messages your business sent, like list-messages or buttons) |
| Referral | Metadata showing how the user came into contact with your business (e.g., ad click, QR code, link). |
| Sticker | Sticker media. |
| System | System-level notifications such as user identity/phone-number changes |
| text | Plain text message |
| Template | Represents a template message sent by the business, including name, language, and dynamic components. |
| Type | Specifies the kind of message or event, helping the backend parse content correctly (e.g., text, image, interactive, sent, delivered). |
| Video | A video sent by user. |
The value “base64” will be supplied for messages containing binary data. Content will be supplied encoded using base64, decoding content is needed to obtain the original data. NOTE: Regular SMS messages with GSM 7-bit or Unicode content will not supply this parameter.
DLR Callback
You will only receive DLR Statuses if you have configured a DLR callback URL within your API Configuration.
We recommend using https:// for your callback URLs.
When a DLR message is received for you a POST request is made to the DLR callback URL, this callback will include the DLR Status detail as a JSON object in the body of the POST request.
POST callback-url
{
"id": str:id,
"status": str:status,
"reference": str:reference,
}
DLR Message Status
The following are the status codes returned in DLRs that our message gateway supports.
| Status | Description |
|---|---|
| sent | Message has been sent by the carrier transport |
| received | Message has been received |
| rejected | The carrier rejected the message |
| expired | The carrier was unable to deliver the message in a specified amount of time. For instance when the phone was turned off. |
OpenAPI Specification
This API has been developed in accordance with the OpenAPI specification defined here.
The OpenAPI (Swagger) specification can be obtained from here
You can see code samples and a breakdown of the specification here.
Error Codes
The following is a list of common errors that can occur:
| Code | Description |
|---|---|
| 131026 | Message Undeliverable: Indicates a “Bad Request” (400), often because the recipient’s phone number is invalid, not on WhatsApp, or the recipient has not accepted new Terms of Service |
| 131048 | Spam Rate Limit Hit: Restrictions applied because too many messages were flagged or blocked as spam |
| 130429 | Rate Limit Hit / Throughput Reached: The maximum allowed Cloud API message limit has been exceeded |
| 131047 | Outside 24 Hour Window: Messages sent outside the 24 hour customer service window |
| 131056 | Message Rate Limit (Same Recipient): Too many messages sent to a single recipient in a short period |
| 131031 | Account Blocked/Locked: The account is blocked by Meta for policy violations |
| 131042 | Payment Issue: Payment account not linked to the WhatsApp Business Account or credit limit exceeded |
| 132001 | Template Does Not Exist: The message template used is not approved, has the wrong name, or is in the wrong language |
A comprehensive list of WhatsApp error codes is available: here
Help
Having trouble integrating with any of our services? Contact support@ezitxt.com and we’ll help you sort it out.