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:
| Field | Use it when |
|---|---|
markdown | Almost always. day3 Markdown, below. |
sections | You are round-tripping the composer’s own structure. |
html | You 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
 an image, alone on its own line
[](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
 (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. :::htmlis one opaque block that humans cannot edit in the composer. Use it last.- Images must be absolute
httpsURLs, 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
/v1/campaignsNewest first, cursor-paginated. Filter with ?status=.
Create a draft
/v1/campaignsEvery field is optional. A draft can be incomplete, as in the app.
| Field | Notes |
|---|---|
subject | The subject line. |
markdown / sections / html | The body. Exactly one. |
name | Internal name, never shown to recipients. |
preview_text | Inbox preview text. |
audience_id | Defaults to your only audience, when there is exactly one. |
segment_id | Send to a segment instead of the whole audience. |
topic_id | Send only to contacts subscribed to a topic. |
sender_id | Defaults to the account’s default sender. |
from_name, reply_to, footer_text | Override 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
/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
/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
/v1/campaigns/{campaign_id}Drafts and scheduled campaigns only. A sent campaign is a record and stays.
Preview a campaign
/v1/campaigns/{campaign_id}/previewThe 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
/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
/v1/campaigns/{campaign_id}/sendneeds campaigns:sendSends 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
/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
/v1/campaigns/{campaign_id}/scheduleReturns 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.