Create a campaign
A campaign is a /v1 broadcast; the id works on /v1/broadcasts/{broadcastId}. Runs POST /v1/broadcasts with the sender resolved from from. A repeated idempotencyKey answers 409 conflict with the original in details.campaign. A channel the resolved sender does not carry (smart: no channel at all) is refused at creation with 409 no_channel, as on POST /v2/messages, rather than created and failed at send. from with a channel it does not carry (a sms campaign from: "sms_oneway") is that same 409 no_channel, in the words POST /v2/messages uses (details.connected, and sms vs sms_oneway told apart); channel only picks between senders that share an address, it never makes an existing address 404.
Authorization
AuthorizationheaderrequiredBearer YOUR_API_KEY. Create a key in the dashboard.
Body
application/json
namestringrequiredName of the broadcast campaign.
channelstringrequiredBroadcast delivery channel. Use 'smart' for per-contact intelligent routing.
One ofsmartsmssms_onewaywhatsapptelegramemailmessageTypestringType of message for broadcast.
One oftextimagevideoaudiodocumenttemplateDefaulttexttextstringText content or caption. Supports template variables: {{name}}, {{1}}, etc.
contentobjectContent for non-text broadcast message types.
8 properties
mediaUrlstringURL of the media file.
mediaIdstringMedia ID if already uploaded.
mimeTypestringMIME type of the media.
filenamestringFilename for documents.
templateIdstringTemplate ID for template messages.
templateVariablesobjectDefault body variables (can be overridden per contact). Key them to match the template body: by position (
1,2, ...) for positional templates, or by name (e.g.customer_name) for named templates. Zavu detects the template's format and sends the correct payload to Meta. Do not mix positional and named keys.1 properties
{key}string
templateButtonVariablesobjectDefault button variables for dynamic URL/OTP buttons. Keys are the button index (0, 1, 2). Per-contact values override these.
1 properties
{key}string
templateHeaderVariablesobjectDefault value for a text-header variable, keyed by
1(can be overridden per contact). If omitted, Zavu resolves the header fromtemplateVariablesby the header placeholder's name.1 properties
{key}string
emailSubjectstringEmail subject line. Required for email broadcasts.
emailHtmlBodystringHTML body for email broadcasts.
scheduledAtstring<date-time>Schedule the broadcast for future delivery.
metadataobject1 properties
{key}string
idempotencyKeystringIdempotency key to prevent duplicate broadcasts.
fromstringThe address that sends the campaign (
GET /v2/channels). The project default when omitted. Resolved likefromonPOST /v2/messages, with the campaign'schannelas the transport (none forsmart).
Responses
201Created as `draft`.
campaignobjectrequiredA campaign. The same object as a /v1 broadcast: its
idworks on/v1/broadcasts/{broadcastId}.26 properties
idstringrequirednamestringrequiredstatusstringrequiredCurrent status of the campaign.
pending_review: in the automated content review.pending_admin_review: the automated review passed and it waits for a person, which is where every channel but a WhatsApp campaign on an approved template goes.rejected: the review refused it; edit it and send again, or escalate.scheduledandsendingfollow approval.One ofdraftpending_reviewpending_admin_reviewapprovedrejectedescalatedrejected_finalscheduledsendingpausedcompletedcancelledfailedchannelstringrequiredBroadcast delivery channel. Use 'smart' for per-contact intelligent routing.
One ofsmartsmssms_onewaywhatsapptelegramemailmessageTypestringrequiredType of message for broadcast.
One oftextimagevideoaudiodocumenttemplatetextstringcontentobjectContent for non-text broadcast message types.
8 properties
mediaUrlstringURL of the media file.
mediaIdstringMedia ID if already uploaded.
mimeTypestringMIME type of the media.
filenamestringFilename for documents.
templateIdstringTemplate ID for template messages.
templateVariablesobjectDefault body variables (can be overridden per contact). Key them to match the template body: by position (
1,2, ...) for positional templates, or by name (e.g.customer_name) for named templates. Zavu detects the template's format and sends the correct payload to Meta. Do not mix positional and named keys.1 properties
{key}string
templateButtonVariablesobjectDefault button variables for dynamic URL/OTP buttons. Keys are the button index (0, 1, 2). Per-contact values override these.
1 properties
{key}string
templateHeaderVariablesobjectDefault value for a text-header variable, keyed by
1(can be overridden per contact). If omitted, Zavu resolves the header fromtemplateVariablesby the header placeholder's name.1 properties
{key}string
emailSubjectstringtotalContactsintegerrequiredTotal number of contacts in the broadcast.
pendingCountintegersendingCountintegersentCountintegerRecipients whose message the provider accepted, without a confirmed delivery yet. Channels that never report delivery keep their recipients here.
deliveredCountintegerRecipients with confirmed delivery to the device.
failedCountintegerestimatedCostnumberEstimated total cost in USD.
reservedAmountnumberAmount reserved from balance in USD.
actualCostnumberActual cost so far in USD.
scheduledAtstring<date-time>startedAtstring<date-time>completedAtstring<date-time>metadataobject1 properties
{key}string
createdAtstring<date-time>requiredupdatedAtstring<date-time>reviewResultobjectAI content review result.
5 properties
scorenumberContent safety score from 0.0 to 1.0, where 1.0 is completely safe.
categoriesstring[]Policy categories violated, if any.
reasoningstringExplanation of the review decision.
reviewedAtstring<date-time>flaggedContentstring[]Problematic text fragments, if any.
reviewAttemptsintegerNumber of review attempts (max 3).
fromstringThe address the campaign is sent from, for its
channel(the sender's first address whenchannelissmart).
400Invalid body (`details.errors`).
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring
401Unauthorized.
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring
403`kyb_required`: `channel: "sms_oneway"` on an account required to verify its business before using one-way SMS, until that verification is approved. One-way SMS needs no verification by default.
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring
404`from` names no address of this project (`details.from`).
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring
409`no_channel`: no `from` and no default, or the sender has no `channel` transport (`details.channel`, `details.connect`, `details.connected`, the same answer as `POST /v2/messages` with that `channel`). `ambiguous_from`, or `conflict` (repeated `idempotencyKey`; the original is in `details.campaign`).
codestringrequiredmessagestringrequireddetailsobjectMachine-readable context. Keys that mean the same thing everywhere: -
errors: present on every400 invalid_requestfor an invalid body or query parameter,[{path, message, ...}],pathnaming the field (["to"],["contacts", 2, "recipient"],["limit"]). -recommendation: one sentence saying what to do next. -dashboardUrl: the dashboard screen that fixes it. -connect: on409 no_channel, the channels this project can connect to reach the recipient, each{type, request, note, available, dashboardUrl?};requestis the exact call (POST /v2/channelswith its body, orPOST /v2/numbers), or null for a channel connected from the dashboard (WhatsApp, Instagram, Messenger).available: falsesays why innote(one-way SMS closed until business verification is approved). -address/from: the address the error is about, under the name the request used for it.1 properties
errorsobject[]3 properties
pathobject[]requiredmessagestringrequiredcodestring