Skip to main content

Campaigns

MethodPathScopeSDK
POST/api/v1/campaignscampaigns:writecampaigns.create / mailroom.campaign
GET/api/v1/campaignsany valid keycampaigns.list
GET/api/v1/campaigns/:idany valid keycampaigns.get
POST/api/v1/campaigns/:id/cancelcampaigns:writecampaigns.cancel

POST /api/v1/campaigns

FieldTypeNotes
templatestringRequired. Must be enabled for the project/brand.
audienceobjectRequired. See below.
namestringLabel shown in the console.
subjectstringOverrides the template/project default.
typetransactional | marketingDefaults to the template's type.
dataobjectTemplate variables, applied to every recipient.
brandstringBrand slug.
scheduleAtISO stringOmit to send immediately.
endsAtISO stringStop sending after this instant.
variantsarray2–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).

422invalid_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.