Automations
Send one message to many contacts at once, now or at a scheduled time, with per-recipient variables, segments and delivery tracking.
A broadcast sends one message from one account to a list of recipients: an order update to everyone who bought this week, a launch announcement to a tag, an event reminder to a segment. You create it as a draft, add recipients, then send it now or schedule it. Pozy tracks every recipient as sent, delivered, read or failed.
Broadcasts work on WhatsApp, SMS, iMessage, Instagram, Facebook, X, Bluesky and Slack. Telegram is coming soon. WhatsApp broadcasts send approved templates; the others send text.
#Create, fill and send
#Create the draft
curl -X POST https://api.pozy.ai/v1/broadcasts \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "6650c1e2a3b4c5d6e7f80911",
"accountId": "6650c1e2a3b4c5d6e7f80a44",
"platform": "whatsapp",
"name": "Black Friday early access",
"template": {
"name": "early_access",
"language": "en",
"components": [{ "type": "body", "parameters": [{ "type": "text", "text": "{{1}}" }, { "type": "text", "text": "{{2}}" }] }],
"variableMapping": { "1": { "field": "name" }, "2": { "field": "custom", "customValue": "BF-EARLY-20" } }
},
"segmentFilters": { "tags": ["vip"], "isSubscribed": true }
}'const res = await fetch("https://api.pozy.ai/v1/broadcasts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
profileId: "6650c1e2a3b4c5d6e7f80911",
accountId: "6650c1e2a3b4c5d6e7f80a44",
platform: "whatsapp",
name: "Black Friday early access",
template: {
name: "early_access",
language: "en",
components: [{ type: "body", parameters: [{ type: "text", text: "{{1}}" }, { type: "text", text: "{{2}}" }] }],
variableMapping: { "1": { field: "name" }, "2": { field: "custom", customValue: "BF-EARLY-20" } },
},
segmentFilters: { tags: ["vip"], isSubscribed: true },
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
const broadcastId = data.broadcast.id;import os
import requests
H = {"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"}
created = requests.post(
"https://api.pozy.ai/v1/broadcasts",
headers=H,
json={
"profileId": "6650c1e2a3b4c5d6e7f80911",
"accountId": "6650c1e2a3b4c5d6e7f80a44",
"platform": "whatsapp",
"name": "Black Friday early access",
"template": {"name": "early_access", "language": "en", "variableMapping": {"1": {"field": "name"}}},
"segmentFilters": {"tags": ["vip"], "isSubscribed": True},
},
timeout=30,
).json()
broadcast_id = created["broadcast"]["id"]#Add recipients
POST /v1/broadcasts/{broadcastId}/recipients with one of:
useSegment: trueto add every contact matchingsegmentFilterscontactIdswith Pozy contact idsphoneswith E.164 numbers (WhatsApp, SMS). Pozy creates contacts for numbers it has not seen
curl -X POST https://api.pozy.ai/v1/broadcasts/6650c1e2a3b4c5d6e7f80a88/recipients \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "useSegment": true }'The response counts added and skipped. Duplicates and contacts with no channel on this account are skipped. Call it several times to combine sources.
#Send or schedule
POST /v1/broadcasts/{id}/sendstarts delivery now.POST /v1/broadcasts/{id}/schedulewithscheduledAt(ISO 8601, in the future) sends it later. Call it again to move the date.POST /v1/broadcasts/{id}/cancelstops a scheduled broadcast.
#Messages and templates
| Platform | What to send |
|---|---|
template with an approved template's name and language, plus components and variableMapping when it has placeholders |
|
| SMS | message.text, and optionally message.attachments for MMS media (JPEG, PNG, GIF, WEBP, MP4 or 3GPP, public URLs, about 1 MB in total) |
| Everything else | message.text |
variableMapping fills numbered placeholders ({{1}}, {{2}}) per recipient at send time:
field |
Becomes |
|---|---|
name |
The contact's name, or "there" when it is empty |
phone |
The recipient's number |
email, company |
The contact's email or company |
custom |
The fixed customValue, the same for everyone |
The number of variableMapping entries must equal the number of placeholders in the template body. A mismatch makes WhatsApp reject each send with a parameter-count error. Named placeholders are not supported; use numbered ones.
#Segments
segmentFilters describes who useSegment adds:
| Field | Matches |
|---|---|
tags |
Contacts with these tags |
isSubscribed |
true to leave out people who opted out |
customFields |
Exact custom field values by slug, type included (5 does not match "5"). Every key must match |
Set isSubscribed: true on every marketing broadcast.
#Platform rules that cap delivery
- WhatsApp messaging limits. A number's tier caps how many unique people it can start conversations with per day. A newly connected number starts at 250 a day, and recipients above the cap do not deliver. Check the number's tier before a large send; see WhatsApp phone numbers.
- Instagram and Facebook. A broadcast only reaches people who messaged the account in the last 24 hours. Message tags are not usable:
HUMAN_AGENTis for replies typed by a person, and the others were retired. - SMS in the US needs a registered 10DLC campaign. See 10DLC.
- Costs. Each recipient counts as one outbound message. WhatsApp template fees are charged by WhatsApp on top. See WhatsApp pricing and Pricing.
#Track results
GET /v1/broadcasts/{id} shows status (draft, scheduled, sending, completed, failed, cancelled) and the counters recipientCount, sentCount, deliveredCount, readCount and failedCount.
GET /v1/broadcasts/{id}/recipients lists each recipient with status (pending, sent, delivered, read, failed) and timestamps. Failed rows carry error, errorCode and errorExplanation. Filter with status=failed to see what went wrong.
Every message also arrives as message.sent with sentVia: "broadcast" and the broadcastId, followed by delivery and read events where the platform reports them.
#Errors
| Error | Cause |
|---|---|
400 "Broadcast has no recipients" |
Send or schedule before adding recipients |
400 "Cannot send broadcast in ... status" |
The broadcast is already sending or done. Check status |
Per-recipient failed |
Usually a template mismatch, an opted-out number or a number that is not on WhatsApp. The call itself still succeeds |
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/broadcasts |
List broadcasts |
POST /v1/broadcasts |
Create broadcast draft |
GET /v1/broadcasts/{broadcastId} |
Get broadcast details |
PATCH /v1/broadcasts/{broadcastId} |
Update broadcast |
DELETE /v1/broadcasts/{broadcastId} |
Delete broadcast |
POST /v1/broadcasts/{broadcastId}/send |
Send broadcast now |
POST /v1/broadcasts/{broadcastId}/schedule |
Schedule broadcast for later |
POST /v1/broadcasts/{broadcastId}/cancel |
Cancel broadcast |
GET /v1/broadcasts/{broadcastId}/recipients |
List broadcast recipients |
POST /v1/broadcasts/{broadcastId}/recipients |
Add recipients to a broadcast |