Campaigns: Draft, Schedule & Send
Create and send email campaigns to audiences
A campaign is a one-time email broadcast to an audience. Create a campaign, optionally test it, then send it to hundreds or thousands of recipients.
Create a Campaign (Draft)
Create a campaign in draft status. name, subjectA and exactly one of
templateId / html are required — omit subjectA and the request fails
with 422.
cURL
curl -X POST https://api.tratto.email/v1/campaigns \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{
"name":"Q3 Summer Sale",
"subjectA":"Our summer sale starts today",
"templateId":"tmpl_abc123",
"audienceId":"aud_abc123"
}'Response: the id, and nothing else.
{
"data": {
"id": "camp_xyz789"
}
}Fetch the campaign with GET /v1/campaigns/{id} to read its status, content
and stats.
Body fields:
| Field | Required | Notes |
|---|---|---|
name | yes | max 200 characters |
subjectA | yes | the subject line, max 998 characters |
subjectB | no | second subject for an A/B test |
templateId | one of | copies the template's content into the campaign. Exactly one of templateId or html — both, or neither, is a 422 |
html | one of | inline HTML, no template needed |
audienceId | no | omitted = every contact in the workspace |
fromName | no | falls back to the workspace default sender |
fromEmail | no | falls back to the workspace default sender |
If neither the body nor the workspace supplies a sender, the request fails with 422 and a message telling you to set a default sender.
The campaign owns a copy of the template's content from creation onward: editing the template later does not change a campaign already created from it, and editing the campaign does not touch the template.
Test Send
Send a test email before launching to make sure everything looks correct.
cURL
curl -X POST https://api.tratto.email/v1/campaigns/camp_xyz789/test-send \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"to":"[email protected]"}'A test email is sent to your address immediately.
Send Immediately
Send the campaign to all contacts in the audience right now.
cURL
curl -X POST https://api.tratto.email/v1/campaigns/camp_xyz789/send \
-H "Authorization: Bearer tratto_live_..."Response:
{
"data": {
"status": "sending"
}
}The campaign status becomes sending, then completed when the send is done.
Sending is refused with 409 unless the campaign is draft or paused, and it
is checked against your remaining monthly quota before
it starts.
Schedule for Later
Schedule the campaign with scheduledAt (ISO 8601). The field is not
called sendAt.
cURL
curl -X POST https://api.tratto.email/v1/campaigns/camp_xyz789/send \
-H "Authorization: Bearer tratto_live_..." \
-H "Content-Type: application/json" \
-d '{"scheduledAt":"2026-10-01T09:00:00Z"}'The campaign status becomes scheduled and it sends automatically at that
time. A scheduledAt in the past is treated as "send now".
To cancel a schedule and return the campaign to draft:
curl -X POST https://api.tratto.email/v1/campaigns/camp_xyz789/unschedule \
-H "Authorization: Bearer tratto_live_..."That returns 409 if the dispatcher has already started the send — pause it
instead.
Campaign Status Lifecycle
The five statuses are draft, scheduled, sending, paused and
completed. There is no sent.
draft
├─→ (test-send)
├─→ send → sending → completed
└─→ send + scheduledAt → scheduled → sending → completed
└─→ unschedule → draft
sending / scheduled ─→ pause → paused ─→ send (resume) → sendingPause a Campaign
Stop a scheduled or in-progress campaign. Only a sending or scheduled
campaign can be paused; anything else is a 409.
cURL
curl -X POST https://api.tratto.email/v1/campaigns/camp_xyz789/pause \
-H "Authorization: Bearer tratto_live_..."Resuming is a fresh POST /:id/send on the paused campaign — there is no
separate resume endpoint. It picks up only the recipients it never reached, so
nobody is mailed twice.
A campaign can also be paused for you: when a send exhausts the monthly
quota mid-flight, the dispatcher pauses it and sets pausedReason to
"quota_exceeded". On a campaign you paused by hand, pausedReason is
null — that field is the only way to tell the two apart.
A paused campaign can be resumed; only a draft one can be deleted.
Get Campaign Stats
View delivery statistics after sending.
cURL
curl https://api.tratto.email/v1/campaigns/camp_xyz789/stats \
-H "Authorization: Bearer tratto_live_..."Response: counts and rates are two separate objects.
{
"data": {
"campaignId": "camp_xyz789",
"status": "completed",
"stats": {
"total": 5000,
"sent": 5000,
"delivered": 4950,
"opened": 2475,
"clicked": 742,
"bounced": 40,
"skipped": 12,
"untracked": 130
},
"rates": {
"deliveryRate": 99,
"openRate": 50.82,
"clickRate": 15.24,
"bounceRate": 0.8,
"untracked": 130
}
}
}Rates are percentages, rounded to two decimals: 99 means 99%, not 99 in
a hundred thousand and certainly not 0.99. An alert written as
deliveryRate < 0.95 will never fire — you want < 95. Same scale as
Analytics.
Field notes:
totalis the number of recipients;sentcounts the ones actually dispatchedskipped— sends cancelled because the contact unsubscribed after dispatch. They never happened, so they feed no rateuntracked— recipients who opted out of open/click tracking. They are excluded from the openRate/clickRate denominator, never estimated. Theuntrackedkey insideratesis that same count, not a ratestats.variantsandrates.variantsappear only on a campaign that ran an A/B subject test- There is no
complainedfield, and nototalSent
List Campaigns
Get all campaigns.
cURL
curl "https://api.tratto.email/v1/campaigns?status=completed&limit=50" \
-H "Authorization: Bearer tratto_live_..."Query parameters:
status: Filter by status —draft,scheduled,sending,paused,completed.sentis not a valid value and returns 422q: Name prefix search, case-insensitive and accent-sensitive (salmatchesSaldi estate,estatedoes not). While it is set, results are ordered by name instead of newest-firstlimit: Results per page (default 50, max 100)after: Cursor for pagination
Get Campaign Details
Retrieve a specific campaign.
cURL
curl https://api.tratto.email/v1/campaigns/camp_xyz789 \
-H "Authorization: Bearer tratto_live_..."Campaign Best Practices
1. Always Test First
Send a test email to yourself before launching to any audience.
2. Use Descriptive Names
✅ Q3 Summer Sale - Newsletter Segment
❌ Campaign 1, Test
3. Review Audience Size
Count the recipients before sending —
GET /v1/contacts?status=subscribed&audienceId=… returns the same
pagination.total the send gate counts. An audience with no subscribed
contacts means no one receives it.
4. Schedule During Optimal Times
Consider your audience's timezone when scheduling. Early morning or lunch time usually see higher open rates.
5. Monitor Delivery Stats
After sending, review bounce, complaint, and open rates to understand engagement.
6. Create New Campaigns, Don't Re-send
A campaign reaches each recipient once. Re-sending a completed campaign is a
409; resuming a paused one only covers the recipients it never reached. To
mail the same audience again, create a new campaign.
Next Steps
Edit this page on GitHub
Last updated on