Run a campaign
هذا المحتوى غير متوفر بلغتك بعد.
-
Create it
Section titled “Create it”Terminal window curl https://k-message.kerneltics.com/v1/campaigns \-H "Authorization: Bearer km_live_YOUR_KEY" \-H "Content-Type: application/json" \-H "Idempotency-Key: eid-2026-campaign" \-d '{ "name": "Eid offer", "template": "eid_promo" }'It is created in
draft. Nothing sends. -
Upload recipients
Section titled “Upload recipients”Up to 1000 per call, in as many calls as you need.
for (const batch of chunk(customers, 1000)) {await post(`/v1/campaigns/${campaign.id}/recipients`, {recipients: batch.map(c => ({to: c.phone,name: c.name,parameters: { name: c.firstName, code: 'EID20' },})),})}Each 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 error names the offending index, because nobody can find the bad row in a thousand otherwise.
-
Start it
Section titled “Start it”Terminal window curl https://k-message.kerneltics.com/v1/campaigns/{id}/start \-H "Authorization: Bearer km_live_YOUR_KEY" \-H "Content-Type: application/json" \-d '{ "send_mode": "spread" }'{ "status": "processing", "queued": 480, "skipped": 0 }queuedis what went out now, not the total. Underspread, the rest follow on later days as the allowance refreshes.Add
"scheduled_at": "2026-08-25T09:00:00Z"to arm it for a future time instead of starting now. -
Follow it
Section titled “Follow it”Subscribe to
campaign.completedand the final counts arrive when it is done. Or poll:Terminal window curl https://k-message.kerneltics.com/v1/campaigns/{id} \-H "Authorization: Bearer km_live_YOUR_KEY"
Send modes
Section titled “Send modes”| Mode | Recipients who do not fit today |
|---|---|
spread (default) | Carried into following days until everyone is reached |
today_only | Skipped, and counted in skipped |
spread is right for anything that stays relevant, such as a product
announcement. today_only is right for something that expires, such as a
one-day offer, where sending it tomorrow is worse than not sending it.
Reading a stalled campaign
Section titled “Reading a stalled campaign”A campaign that stops moving is usually not broken:
{ "status": "processing", "resumes_at": "2026-08-21T00:05:00Z", "throttle_reason": "Daily WhatsApp messaging limit reached"}That is spread doing its job. It resumes on its own.
GET /v1/accounts shows the number’s messaging_limit. It is Meta’s
per-business-portfolio cap on distinct new conversations per rolling 24 hours,
and it rises as your sending history and quality rating improve.
Pausing
Section titled “Pausing”curl -X POST https://k-message.kerneltics.com/v1/campaigns/{id}/pause \ -H "Authorization: Bearer km_live_YOUR_KEY"Recipients already handed to the workers still go out; the rest stay pending. Starting it again picks up where it left off.
Recipients can be added while a campaign is paused, but not while it is running: adding mid-send races the workers draining the queue, so whether the new rows went out would depend on timing.