Campaigns
Sequences, steps and variants, leads, schedule, launch and pause. 26 endpoints, each also a tool for your AI through MCP. Authentication and errors are on the overview.
List campaigns
GET/api/v1/campaigns
Newest first, with lead counts by progress.
MCP tool list_campaignsRead-only
Parameters
statusquery · "draft" | "running" | "paused" | "completed"[]
Returns
campaignsrequiredobject[]
curl https://ballast.to/api/v1/campaigns \
-H "Authorization: Bearer $BALLAST_API_KEY"Daily emails sent, replies, bounces and opens
GET/api/v1/campaigns/stats
For all campaigns, or one with campaignId. Days are calendar days in the workspace's timezone.
MCP tool get_campaign_statsRead-only
Parameters
daysquery · number- 7, 30 or 90 days
campaignIdquery · string
Returns
daysrequirednumbertimezonerequiredstring- Days are calendar days in this timezone
seriesrequiredobject[]totalsrequiredobjecttracksOpensrequiredboolean- Some campaign in scope tracks opens
curl https://ballast.to/api/v1/campaigns/stats \
-H "Authorization: Bearer $BALLAST_API_KEY"Sends, replies and bounces by campaign, mailbox and email provider, plus reply sentiment
GET/api/v1/campaigns/analytics
MCP tool get_campaign_analyticsRead-only
Parameters
daysquery · number- 7, 30 or 90 days
Returns
daysrequirednumberbyCampaignrequiredobject[]byMailboxrequiredobject[]byEsprequiredobject[]sentimentrequiredobject- Replies by the type of the label their thread carries now
curl https://ballast.to/api/v1/campaigns/analytics \
-H "Authorization: Bearer $BALLAST_API_KEY"One campaign's results by step, A/B variant, mailbox and email provider
GET/api/v1/campaigns/{id}/breakdown
Since the campaign started. Replies count against the email they answered; the winner per step needs 50+ sends on each variant.
MCP tool get_campaign_breakdownRead-only
Parameters
idrequiredpath · string
Returns
stepsrequiredobject[]byMailboxrequiredobject[]byEsprequiredobject[]sentimentrequiredobject
curl https://ballast.to/api/v1/campaigns/<id>/breakdown \
-H "Authorization: Bearer $BALLAST_API_KEY"Get a campaign with its sequence, schedule and settings
GET/api/v1/campaigns/{id}
MCP tool get_campaignRead-only
Parameters
idrequiredpath · string
Returns
idrequiredstringnamerequiredstringstatusrequired"draft" | "running" | "paused" | "completed"pausedReasonrequiredstring | nulltimezoneFallbackrequiredstring- IANA timezone for leads without one
windowStartrequiredinteger- Minutes after midnight
windowEndrequiredintegerdaysrequiredinteger- Bitmask, bit 0 = Monday ... bit 6 = Sunday
dailyCaprequiredinteger | null- First emails a day for the campaign; null = only mailbox limits
bounceThresholdrequirednumber | null- Pause at this bounce rate (%); null = workspace default
espMatchingrequiredbooleanstopOnReplyrequiredbooleantrackClicksrequiredbooleantrackOpensrequiredbooleanstartOnrequiredstring | null- Optional first sending day (YYYY-MM-DD, in timezoneFallback). Null = start when launched
endOnrequiredstring | null- Optional last sending day (YYYY-MM-DD, in timezoneFallback). After it nothing goes out and the campaign pauses. Null = no end
stopForCompanyrequiredboolean- When a lead replies, stop the sequence for everyone at the same company domain (free-mail domains excluded)
skipRiskyrequiredboolean- Leave out risky and catch-all leads: skipped when added and before their first email
startedAtrequiredstring | nullcreatedAtrequiredstringupdatedAtrequiredstringstepsrequiredobject[]mailboxIdsrequiredstring[]leadCountsrequiredobject- Campaign leads by status
reachedrequirednumber[]- Leads that reached each step (index = step position)
activeMailboxesrequirednumberworkspacerequiredobject
curl https://ballast.to/api/v1/campaigns/<id> \
-H "Authorization: Bearer $BALLAST_API_KEY"Create a draft campaign
POST/api/v1/campaigns
Starts with one empty email. Use set_sequence to write the emails, then add leads and mailboxes.
MCP tool create_campaign
Parameters
namestring
Returns
idrequiredstring
curl -X POST https://ballast.to/api/v1/campaigns \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"<name>"}'Copy a campaign's sequence, schedule and mailboxes into a new draft (no leads)
POST/api/v1/campaigns/{id}/duplicate
MCP tool duplicate_campaign
Parameters
idrequiredpath · string
Returns
idrequiredstring
curl -X POST https://ballast.to/api/v1/campaigns/<id>/duplicate \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Rename a campaign or change its schedule, mailboxes and options
PATCH/api/v1/campaigns/{id}
MCP tool update_campaign
Parameters
idrequiredpath · stringnamestringmailboxIdsstring[]- Replaces the campaign's mailboxes
timezoneFallbackstring- IANA timezone for leads without one
windowStartinteger- Minutes after midnight
windowEndintegerdaysinteger- Bitmask, bit 0 = Monday ... bit 6 = Sunday
dailyCapinteger | null- First emails a day for the campaign; null = only mailbox limits
bounceThresholdnumber | null- Pause at this bounce rate (%); null = workspace default
espMatchingbooleanstopOnReplybooleantrackClicksbooleantrackOpensbooleanstartOnstring | null- Optional first sending day (YYYY-MM-DD, in timezoneFallback). Null = start when launched
endOnstring | null- Optional last sending day (YYYY-MM-DD, in timezoneFallback). After it nothing goes out and the campaign pauses. Null = no end
stopForCompanyboolean- When a lead replies, stop the sequence for everyone at the same company domain (free-mail domains excluded)
skipRiskyboolean- Leave out risky and catch-all leads: skipped when added and before their first email
Returns the same fields as Get a campaign with its sequence, schedule and settings.
curl -X PATCH https://ballast.to/api/v1/campaigns/<id> \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"<name>","mailboxIds":[]}'Delete a campaign
DELETE/api/v1/campaigns/{id}
Its leads stay in the workspace.
MCP tool delete_campaignMCP asks to confirm
Parameters
idrequiredpath · string
Returns
okrequiredtrue
curl -X DELETE https://ballast.to/api/v1/campaigns/<id> \
-H "Authorization: Bearer $BALLAST_API_KEY"Add a follow-up step at the end
POST/api/v1/campaigns/{id}/steps
Parameters
idrequiredpath · string
Returns the same fields as Get a campaign with its sequence, schedule and settings.
curl -X POST https://ballast.to/api/v1/campaigns/<id>/steps \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Change a step's wait time or threading
PATCH/api/v1/campaigns/{id}/steps/{stepId}
Parameters
idrequiredpath · stringstepIdrequiredpath · stringwaitDaysintegersameThreadboolean
Returns
okrequiredtrue
curl -X PATCH https://ballast.to/api/v1/campaigns/<id>/steps/<stepId> \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"waitDays":0,"sameThread":true}'Delete a step
DELETE/api/v1/campaigns/{id}/steps/{stepId}
Parameters
idrequiredpath · stringstepIdrequiredpath · string
Returns the same fields as Get a campaign with its sequence, schedule and settings.
curl -X DELETE https://ballast.to/api/v1/campaigns/<id>/steps/<stepId> \
-H "Authorization: Bearer $BALLAST_API_KEY"Move a step up or down
POST/api/v1/campaigns/{id}/steps/{stepId}/move
Parameters
idrequiredpath · stringstepIdrequiredpath · stringtorequiredinteger
Returns the same fields as Get a campaign with its sequence, schedule and settings.
curl -X POST https://ballast.to/api/v1/campaigns/<id>/steps/<stepId>/move \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"to":0}'Add an A/B variant to a step, optionally copying another
POST/api/v1/campaigns/{id}/steps/{stepId}/variants
Parameters
idrequiredpath · stringstepIdrequiredpath · stringcopyFromstring
Returns the same fields as Get a campaign with its sequence, schedule and settings.
curl -X POST https://ballast.to/api/v1/campaigns/<id>/steps/<stepId>/variants \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"copyFrom":"<copyFrom>"}'Change a variant's subject, body, weight or on/off
PATCH/api/v1/campaigns/{id}/variants/{variantId}
Parameters
idrequiredpath · stringvariantIdrequiredpath · stringsubjectstringbodystring- HTML or plain text; sanitized on save
weightintegeractiveboolean
Returns
okrequiredtruebodyrequiredstring- The body as saved (sanitized)
curl -X PATCH https://ballast.to/api/v1/campaigns/<id>/variants/<variantId> \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"subject":"<subject>","body":"<body>"}'Delete a variant
DELETE/api/v1/campaigns/{id}/variants/{variantId}
Parameters
idrequiredpath · stringvariantIdrequiredpath · string
Returns the same fields as Get a campaign with its sequence, schedule and settings.
curl -X DELETE https://ballast.to/api/v1/campaigns/<id>/variants/<variantId> \
-H "Authorization: Bearer $BALLAST_API_KEY"Replace the whole sequence
PUT/api/v1/campaigns/{id}/sequence
Steps in order, each with 1 to 5 variants. Bodies may be plain text (blank lines split paragraphs) or simple HTML. Use {{first_name}} style variables, {{first_name|there}} for a fallback, {Hi|Hello} spintax, and put {{unsubscribe}} in the first email. Only drafts and paused campaigns.
MCP tool set_sequence
Parameters
idrequiredpath · stringstepsrequiredobject[]
Returns the same fields as Get a campaign with its sequence, schedule and settings.
curl -X PUT https://ballast.to/api/v1/campaigns/<id>/sequence \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"steps":[]}'Write emails with AI from the offer profile
POST/api/v1/campaigns/{id}/write
Drafts a whole sequence (mode sequence) or a new version of one variant (rewrite, shorter, angle), using only facts from the workspace's offer profile and lead fields. Results are saved as new variants and never overwrite existing text; an empty campaign gets the drafted steps. Each email is checked against the content checklist; anything still failing comes back in problems. Needs a saved offer profile (update_offer_profile).
MCP tool write_sequenceNeeds an active plan
Parameters
idrequiredpath · stringmode"sequence" | "rewrite" | "shorter" | "angle"- sequence = draft every step; rewrite, shorter, angle = a new version of one variant
stepsinteger- sequence mode: how many emails
variantIdstring- rewrite, shorter, angle: the variant to start from (required)
anglestring- Optional angle or notes, e.g. 'lead with the cost of manual payroll'
personastring- Optional target persona, e.g. 'operations managers at restaurant groups'
Returns
campaignrequiredobjectcreatedrequiredobject[]skippedrequiredstring[]- Emails that had nowhere to go (step already has 5 variants, or 10 steps)
curl -X POST https://ballast.to/api/v1/campaigns/<id>/write \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"mode":"sequence","steps":0}'Leads in a campaign with their progress
GET/api/v1/campaigns/{id}/leads
MCP tool list_campaign_leadsRead-only
Parameters
idrequiredpath · stringstatusquery · "not_contacted" | "contacted" | "completed" | "replied" | "rescheduled" | "unsubscribed" | "bounced" | "skipped" | "stopped"[]searchquery · stringpagequery · integerpageSizequery · integer
Returns
leadsrequiredobject[]totalrequirednumberpagerequirednumberpageSizerequirednumber
curl https://ballast.to/api/v1/campaigns/<id>/leads \
-H "Authorization: Bearer $BALLAST_API_KEY"Emails sent to one lead in a campaign
GET/api/v1/campaigns/{id}/leads/{campaignLeadId}/sends
Every step that went out, with its rendered subject and body, status and any error.
MCP tool list_campaign_lead_sendsRead-only
Parameters
idrequiredpath · stringcampaignLeadIdrequiredpath · string
Returns
sendsrequiredobject[]
curl https://ballast.to/api/v1/campaigns/<id>/leads/<campaignLeadId>/sends \
-H "Authorization: Bearer $BALLAST_API_KEY"Add leads from lists (or by id) to a campaign
POST/api/v1/campaigns/{id}/leads
Skips leads already in the campaign, unsubscribed, bounced or suppressed leads, and addresses verification found invalid.
MCP tool add_leads_to_campaign
Parameters
idrequiredpath · stringlistIdsstring[]leadIdsstring[]allLeadsboolean- Every lead in the workspace
Returns
matchedrequirednumberaddedrequirednumberalreadyInrequirednumbersuppressedrequirednumber- Unsubscribed, bounced or on the suppression list
invalidrequirednumber- Verification said the address doesn't exist
riskyrequirednumber- Risky or catch-all, left out because the campaign skips risky leads
curl -X POST https://ballast.to/api/v1/campaigns/<id>/leads \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"listIds":[],"leadIds":[]}'Take leads out of a campaign (they stay in the workspace)
POST/api/v1/campaigns/{id}/leads/remove
MCP tool remove_leads_from_campaignMCP asks to confirm
Parameters
idrequiredpath · stringidsrequiredstring[]- Campaign lead ids
Returns
removedrequirednumber
curl -X POST https://ballast.to/api/v1/campaigns/<id>/leads/remove \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ids":[]}'Render every step and variant for one lead
GET/api/v1/campaigns/{id}/preview
Shows the emails exactly as that lead would get them, with spintax resolved the way it will be for them. Defaults to the first lead in the campaign.
MCP tool preview_campaignRead-only
Parameters
idrequiredpath · stringleadIdquery · string
Returns
leadrequiredobject | nullsenderrequiredobject | nullunsubscriberequiredstringemailsrequiredobject[]pickerrequiredobject[]pickerTotalrequirednumber
curl https://ballast.to/api/v1/campaigns/<id>/preview \
-H "Authorization: Bearer $BALLAST_API_KEY"What has to be fixed before launch
GET/api/v1/campaigns/{id}/checklist
Required items block the launch; warnings are advice.
MCP tool get_launch_checklistRead-only
Parameters
idrequiredpath · string
Returns
itemsrequiredobject[]canLaunchrequiredboolean
curl https://ballast.to/api/v1/campaigns/<id>/checklist \
-H "Authorization: Bearer $BALLAST_API_KEY"Launch or resume a campaign
POST/api/v1/campaigns/{id}/launch
Runs the launch checklist first and refuses when a required item fails. The worker then sends inside the schedule window.
MCP tool launch_campaignNeeds an active planMCP asks to confirm
Parameters
idrequiredpath · string
Returns
statusrequired"draft" | "running" | "paused" | "completed"itemsrequiredobject[]
curl -X POST https://ballast.to/api/v1/campaigns/<id>/launch \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'Pause a running campaign
POST/api/v1/campaigns/{id}/pause
Nothing more is sent until it is launched again. Emails already handed to the provider still arrive.
MCP tool pause_campaign
Parameters
idrequiredpath · string
Returns
statusrequired"draft" | "running" | "paused" | "completed"
curl -X POST https://ballast.to/api/v1/campaigns/<id>/pause \
-H "Authorization: Bearer $BALLAST_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'