Campaigns
Base path: /campaigns
Campaigns send a templated message to every active contact in a group, asynchronously. Unlike
/sms/send, a campaign is queued and processed by a background
worker rather than sent inline — expect total_delivered / total_failed to fill in over the
following seconds to minutes, not instantly.
Create a campaign
POST /campaigns
{
"name": "July Promo",
"message": "Hi {first_name}, enjoy 20% off this week only!",
"group_id": "3fa85f64-...",
"sender_id": null,
"scheduled_at": null
}messagesupports merge tags{first_name}and{last_name}, resolved per-recipient by the worker from your Contacts data.group_id— required; the campaign targets every non-opted-out contact in this group.scheduled_at— omit to send immediately (status: "queued"), or pass a future datetime to schedule it (status: "scheduled") — picked up automatically once due.
Cost is calculated and debited from your wallet upfront, based on your current pricing tier.
400 if the group has no active contacts; 402 if your balance can’t cover the cost.
List campaigns
GET /campaigns — all your campaigns, newest first.
Get a campaign
GET /campaigns/{campaign_id}
Campaign report
GET /campaigns/{campaign_id}/report
{
"campaign": { "id": "...", "name": "July Promo", "status": "completed", "...": "..." },
"stats": {
"total_recipients": 500,
"delivered": 480,
"failed": 12,
"pending": 8,
"delivery_rate": 96.0
},
"cost_kes": 240.0,
"started_at": "2026-07-01T09:00:03Z",
"completed_at": "2026-07-01T09:04:11Z"
}Campaign statuses
draft → queued / scheduled → sending → completed | failed
Last updated on