Send a WhatsApp message
curl --request POST \
--url https://backend.botcadence.com/organizations/{organization_id}/projects/{project_id}/broadcasts/{broadcast_id}/messages \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"to": "<string>"
}
'const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({to: '<string>'})
};
fetch('https://backend.botcadence.com/organizations/{organization_id}/projects/{project_id}/broadcasts/{broadcast_id}/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://backend.botcadence.com/organizations/{organization_id}/projects/{project_id}/broadcasts/{broadcast_id}/messages"
payload = { "to": "<string>" }
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)WhatsApp
Send a WhatsApp message
Send one WhatsApp message through a broadcast and track the recipient in Botcadence
POST
/
organizations
/
{organization_id}
/
projects
/
{project_id}
/
broadcasts
/
{broadcast_id}
/
messages
Send a WhatsApp message
curl --request POST \
--url https://backend.botcadence.com/organizations/{organization_id}/projects/{project_id}/broadcasts/{broadcast_id}/messages \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"to": "<string>"
}
'const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({to: '<string>'})
};
fetch('https://backend.botcadence.com/organizations/{organization_id}/projects/{project_id}/broadcasts/{broadcast_id}/messages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://backend.botcadence.com/organizations/{organization_id}/projects/{project_id}/broadcasts/{broadcast_id}/messages"
payload = { "to": "<string>" }
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)Send one WhatsApp message to one recipient and record it under an existing broadcast. The request does not start the broadcast or send to its saved contact list. API recipients appear in that broadcast’s recipient history with their delivery status.
Required scope:
If the attached template has no variables, send only
Use either
For example, send a location with:
End-to-end setup
- In Botcadence, connect a WhatsApp number to the project.
- Create a WhatsApp broadcast and select its sender. Save the broadcast. It can stay in draft; this API call does not launch it.
- For template sends, attach an approved WhatsApp template to the broadcast. The template’s named variables are the keys you pass in
data. - Create a project API key with the
whatsapp:createscope. Keep the key on your server. - Open the broadcast in the dashboard and copy its ID from the URL. Copy the organization and project IDs into the request below as well.
Authentication
Send the project API key as a Bearer token. See API authentication.Authorization: Bearer bot_live_YOUR_KEY
whatsapp:create
Path parameters
string
required
Organization that owns the project and API key.
string
required
Project containing the broadcast and connected WhatsApp number.
string
required
Existing broadcast used to track this send. The broadcast’s contact list is not sent.
Request body
Use one of two request shapes:- Broadcast template: omit
typeand pass the recipient into. Pass named template variables indata. You cannot choose another template in the request. - Typed message: pass
typeand a matchingpayload. Do not includedatain a typed message request.
string
required
Recipient phone number in international format, such as
+14155552671. Spaces, parentheses, periods, and hyphens are removed.object
Named values for variables in the broadcast’s attached template. The keys must match the template’s variables exactly. Media headers use
header_media_url; location headers use header_location with latitude and longitude. Omit this field when the template has no variables.string
Typed message:
text, image, video, audio, voice, document, sticker, location, contacts, interactive, reaction, product, product_list, or catalog.object
Fields for the selected message type. Media uses a publicly reachable HTTPS URL; this API does not upload files.
Example 1: send the broadcast’s approved template
Suppose the approved template attached to the broadcast has the named variablesfirst_name and order_id. Send those values in data; the API gets the template name, language, channel, and sender from the broadcast settings.
curl -X POST \
"https://backend.botcadence.com/organizations/ORG_ID/projects/PROJECT_ID/broadcasts/BROADCAST_ID/messages" \
-H "Authorization: Bearer $BOTCADENCE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-confirmation" \
-d '{
"to": "+14155552671",
"data": {
"first_name": "Alex",
"order_id": "ORD-1042"
}
}'
to, or pass an empty data object. A template send can be used when the free-form messaging window is closed, provided the template is approved and the account is eligible to send it.
Example 2: send a text message
Free-form messages such as text require an open WhatsApp messaging window for the recipient.curl -X POST \
"https://backend.botcadence.com/organizations/ORG_ID/projects/PROJECT_ID/broadcasts/BROADCAST_ID/messages" \
-H "Authorization: Bearer $BOTCADENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+14155552671",
"type": "text",
"payload": {
"body": "Hi Alex, your order is ready.",
"preview_url": true
}
}'
preview_url is optional and defaults to true.
Example 3: send an image or document from a URL
The URL must use HTTPS and Meta must be able to fetch it without signing in. For a document,filename and caption are optional.
curl -X POST \
"https://backend.botcadence.com/organizations/ORG_ID/projects/PROJECT_ID/broadcasts/BROADCAST_ID/messages" \
-H "Authorization: Bearer $BOTCADENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+14155552671",
"type": "image",
"payload": {
"link": "https://cdn.example.com/order-1042.png",
"caption": "Your order is ready"
}
}'
curl -X POST \
"https://backend.botcadence.com/organizations/ORG_ID/projects/PROJECT_ID/broadcasts/BROADCAST_ID/messages" \
-H "Authorization: Bearer $BOTCADENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+14155552671",
"type": "document",
"payload": {
"url": "https://cdn.example.com/invoices/ORD-1042.pdf",
"filename": "invoice-ORD-1042.pdf",
"caption": "Your invoice"
}
}'
link or url; both are accepted. The API forwards the URL to WhatsApp and does not store a copy of the file.
Other message types
All typed messages use the same endpoint.payload contains the fields for the selected type.
type | Example payload | Notes |
|---|---|---|
video | {"link":"https://cdn.example.com/clip.mp4","caption":"Watch this"} | HTTPS URL; caption optional. |
audio | {"link":"https://cdn.example.com/audio.mp3"} | HTTPS URL. |
voice | {"link":"https://cdn.example.com/voice.ogg"} | Sent as an audio voice note. |
sticker | {"link":"https://cdn.example.com/sticker.webp"} | HTTPS URL. |
location | {"latitude":37.7898,"longitude":-122.3942,"name":"Ferry Building","address":"San Francisco"} | Latitude must be -90 to 90; longitude -180 to 180. |
contacts | {"contacts":[{"name":{"formatted_name":"Ada Lovelace","first_name":"Ada","last_name":"Lovelace"},"phones":[{"phone":"+14155552671","type":"CELL"}]}]} | Provide a non-empty array in WhatsApp contact format. |
interactive | {"type":"button","body":{"text":"Confirm your order?"},"action":{"buttons":[{"type":"reply","reply":{"id":"confirm","title":"Confirm"}}]}} | Supply a WhatsApp interactive object with type and action. |
reaction | {"message_id":"wamid.MESSAGE_TO_REACT_TO","emoji":"👍"} | message_id is the WhatsApp message being reacted to. |
product | {"body":{"text":"View this item"},"action":{"catalog_id":"CATALOG_ID","product_retailer_id":"SKU-1042"}} | Uses the WhatsApp catalog connected to the sender. |
product_list or catalog | {"body":{"text":"Choose an item"},"action":{"catalog_id":"CATALOG_ID","sections":[{"title":"Featured","product_items":[{"product_retailer_id":"SKU-1042"}]}]}} | Uses catalog IDs and product retailer IDs from Meta. |
{
"to": "+14155552671",
"type": "location",
"payload": {
"latitude": 37.7898,
"longitude": -122.3942,
"name": "Ferry Building",
"address": "San Francisco"
}
}
Idempotent retries
You can send anIdempotency-Key header of 1–255 characters. If the original request included the header, retry a timeout with the same key and request body. For 24 hours, repeating the same key and request returns the saved result instead of sending again. Reusing a key with a different request returns 409 Conflict. If the provider outcome is still being resolved, the API returns 202 Accepted while it waits for a delivery status update. Without an idempotency key on the original request, a timeout retry may send a duplicate.
Idempotency-Key: order-1042-confirmation
Response
When Meta accepts the request, the API returns the internal message ID, recipient, send status, and Meta’s message ID when available. Acceptance does not mean the recipient has received or read the message; delivery updates arrive later and appear in the broadcast recipient history.{
"status": "success",
"message": "WhatsApp message accepted by Meta",
"data": {
"message_id": "665f1a2b3c4d5e6f7a8b9c0d",
"broadcast_id": "665f1a2b3c4d5e6f7a8b9c0e",
"to": "+14155552671",
"type": "template",
"status": "sent",
"provider_message_id": "wamid.HBgLMTQxNTU1NTI2NzEVAgARGBI..."
},
"status_code": 200
}
Limits and errors
An active plan, available WhatsApp send quota, a connected sender, and messaging eligibility are required. A successful Meta acceptance consumes one WhatsApp send. If Meta definitely rejects the request, the API marks it failed and releases the reserved send. If the provider outcome is uncertain and the original request includedIdempotency-Key, retry with the same key while the API resolves the status webhook. Otherwise, check the broadcast history before deciding whether to retry.
| Status | Meaning |
|---|---|
400 | Invalid request, unavailable sender, closed messaging window for a typed message, invalid template, or recipient opted out. |
401 | API key is missing, invalid, or revoked. |
402 | Plan is inactive or WhatsApp send quota is exhausted. |
403 | API key belongs to another organization/project or lacks whatsapp:create. |
404 | Broadcast does not exist in the organization and project. |
409 | Idempotency key was already used with a different request. |
202 | A send using this idempotency key is processing or its provider outcome is still being resolved. |
503 | Provider outcome is unknown. A repeated request with the same idempotency key returns 202 until the webhook resolves it. |

