Campaigns
| Method | Path | Scope | SDK |
|---|---|---|---|
POST | /api/v1/campaigns | campaigns:write | campaigns.create / mailroom.campaign |
GET | /api/v1/campaigns | any valid key | campaigns.list |
GET | /api/v1/campaigns/:id | any valid key | campaigns.get |
POST | /api/v1/campaigns/:id/cancel | campaigns:write | campaigns.cancel |
POST /api/v1/campaigns
| Field | Type | Notes |
|---|---|---|
template | string | Required. Must be enabled for the project/brand. |
audience | object | Required. See below. |
name | string | Label shown in the console. |
subject | string | Overrides the template/project default. |
type | transactional | marketing | Defaults to the template's type. |
data | object | Template variables, applied to every recipient. |
brand | string | Brand slug. |
scheduleAt | ISO string | Omit to send immediately. |
endsAt | ISO string | Stop sending after this instant. |
variants | array | 2–4 A/B arms: { key, subject?, weight? }. |
Audience modes
{ "mode": "entire" }
{ "mode": "segment", "segmentId": "6b1e…" }
{ "mode": "tag", "tag": "vip" }
{ "mode": "people", "emails": ["ada@example.com", "grace@example.com"] }
Unsubscribed and suppressed contacts are excluded in every mode.
curl -X POST https://mailroom.example.com/api/v1/campaigns \
-H "Authorization: Bearer pk_live_…" \
-H "Content-Type: application/json" \
-d '{
"name": "Spring sale",
"template": "sale",
"subject": "20% off this week",
"audience": { "mode": "tag", "tag": "vip" },
"scheduleAt": "2026-08-01T15:00:00Z"
}'
201
{
"ok": true,
"campaignId": "c9d2…",
"audienceSize": 1840,
"enrolled": 1840,
"scheduledFor": "2026-08-01T15:00:00Z",
"status": "scheduled"
}
The response returns as soon as the audience is resolved and enqueued; delivery is
drained by a dispatcher. audienceSize is what the filter matched, enrolled is
what was queued (they differ when recipients are skipped).
422 — invalid_request (bad payload), or a reason code from campaign creation
such as an unknown template or an empty audience. 403 email_unverified — the
organization owner's email is unverified.
GET /api/v1/campaigns
{
"ok": true,
"campaigns": [
{
"id": "c9d2…",
"name": "Spring sale",
"template": "sale",
"subject": "20% off this week",
"status": "sending",
"scheduled_at": "2026-08-01T15:00:00Z",
"ends_at": null,
"variants": null,
"total_recipients": 1840,
"sent_count": 1204,
"delivered_count": 1180,
"opened_count": 402,
"clicked_count": 88,
"bounced_count": 6,
"created_at": "2026-07-28T09:00:00.000Z",
"sent_at": null
}
]
}
status: draft, scheduled, queued, sending, sent, cancelled, failed.
GET /api/v1/campaigns/:id
Same record shape under campaign. 404 not_found if it is not in this project.
POST /api/v1/campaigns/:id/cancel
{ "ok": true, "id": "c9d2…", "status": "cancelled", "cancelledJobs": 636 }
cancelledJobs is how many queued sends were dropped. Mail already handed to the
provider cannot be recalled. Cancelling a campaign that is already sent returns
422 with a reason code.