Skip to Content
Campaigns

Campaigns

A campaign is one email to a whole audience, or to a segment or topic within it. Everything the app’s composer does is available here, so a script or an AI editor can draft and a human can still review before it goes out.

Sending is irreversible, so it needs its own scope.

The Campaign object

{ "id": "cmp_4v0dz1k9x2m7", "object": "campaign", "name": "August release", "subject": "What shipped in August", "preview_text": "Sending domains, faster imports, and a new API.", "status": "draft", "sandbox": false, "audience_id": "aud_7k2m9x4v0dz1", "segment_id": null, "topic_id": null, "sender_id": "snd_2v0dz1k9x4m", "sending_domain_id": "dom_9x4v0dz1k2m", "from_name": "Acme", "from_email": "hello@yourdomain.com", "reply_to": null, "footer_text": null, "risk_level": null, "risk_summary": null, "paused_reason": null, "scheduled_at": null, "sent_at": null, "created_at": "2026-08-20T09:00:00.000Z", "updated_at": "2026-08-20T09:00:00.000Z", "url": "https://go.day3.app/campaigns/cmp_4v0dz1k9x2m7" }

url opens the campaign in the app. Every write returns it.

Campaign bodies

Send exactly one of:

FieldUse it when
markdownAlmost always. day3 Markdown, below.
sectionsYou are round-tripping the composer’s own structure.
htmlYou have finished HTML. Sanitized and stored as one opaque block.

Prefer markdown: each construct becomes a real block in the visual composer, so a human can still edit it. html cannot be edited block by block.

day3 Markdown

Ordinary Markdown, plus a few block constructs:

# Heading (through ######) Plain paragraphs, **bold**, *italic*, `code`, [links](https://example.com) - bullet / 1. numbered lists --- a horizontal rule ![Alt](https://cdn.example.com/a.png) an image, alone on its own line [![Alt](img-url)](link-url) an image that links somewhere [Label](https://x.com){.button} a call-to-action button options: {.button bg=#2563eb color=#ffffff full align=left} > A quote a callout box > -- Attribution optional attribution line :::spacer 48::: blank vertical space, in pixels :::columns two or three side-by-side columns ### Left Text. +++ ### Right Text. ::: :::card image-left an image paired with text ![Alt](https://cdn.example.com/p.png) (also image-right / image-top) Text beside the image. ::: :::social Follow us: a row of profile links - twitter: https://x.com/acme (twitter, linkedin, facebook, - website: https://acme.com instagram, youtube, github, ::: website, email) :::section {bg=#f5f5f5 align=center} tint or align a block Anything above. ::: :::html raw HTML, sanitized on the way in <table><tr><td>Anything the blocks above cannot express.</td></tr></table> ::: === force a split between two text blocks
  • A quote’s attribution line must start with --, an en dash or an em dash. Any other line is more quote.
  • :::html is one opaque block that humans cannot edit in the composer. Use it last.
  • Images must be absolute https URLs, already hosted. The API cannot upload files.

Personalization. {{first_name}}, {{last_name}}, {{email}} and any custom field key merge per recipient. Add a fallback for blanks: {{first_name|there}}.

The postal address and unsubscribe link are appended to the footer automatically. They are a compliance requirement and cannot be removed.

List campaigns

GET/v1/campaigns

Newest first, cursor-paginated. Filter with ?status=.

Create a draft

POST/v1/campaigns

Every field is optional. A draft can be incomplete, as in the app.

FieldNotes
subjectThe subject line.
markdown / sections / htmlThe body. Exactly one.
nameInternal name, never shown to recipients.
preview_textInbox preview text.
audience_idDefaults to your only audience, when there is exactly one.
segment_idSend to a segment instead of the whole audience.
topic_idSend only to contacts subscribed to a topic.
sender_idDefaults to the account’s default sender.
from_name, reply_to, footer_textOverride the sender defaults.
curl -X POST https://go.day3.app/api/v1/campaigns \ -H "Authorization: Bearer $DAY3_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "subject": "What shipped in August", "preview_text": "Sending domains, faster imports, and a new API.", "markdown": "# August\n\nHi {{first_name|there}}, here is what changed.\n\n[Read the changelog](https://day3.app/changelog){.button}" }'

Retrieve a campaign

GET/v1/campaigns/{campaign_id}

Returns the campaign with its body in all three forms: markdown, sections and html.

Read before you edit. A PATCH with markdown replaces the whole body and discards any change a human made in the composer.

Update a campaign

PATCH/v1/campaigns/{campaign_id}

Same fields as create. Only what you send changes.

Returns 409 once the campaign has left draft or scheduled. Sending and sent campaigns are immutable.

Delete a campaign

DELETE/v1/campaigns/{campaign_id}

Drafts and scheduled campaigns only. A sent campaign is a record and stays.

Preview a campaign

GET/v1/campaigns/{campaign_id}/preview

The rendered email: theme, merge tags and compliance footer applied. Add ?format=html for the HTML document instead of a JSON wrapper.

Show this to a human, or read it back to check your Markdown became the blocks you expected.

Send a test

POST/v1/campaigns/{campaign_id}/test
{ "to": "you@example.com" }

to is one address or an array of up to 5. Tests go only to the addresses you name, never to the audience, so they need no scope.

Send to the audience

POST/v1/campaigns/{campaign_id}/sendneeds campaigns:send

Sends to the whole audience, now. No confirmation, no undo. The automated risk review runs first, and delivery follows if it passes.

Needs the campaigns:send scope. Without it: 403 insufficient_scope. Mint a new key with sending enabled.

Schedule a send

POST/v1/campaigns/{campaign_id}/scheduleneeds campaigns:send
{ "send_at": "2026-09-01T09:00:00Z" }

At least one minute in the future. Same scope and consequences as sending, just later.

Cancel a schedule

DELETE/v1/campaigns/{campaign_id}/schedule

Returns the campaign to draft. No scope needed: un-sending is always safe.

Sandbox mode

On a free plan a campaign send is real but reaches only members of your own organization, and the campaign carries "sandbox": true. The 100 emails a month are shared with API and test sends. See Authentication.

Sending a series instead

A campaign is one email at one moment. A welcome series, trial drip or onboarding sequence is an automation: built on the canvas in the app, enrolled into one contact at a time from your backend.

Last updated on