تخطَّ إلى المحتوى

Campaigns

هذا المحتوى غير متوفر بلغتك بعد.

A campaign sends one approved template to many people, paced against WhatsApp’s daily messaging allowance.

Creating and starting are separate calls. Building a recipient list takes several requests, and a create that also sent would make a half-uploaded list unrecoverable.

Creates a campaign in draft. Nothing is sent.

Scope: campaigns:write · Accepts Idempotency-Key

{
"name": "Eid offer",
"template": "eid_promo",
"account": "Main"
}
FieldNotes
nameRequired. For your own records.
templateTemplate name. Or template_id. Must be APPROVED.
accountWhich number to send from. Defaults to the template’s, then the organization default.

Adds recipients. Call it repeatedly for a large list.

Scope: campaigns:write · Accepts Idempotency-Key

{
"recipients": [
{
"to": "+966500000001",
"name": "Sara",
"parameters": { "name": "Sara", "code": "EID20" }
},
{
"to": "+966500000002",
"name": "Omar",
"parameters": { "name": "Omar", "code": "EID20" }
}
]
}

Up to 1000 per call. Each entry needs to; parameters fills the template’s variables for that person.

201
{ "added": 2, "total_recipients": 2, "campaign_id": "5d4c3b2a-..." }

A batch is written in one transaction: if one entry is rejected, none of them are stored, so the campaign never holds a list you believe it does not have. The validation error names the offending index (recipients[41].to), because nobody can find the bad row in a thousand otherwise.

Recipients can only be added while a campaign is draft or paused. Adding to a running campaign would race the workers draining the queue, so whether the new rows went out would depend on timing.

Starts sending, or arms the campaign for later.

Scope: campaigns:write · Accepts Idempotency-Key

{ "send_mode": "spread", "scheduled_at": "2026-08-25T09:00:00Z" }

Both fields are optional. With no body, it starts now with spread.

send_modeBehaviour
spread (default)Recipients who do not fit inside today’s allowance are carried into following days. Nobody is dropped.
today_onlySend as many as today’s allowance permits and skip the rest, counted in skipped.

scheduled_at in the future arms the campaign; the processor picks it up when the time arrives.

200 — started
{ "status": "processing", "queued": 480, "skipped": 0 }
200 — armed
{ "status": "scheduled", "scheduled_at": "2026-08-25T09:00:00Z" }

queued is how many were handed to the workers now, not how many will be sent in total. Under spread, the rest follow on later days.

Scope: campaigns:write

Stops a processing or scheduled campaign. Recipients already handed to the workers still go out; the rest stay pending until you start it again.

Scope: campaigns:read

200
{
"id": "5d4c3b2a-...",
"name": "Eid offer",
"status": "processing",
"template_id": "7c6b5a4d-...",
"template_name": "eid_promo",
"account": "Main",
"recipients": {
"total": 1200,
"sent": 480,
"delivered": 421,
"read": 190,
"failed": 3,
"skipped": 0
},
"send_mode": "spread",
"started_at": "2026-08-20T09:00:00Z",
"resumes_at": "2026-08-21T00:05:00Z",
"throttle_reason": "Daily WhatsApp messaging limit reached",
"created_at": "2026-08-19T16:20:00Z"
}
StatusMeaning
draftCreated, not started
scheduledArmed for scheduled_at
processingSending
pausedStopped by a person
completedEvery recipient dealt with
failedCould not run

Set when a campaign parked itself against the daily allowance. Without them a stalled campaign looks broken; with them it is visibly waiting, and the time it resumes is stated.

Scope: campaigns:read · Filter with status, paginate with limit and cursor.

Poll GET /v1/campaigns/{id}, or subscribe to campaign.completed and have the final counts delivered to you. See Event reference.