Broadcasts
One campaign.Thousands of contacts.
Build the list in batches of a thousand, give every recipient variables of its own, and send on the channel that fits — or let each contact be reached the way that works for them. The cost is reserved before the first message leaves, and the run is readable while it happens.
Channels a broadcast can take
Six values, and no others. smart decides per contact, so a smart campaign answers to whatever the channel it picks asks for — it can route to SMS or to email.
What gates a send
Drafting is free. Sending is read.
No verification stands between you and a send. What stands there is the content: every broadcast is read before it goes out. Pick a channel and read what it asks of you, what reads the content, and what a refused send returns.
No verification. Each contact is then sent as an ordinary message, so the daily ceiling applies per recipient — and so does the 10DLC campaign carriers require on US and Canadian numbers.
Automated content review first, then a person clears it before anything is sent.
The review rejects it, the broadcast lands on rejected, and the reason sits on it. Edit the copy and retry the review, or escalate it to a person.
None of this touches a draft. Create the broadcast, add every recipient, rewrite the copy — nothing is read, nothing is charged. The checks run at the send.
The state machine
Twelve states. Walk them.
Every status a broadcast can report, and every move between them. Click a status to read it; press a transition to take it.
Draft
Created, not submitted. It costs nothing, asks for no verification, and can be edited and refilled for as long as you want.
What it accepts
- PATCH /v1/broadcasts/{id} — rewrite the copy
- POST /v1/broadcasts/{id}/contacts — add up to 1,000 recipients per call
- DELETE /v1/broadcasts/{id} — throw it away
- POST /v1/broadcasts/{id}/send — submit it
Every move above fires the broadcast.status_changed webhook, so none of it has to be polled to be noticed.
One campaign, one message each
Every recipient carries its own variables.
A batch is a list of recipients, each with a templateVariables object of its own. Edit the body or any row and watch what that person actually receives — and what the endpoint would answer.
added
+14155551234
Hi John, order ORD-001 shipped today.
added
+5491133445566
Hi Lucía, order ORD-002 shipped today.
added
mara@example.com
Hi Mara, order ORD-003 shipped today.
3
added
0
duplicates
0
invalid
Up to 1,000 recipients per request, called as many times as the list needs. Duplicates and invalid entries come back counted, with a reason each, rather than dropped in silence. WhatsApp templates take two more objects per recipient: templateButtonVariables, keyed by button index, and templateHeaderVariables, keyed by 1.
While it runs
Counts, cost and a finish time.
One call answers with the whole picture. Drag the run forward, or cancel it mid-flight and watch what becomes of the recipients that had not left yet.
48%
percentComplete
5,000 recipients
startedAt 10:30 · eta 10:45
2,500
pending
100
sending
2,352
delivered
48
failed
0
skipped
$75.00
estimatedCost
$75.00
reservedAmount
$35.28
actualCost
The estimated cost is reserved from your balance when the send starts, so a run cannot get halfway through and run out of money. actualCost accrues on what was delivered, and the difference goes back.
Four calls
Broadcasts are in the SDK.
Create it, fill it, send it, watch it. Real methods in TypeScript and Python, and the same four steps over plain HTTP.
import Zavudev from '@zavudev/sdk';
const zavu = new Zavudev({ apiKey: process.env['ZAVUDEV_API_KEY'] });
// channel: smart | sms | sms_oneway | whatsapp | telegram | email
const broadcast = await zavu.broadcasts.create({
name: 'October update',
channel: 'smart',
text: 'Hi {{name}}, order {{order_id}} shipped today.',
});
console.log(broadcast.id, broadcast.status); // -> "draft"Write it once. Reach all of them.
Start free, no card. Drafts cost nothing — verification is only asked for at the send, and never on WhatsApp.