Skip to content
OmniChannels.ai

WhatsApp Business API

Send WhatsApp templates, text, media and interactive messages through one multipart endpoint, manage templates and batches, and track every recipient.

Base URL https://api.broadnet.meUpdated

All WhatsApp messages go through one endpoint, POST /whatsapp/message/sendbulk, where messageType selects the payload. This page shows how to send approved templates and session messages, manage templates, and track delivery per recipient.

Before you send#

  • Connect a WhatsApp Business Account. Onboarding uses Meta Embedded Signup. POST /whatsapp/generate-link returns an encrypted signup link (HTTP 201) for your account; the business admin opens it and completes Meta's flow (business account, phone number verification and display name). Our team supports you through Meta's review.
  • Have an approved template for any message that starts a conversation or is sent outside the customer service window.
  • Hold opt-in from each recipient, as Meta's policies require.

The customer service window#

When a customer messages you, a 24-hour customer service window opens. Inside it you can reply with any message type (text, media, interactive). Outside it, you can only send an approved template. Meta sets these rules and its pricing; check Meta's current documentation and rate card for the categories and markets you send to.

Send a template#

Set messageType=TEMPLATE, name the template and its language, and pass the body variable.

cURL

curl -X POST https://api.broadnet.me/whatsapp/message/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F batchId=0 \
  -F campaignName=order-updates \
  -F destinationNo=971500000000 \
  -F messageType=TEMPLATE \
  -F templateName=order_update \
  -F templateLanguage=en_US \
  -F bodyTemplateVariables=INV-400

Node.js

const form = new FormData();
form.append("batchId", "0");
form.append("campaignName", "order-updates");
form.append("destinationNo", "971500000000");
form.append("messageType", "TEMPLATE");
form.append("templateName", "order_update");
form.append("templateLanguage", "en_US");
form.append("bodyTemplateVariables", "INV-400");

