Skip to content
TTopSend

Campaigns

Create and update draft campaigns, and retrieve campaign details and performance statistics. Drafts created through the API are reviewed, tested, and scheduled or sent from the TopSend dashboard.

Draft-only keys. Give an API key the campaign_drafts:write permission (Settings → API Keys → “Campaign drafts (no sending)”) to let it create and update drafts without being able to send anything. Sending campaigns or transactional email requires campaigns:write, which also includes draft access. Useful for AI assistants that set up campaigns for you to review.
GET
/campaigns

List all campaigns with summary stats.

Query Parameters

NameTypeRequiredDescription
statusstringOptionalFilter by campaign status: "draft", "scheduled", "sending", "sent", or "paused".
limitintegerOptionalNumber of campaigns to return (default: 100, max: 1000).
offsetintegerOptionalNumber of campaigns to skip for pagination (default: 0).
curl "https://api.topsend.com/api/v1/campaigns?status=sent&limit=10" \
-H "Authorization: Bearer ts_live_abc123"
POST
/campaigns

Create a draft campaign. Requires campaign_drafts:write (or campaigns:write). Nothing is sent.

Provide content as an existing template_id, or as html and/or json_structure (the email builder format — copy it from GET /templates/:id of your brand template and swap in your copy). When you send json_structure without html, the HTML is rendered for you and the draft stays editable in the visual builder. An html-only draft sends exactly as given but opens blank in the visual builder — send json_structure if you want to edit it there. Content passes the same safety checks as templates.

Body Parameters

NameTypeRequiredDescription
namestringRequiredInternal campaign name (max 255).
subjectstringRequiredEmail subject line (max 500).
preview_textstringOptionalInbox preview text (max 500).
list_iduuidOptionalAudience list. One of list_id or segment_id is required.
segment_iduuidOptionalAudience segment. One of list_id or segment_id is required.
template_iduuidOptionalUse an existing template as-is. Cannot be combined with html/json_structure.
htmlstringOptionalFull email HTML.
json_structureobjectOptionalEmail builder document { blocks, settings }.
curl -X POST https://api.topsend.com/api/v1/campaigns \
-H "Authorization: Bearer ts_live_abc123" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: newsletter-2026-10-01" \
-d '{
"name": "October Newsletter",
"subject": "Three things for your next release",
"preview_text": "Plus a free checklist",
"list_id": "LIST_ID",
"html": "<html><body><p>Hey {{first_name}},</p><p>...</p></body></html>"
}'
PATCH
/campaigns/:id

Update a campaign while it is still a draft. Requires campaign_drafts:write (or campaigns:write).

All fields are optional; send only what changes. Accepts the same fields as create. Setting list_id clears segment_id and vice versa. New html/json_structure updates the draft's own content and never modifies a shared template it was created from. Returns 409 campaign_not_draft once the campaign is scheduled, sending, or sent.

curl -X PATCH https://api.topsend.com/api/v1/campaigns/CAMPAIGN_ID \
-H "Authorization: Bearer ts_live_abc123" \
-H "Content-Type: application/json" \
-d '{ "subject": "Updated subject", "segment_id": "SEGMENT_ID" }'
GET
/campaigns/:id

Retrieve a single campaign with detailed performance stats and rates.

curl https://api.topsend.com/api/v1/campaigns/CAMPAIGN_ID \
-H "Authorization: Bearer ts_live_abc123"
{
"data": {
"id": "camp_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "January Newsletter",
"subject": "Your January Update",
"preview_text": "New features and product updates...",
"status": "sent",
"template": {
"id": "t1a2b3c4",
"name": "Monthly Newsletter"
},
"list": {
"id": "l1a2b3c4",
"name": "Newsletter Subscribers"
},
"segment": null,
"stats": {
"queued": 0,
"sent": 1200,
"delivered": 1185,
"bounced": 15,
"complained": 2,
"opens": 980,
"unique_opens": 450,
"clicks": 340,
"unique_clicks": 120,
"unsubscribes": 5,
"conversions": 18
},
"rates": {
"delivery_rate": "98.75",
"open_rate": "37.97",
"click_rate": "10.13",
"bounce_rate": "1.25",
"unsubscribe_rate": "0.42"
},
"scheduled_at": null,
"sent_at": "2025-01-15T09:00:00.000Z",
"created_at": "2025-01-10T14:00:00.000Z",
"updated_at": "2025-01-15T09:05:00.000Z"
}
}

Stats Fields

NameTypeRequiredDescription
queuedintegerOptionalEmails still in the send queue.
sentintegerOptionalTotal emails sent (including delivered).
deliveredintegerOptionalEmails confirmed delivered by the recipient mail server.
bouncedintegerOptionalEmails that bounced (hard or soft).
complainedintegerOptionalEmails marked as spam by recipients.
opensintegerOptionalTotal open events (includes repeat opens).
unique_opensintegerOptionalUnique recipients who opened the email.
clicksintegerOptionalTotal click events (includes repeat clicks).
unique_clicksintegerOptionalUnique recipients who clicked a link.
unsubscribesintegerOptionalRecipients who unsubscribed from this campaign.
conversionsintegerOptionalConversion events attributed to this campaign.

Rates Fields

All rates are returned as percentage strings with two decimal places.

NameTypeRequiredDescription
delivery_ratestringOptionalPercentage of sent emails that were delivered.
open_ratestringOptionalPercentage of delivered emails that were opened (unique).
click_ratestringOptionalPercentage of delivered emails with a link click (unique).
bounce_ratestringOptionalPercentage of sent emails that bounced.
unsubscribe_ratestringOptionalPercentage of delivered emails that led to an unsubscribe.