API/Email Campaigns API

Email Campaigns API

Create, edit, schedule, send and measure email campaigns from the API.

Manage the full campaign lifecycle: draft, audience, schedule, send and results. Every request is scoped to the organization that owns the API key.

List campaigns

GET /api/v1/email/campaigns
ParameterTypeDescription
statusstringOptional draft, scheduled, sending, sent, paused or archived.
limitnumberRows to return, 1-200 (default 50).
curl -H "x-api-key: org_api_key" \
  "https://growth.example.com/api/v1/email/campaigns?status=sent&limit=10"
{
  "campaigns": [
    {
      "id": "k17...",
      "name": "August newsletter",
      "status": "sent",
      "scheduledAt": null,
      "sentAt": 1785312000000,
      "stats": { "queued": 0, "sent": 1240, "delivered": 1231, "opened": 502, "clicked": 88, "bounced": 9, "complained": 0, "unsubscribed": 3 },
      "createdAt": 1785225600000
    }
  ],
  "sampleLimited": false
}

Get one campaign

GET /api/v1/email/campaigns/:campaignId

Returns the full campaign, including contentBlocks, audienceTags and audienceFilters. GET /api/v1/email/campaigns/:campaignId/analytics adds the activity timeline and top clicked links; GET /api/v1/email/campaigns/:campaignId/recipients?cursor=&limit= pages through who received it and what they did.

Create a campaign

POST /api/v1/email/campaigns
FieldTypeDescription
namestringRequired internal name.
subjectstringRequired subject line.
contentBlocksarrayRequired, at least one { "type": "...", "props": { ... } } block.
previewTextstringInbox preview text.
fromAddressstringOverrides the sending application's from address.
replyTostringReply-to address.
audienceTagsstring[]Subscribers must carry every tag listed.
audienceFiltersarray{ "field", "operator", "value?", "key?" } filters, ANDed together.
curl -X POST -H "x-api-key: org_api_key" -H "Content-Type: application/json" \
  -d '{"name":"August newsletter","subject":"What shipped in August","contentBlocks":[{"type":"text","props":{"markdown":"# Hello\n\nHere is what shipped."}}],"audienceTags":["customers"]}' \
  "https://growth.example.com/api/v1/email/campaigns"

The campaign is created as a draft. A block with no recognized type falls back to rendering props.markdown.

Update, schedule and archive

PATCH  /api/v1/email/campaigns/:campaignId
POST   /api/v1/email/campaigns/:campaignId/schedule
DELETE /api/v1/email/campaigns/:campaignId

PATCH accepts the same fields as create; only the fields present are changed, and a campaign that is already sending or sent is rejected.

POST .../schedule takes { "scheduledAt": 1786000000000 } (ms, in the future) and books the send. { "scheduledAt": null } moves a scheduled campaign back to draft.

DELETE archives the campaign. Add ?restore=true to take it back out of the archive.

Send

POST /api/v1/email/campaigns/:campaignId/send
FieldTypeDescription
testEmailstringOptional. Sends one preview copy to this address instead of running the campaign.
curl -X POST -H "x-api-key: org_api_key" -H "Content-Type: application/json" \
  -d '{"testEmail":"[email protected]"}' \
  "https://growth.example.com/api/v1/email/campaigns/k17.../send"

Without testEmail this starts the real send to every matching subscribed contact and returns { "started": true }. The test send returns { "sent": true } and never writes send rows or stats.

The audience is read straight from the subscribed status index: contacts whose status is unsubscribed, bounced or complained are never loaded, so they cannot receive a campaign. This is enforced on every batch as the send walks the list, so a contact that bounces or unsubscribes mid-send drops out of the remaining batches. There is no per-recipient error for this — suppressed contacts are silently absent from the send, unlike transactional sends which reject with 409. Send stats therefore count only contacts that were subscribed at the moment their batch was read.

Error responses:

StatusMeaning
400Invalid body, invalid status filter, or nothing to send to.
401Missing or invalid API key.
404Unknown campaign, or a campaign owned by another organization.

Notes

Manage Transactional Emails APIEmail Surveys API