const res = await fetch("https://api.broadnet.me/whatsapp/message/sendbulk", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.BROADNET_TOKEN}` }, // fetch sets the multipart boundary
  body: form,
});
console.log(await res.json());

Python

import os
import requests

fields = {
    "batchId": "0",
    "campaignName": "order-updates",
    "destinationNo": "971500000000",
    "messageType": "TEMPLATE",
    "templateName": "order_update",
    "templateLanguage": "en_US",
    "bodyTemplateVariables": "INV-400",
}
# Send every field as a multipart part (files=) rather than url-encoded (data=).
r = requests.post(
    "https://api.broadnet.me/whatsapp/message/sendbulk",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    files={k: (None, v) for k, v in fields.items()},
    timeout=30,
)
print(r.json())

PHP

<?php
$ch = curl_init("https://api.broadnet.me/whatsapp/message/sendbulk");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("BROADNET_TOKEN")],
    // An array (not a string) makes cURL send multipart/form-data.
    CURLOPT_POSTFIELDS => [
        "batchId" => "0",
        "campaignName" => "order-updates",
        "destinationNo" => "971500000000",
        "messageType" => "TEMPLATE",
        "templateName" => "order_update",
        "templateLanguage" => "en_US",
        "bodyTemplateVariables" => "INV-400",
    ],
]);
echo curl_exec($ch);
curl_close($ch);

The call queues the messages and returns at once with a batch summary:

Response

{
  "totalFiles": 1,
  "totalSuccess": 1,
  "totalFailed": 0,
  "totalDuplicates": 0,
  "batchId": "2609091405000000001",
  "fileResults": [
    {
      "fileName": "direct",
      "totalRecords": 1,
      "successCount": 1,
      "failedRecipients": [],
      "duplicateRecipients": []
    }
  ],
  "message": "Messages queued for delivery"
}

Store batchId. Per-recipient statuses arrive on your webhook and can be read from the bulk insights endpoint.

Request fields#

Which fields are required depends on messageType. These are the common ones:

Field Type Required Description
messageType string Yes TEXT, IMAGE, VIDEO, AUDIO, DOCUMENT, STICKER, LOCATION, CONTACTS, TEMPLATE, INTERACTIVE, REACTION or FLOW.
destinationNo string One of these two One or more numbers with country code, separated by commas, semicolons or new lines.
destinationFiles file One of these two A TXT, CSV or XLSX file of recipients. For personalised templates, one row per recipient with its variables.
batchId string No 0 starts a new batch.
campaignName string No Your label for reporting.
allowDuplicate string No false removes duplicate recipients.
content string Per type Text body (TEXT, up to 4,096 characters) or caption for media.
mediaUrl string Per type Public HTTPS URL of the media.
mediaFile file Per type Upload the media instead of linking it.
templateName string TEMPLATE Approved template name.
templateLanguage string TEMPLATE Template language code, for example en_US or ar.
bodyTemplateVariables string Per template Body variable value. Named parameters, currency and date-time values are passed as JSON.
headerTemplateVariables string Per template Header variable (text, or product details for product headers).
buttonsTemplateVariable string Per template Dynamic button value: URL suffix, coupon code or OTP code.
interactivePayload string (JSON) INTERACTIVE Meta's interactive object: buttons, list, CTA URL, location request and more.
contactsPayload string (JSON) CONTACTS Array of contact cards.
latitude, longitude, locationName, locationAddress string LOCATION Location pin.
replyToMessageId string No WhatsApp message ID (wamid) to quote-reply to, or to react to with REACTION.
emoji string REACTION The reaction emoji.
delay string No Throttle between messages.
scheduled, scheduleTime, gmt string No Schedule the batch, for example scheduleTime=2026-11-01 10:00:00.000, gmt=+04:00.
recurrence, repeatCount, recurrenceEndTime string No Recurring sends, for example DAILY.

For templates with several variables per recipient, upload a personalised destinationFiles file with one row per recipient. Confirm the column layout with our team for your first campaign.

Template variations#

Template feature Fields to add
Header image, video or document mediaUrl (overrides the header media)
Header text variable headerTemplateVariables
Dynamic URL button buttonsTemplateVariable=summer2026
Authentication (OTP) with copy-code button bodyTemplateVariables=482913 and buttonsTemplateVariable=482913
Coupon (copy code) buttonsTemplateVariable=SAVE20
Several buttons buttonsTemplateVariable as a JSON array with index, sub_type and value
Carousel carouselSendCards[0].bodyVariables[0] and similar per-card fields
Named parameter bodyTemplateVariables={"parameter_name":"order_id","text":"ORD-12345"}

Send session messages#

Inside the service window you can send free-form messages. Two examples:

Text

curl -X POST https://api.broadnet.me/whatsapp/message/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F batchId=0 \
  -F destinationNo=971500000000 \
  -F messageType=TEXT \
  -F campaignName=support \
  -F "content=Your order has shipped. Reply here if you need anything."

Reply buttons

curl -X POST https://api.broadnet.me/whatsapp/message/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F batchId=0 \
  -F destinationNo=971500000000 \
  -F messageType=INTERACTIVE \
  -F campaignName=support \
  -F 'interactivePayload={"type":"button","body":{"text":"Confirm your delivery slot?"},"action":{"buttons":[{"type":"reply","reply":{"id":"slot_ok","title":"Confirm"}},{"type":"reply","reply":{"id":"slot_change","title":"Change"}}]}}'

Interactive payloads follow Meta's interactive message format, which also covers lists, CTA URL buttons, location requests, product and catalog messages, and Flows.

Mark a message as read#

POST /whatsapp/message/read marks an inbound message as read. Add "typing": true to show a typing indicator while you prepare the reply.

cURL

curl -X POST https://api.broadnet.me/whatsapp/message/read \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "messageId": "wamid.HBgMOTcxNTAwMDAwMDAwFQIAEhgg", "typing": true }'

Track delivery#

Each recipient moves through SUBMITTED, SENT, DELIVERED and READ, or ends as FAILED or REJECTED with a reason. Statuses are pushed to your account's webhook. You can also read them per batch:

cURL

curl "https://api.broadnet.me/whatsapp/message/bulk-insights?batch_Id=2609091405000000001&status=FAILED&page=0&size=50" \
  -H "Authorization: Bearer $BROADNET_TOKEN"
Parameter Required Description
batch_Id Yes Batch ID returned by the send.
status No Filter, for example DELIVERED, READ or FAILED.
destination No Filter to one recipient.
search No Free-text search.
page, size No Zero-based page index and page size (default 0 and 10).

Manage batches#

Method Path Description
POST /whatsapp/message/all-bulk List batches with filters (multipart form fields such as page, size, status, campaignName).
GET /whatsapp/message/edit?batch_Id=… Batch details.
GET /whatsapp/message/pause?batch_Id=… Pause a batch.
GET /whatsapp/message/resume?batch_Id=… Resume a paused batch.
DELETE /whatsapp/message/abort?batch_Id=… Abort a batch.

Manage templates#

Templates are created through the API (or the console), reviewed by Meta, and then sent by name.

Method Path Description
POST /whatsapp/template Create a template (multipart).
GET /whatsapp/template/list List templates. Filters: name, status (APPROVED, PENDING, REJECTED, PAUSED), language, category, page, size.
GET /whatsapp/template?name=… Template details by name.
GET /whatsapp/template/grouped-by-category Templates grouped by category.
PUT /whatsapp/template/update/{WA_TEMPLATE_ID} Edit a template.
DELETE /whatsapp/template?name=… Delete a template by name.
POST /whatsapp/template/refresh?name=… Re-sync status and category from Meta.
POST /whatsapp/template/library Create a template from Meta's template library.

Main fields for POST /whatsapp/template:

Field Type Required Description
name string Yes Lowercase name, unique in your account.
languageType string Yes Language code, for example en_US.
category string Yes MARKETING, UTILITY or AUTHENTICATION.
templateType string Yes For example DEFAULT, UTILITY_DEFAULT, OTP, CATALOG or CALLING_PERMISSION.
headerFormat string No NONE, TEXT, IMAGE, VIDEO, DOCUMENT, LOCATION or PRODUCT.
headerText, headerFile string, file Per header Header text, or a sample media file.
bodyText string Yes (except OTP) Body with numbered placeholders.
bodyExample string (JSON) With variables Sample values, for example [["Sara","ORD-12345"]].
footerText string No Footer text.
buttonRequest string No Button definition, for example QUICK_REPLY:Track order or URL:Track|https://example.com/track/{{1}}|ORD123.
deliveryMode string OTP COPY_CODE, ONE_TAP or ZERO_TAP for authentication templates.
codeExpirationMinutes string No OTP expiry shown to the user.

New templates start as PENDING until Meta approves them. If you suspect a missed status update, call the refresh endpoint.

Other WhatsApp features in the API#

The WhatsApp section of the API also covers:

  • WhatsApp Flows: create, upload, publish and measure Flows (for example POST /whatsapp/flow/create, POST /whatsapp/flow/{WA_FLOW_ID}/publish, GET /whatsapp/flow/{WA_FLOW_ID}/metrics).
  • Catalogs: manage products and product sets on a connected catalog (for example POST /whatsapp/catalog/{WA_CATALOG_ID}/product, POST /whatsapp/catalog/connect) and read GET /whatsapp/message/catalog-insights.
  • QR links: create and manage QR codes that open a chat (/whatsapp/qr-links).
  • Business profile: read and update the profile (/whatsapp/business-profile) and upload a profile photo (POST /whatsapp/profile-photo).
  • Blocked users: list, block and unblock users (/whatsapp/block-users).

The full field reference for each is in the OpenAPI spec, available to customers on request. See SDKs and OpenAPI.

Next steps#

  • Webhooks: handle DELIVERED, READ and FAILED events.
  • RCS: reach Android users with rich cards, with SMS fallback.
  • Errors and limits: handle 502 errors that carry Meta's error code.
  • SDKs and OpenAPI: send WhatsApp messages with the TypeScript SDK.

Ready to send your first message?

Request test credentials. An engineer sets up your account, and test sends go to your own verified numbers.

Request test access