Broadcast campaign CRUD β create, edit, send, schedule, cancel, duplicate, per-recipient log, and aggregated funnel metrics.
Create a campaign
Create a new broadcast campaign. By default the campaign lands as DRAFT β call POST /campaigns/{id}/send when you're ready to fan it out. Pass send_now=true for an atomic create-and-send.
Audience modes:
ALL_CONTACTSβ every active contact reachable on the picked channelSEGMENTSβ pre-definedcontact_segmentsUUIDs (useGET /broadcast-segmentsto pick)RECIPIENT_LISTβ a pre-uploaded CSV recipient list (useGET /broadcast-recipient-liststo pick)CUSTOMβ manual phone list (dashboard-only in v1)
Template variables: when message_format_type=TEMPLATE, supply whatsapp_template_id + template_variable_mapping. The mapping is a flat object keyed by Meta placeholder index β values can be literal strings or {{column_name}} references into the picked recipient list / segment columns.
Create a campaign βΊ Request Body
namemessage_contentchannel_idThe inbox to send from. Must be an active channel in the caller's org.
descriptioncampaign_typemessage_format_typemedia_urlSet to the URL returned by POST /campaigns/media when the broadcast carries an image / video / document.
media_typeaudience_typetarget_segmentsRequired when audience_type=SEGMENTS. UUIDs of contact_segments rows.
recipient_list_idRequired when audience_type=RECIPIENT_LIST.
whatsapp_template_idRequired when message_format_type=TEMPLATE. The template must be APPROVED.
Flat map keyed by Meta placeholder index ("1", "2", β¦).
statusscheduled_atRequired when status=SCHEDULED. Must be in the future.
timezonesend_nowAtomic create + send shortcut. When true: status is forced to DRAFT, scheduled_at is forced to null, and the SendNow pipeline runs synchronously after persistence.
Create a campaign βΊ Responses
Campaign created (or created + sent when send_now=true).
successGet campaign detail
Returns the enriched campaign detail β channel chip, segment summary, picked recipient list (with column metadata for variable mapping), picked WhatsApp template (with raw components for preview), variable mapping, schedule, lifecycle timestamps, and can_edit/can_send/can_cancel/can_delete action hints driven by the current status.
path Parameters
broadcast_idCampaign (broadcast) UUID, scoped to the caller's organization. Cross-tenant IDs return 404 campaign not found (same shape as missing to avoid id enumeration).
Get campaign detail βΊ Responses
Campaign detail.
successDelete a campaign
Soft-delete (sets deleted_at + deleted_by). SENDING campaigns can't be deleted directly β call POST /campaigns/{id}/cancel first.
path Parameters
broadcast_idCampaign (broadcast) UUID, scoped to the caller's organization. Cross-tenant IDs return 404 campaign not found (same shape as missing to avoid id enumeration).
Delete a campaign βΊ Responses
Campaign deleted.
successmessagedataUpdate a campaign
Partial update. Only DRAFT and SCHEDULED campaigns are editable; anything past that returns 409 campaign no longer editable. Audience / template / schedule fields support the same validation rules as POST /campaigns.
Pass send_now=true for an atomic edit-and-send.
path Parameters
broadcast_idCampaign (broadcast) UUID, scoped to the caller's organization. Cross-tenant IDs return 404 campaign not found (same shape as missing to avoid id enumeration).
Update a campaign βΊ Request Body
namedescriptioncampaign_typemessage_contentmessage_format_typemedia_urlmedia_typechannel_idaudience_typetarget_segmentsrecipient_list_idwhatsapp_template_idstatusscheduled_attimezonesend_nowSame shortcut as on Create. When true the patch forces DRAFT + scheduled_at=null then runs SendNow.
Update a campaign βΊ Responses
Campaign updated.
successSend a campaign
Flips a DRAFT campaign to SENDING and kicks off the SendNow pipeline. Empty body OK β the v1 surface always sends immediately. The Kafka worker re-checks campaign status before processing each recipient, so calling this endpoint twice in close succession is safe.
path Parameters
broadcast_idCampaign (broadcast) UUID, scoped to the caller's organization. Cross-tenant IDs return 404 campaign not found (same shape as missing to avoid id enumeration).
Send a campaign βΊ Request Body optional
send_atSend a campaign βΊ Responses
Campaign now SENDING.
successLean envelope returned by send / cancel actions. Carries enough for the mobile UI to update the row inline without re-fetching the full detail.
Cancel a campaign
Flips a SENDING or SCHEDULED campaign to CANCELLED. The Kafka consumer re-checks status before processing each recipient, so flipping the flag halts the blast (in-flight messages already on the wire still deliver).
path Parameters
broadcast_idCampaign (broadcast) UUID, scoped to the caller's organization. Cross-tenant IDs return 404 campaign not found (same shape as missing to avoid id enumeration).
Cancel a campaign βΊ Responses
Campaign cancelled.
successLean envelope returned by send / cancel actions. Carries enough for the mobile UI to update the row inline without re-fetching the full detail.
Duplicate a campaign
Clones content + audience + template + variable mapping into a new DRAFT row. Body optional β when omitted the new name defaults to <original> (Copy), mirroring the dashboard duplicate UX.
path Parameters
broadcast_idCampaign (broadcast) UUID, scoped to the caller's organization. Cross-tenant IDs return 404 campaign not found (same shape as missing to avoid id enumeration).
Duplicate a campaign βΊ Request Body optional
new_nameDuplicate a campaign βΊ Responses
New draft campaign created.
successList campaign recipients (delivery log)
Per-recipient delivery log used by the campaign detail screen's See Log section. Response includes a summary block (same funnel shape as /metrics) so the header card can render the recipient totals without a second call.
path Parameters
broadcast_idCampaign (broadcast) UUID, scoped to the caller's organization. Cross-tenant IDs return 404 campaign not found (same shape as missing to avoid id enumeration).
query Parameters
statusFilter by recipient delivery status.
qPhone-number substring (case-insensitive).
page1-indexed page number. Capped at 500 to bound deep-scan cost.
limitRows per page. Capped at 100.
List campaign recipients (delivery log) βΊ Responses
Recipients page + summary.
successGet campaign metrics (funnel)
Aggregated send funnel + per-channel breakdown sourced from broadcasts.total_* columns + the broadcast_channel_stats table. Same numbers powering the dashboard's /broadcasts/{id}/logs/summary card. delivery_rate = sent / total, open_rate = read / delivered (both pre-computed server-side so the client doesn't repeat the math).
path Parameters
broadcast_idCampaign (broadcast) UUID, scoped to the caller's organization. Cross-tenant IDs return 404 campaign not found (same shape as missing to avoid id enumeration).
Get campaign metrics (funnel) βΊ Responses
Campaign funnel.
successUpload campaign media
Multipart upload for the broadcast's media_url field. Single file field (also accepts files for clients that pluralise β first entry wins). 25 MB cap matches WhatsApp Business Cloud API's per-message media limit.
Allowed MIME types: image/jpeg, image/png, image/gif, image/webp, video/mp4, video/3gpp, video/quicktime, application/pdf, MS Office documents, text/plain, text/csv.
Upload campaign media βΊ Responses
Media uploaded.
success