ProductPricingCompareCheck your domainDocsDashboardSign inGet started
Docs / REST API

Start

  • Overview
  • Getting started
  • Connect a mailbox

Sending

  • Domains
  • Mailboxes
  • Sending safety

Leads and campaigns

  • Leads
  • Campaigns
  • Write with AI

Replies and results

  • Unibox and AI labels
  • Analytics

Workspace

  • Team and roles
  • Billing and plans
  • Integrations

Developers

  • Connect your AI (MCP)
  • REST API
    • Overview
    • Workspace5
    • Analytics1
    • Campaigns26
    • Leads16
    • Lists4
    • Labels6
    • Suppressions3
    • Unibox6
    • Mailboxes8
    • Warmup3
    • Deliverability Network4
    • Domains4
    • Link domain5
    • Integrations3
    • Webhook endpoints7
    • Offer profile3
    • Billing1
    • Domain checker1
    • API keys1
  • Webhooks

Start

  • Overview
  • Getting started
  • Connect a mailbox

Sending

  • Domains
  • Mailboxes
  • Sending safety

Leads and campaigns

  • Leads
  • Campaigns
  • Write with AI

Replies and results

  • Unibox and AI labels
  • Analytics

Workspace

  • Team and roles
  • Billing and plans
  • Integrations

Developers

  • Connect your AI (MCP)
  • REST API
    • Overview
    • Workspace5
    • Analytics1
    • Campaigns26
    • Leads16
    • Lists4
    • Labels6
    • Suppressions3
    • Unibox6
    • Mailboxes8
    • Warmup3
    • Deliverability Network4
    • Domains4
    • Link domain5
    • Integrations3
    • Webhook endpoints7
    • Offer profile3
    • Billing1
    • Domain checker1
    • API keys1
  • Webhooks

Cold email that keeps your domains steady, with every feature on every plan.

Product

  • Features
  • Pricing
  • Sequences
  • Warmup
  • How it works
  • Docs
  • Changelog
  • Blog

Compare

  • Ballast vs Instantly
  • Ballast vs Smartlead
  • Ballast vs Lemlist
  • Switch from Instantly
  • Switch from Smartlead
  • Switch from Lemlist

Free tools

  • Domain checker
  • MX lookup
  • SPF checker
  • DKIM checker
  • DMARC checker
  • Blacklist check

Legal

  • Terms of Service
  • Privacy Policy
  • Acceptable Use Policy
  • Data Processing Agreement
  • Sub-processors

Developers

  • REST API
  • MCP server
  • OpenAPI spec
© 2026 BallastTermsPrivacy
All systems normal
ProductPricingCompareCheck your domainDocsBlogChangelogSign in

API reference

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
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

daysrequirednumber
timezonerequiredstring
Days are calendar days in this timezone
seriesrequiredobject[]
totalsrequiredobject
tracksOpensrequiredboolean
Some campaign in scope tracks opens
cURL
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

daysrequirednumber
byCampaignrequiredobject[]
byMailboxrequiredobject[]
byEsprequiredobject[]
sentimentrequiredobject
Replies by the type of the label their thread carries now
cURL
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
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

idrequiredstring
namerequiredstring
statusrequired"draft" | "running" | "paused" | "completed"
pausedReasonrequiredstring | null
timezoneFallbackrequiredstring
IANA timezone for leads without one
windowStartrequiredinteger
Minutes after midnight
windowEndrequiredinteger
daysrequiredinteger
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
espMatchingrequiredboolean
stopOnReplyrequiredboolean
trackClicksrequiredboolean
trackOpensrequiredboolean
startOnrequiredstring | 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 | null
createdAtrequiredstring
updatedAtrequiredstring
stepsrequiredobject[]
mailboxIdsrequiredstring[]
leadCountsrequiredobject
Campaign leads by status
reachedrequirednumber[]
Leads that reached each step (index = step position)
activeMailboxesrequirednumber
workspacerequiredobject
cURL
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
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
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 · string
namestring
mailboxIdsstring[]
Replaces the campaign's mailboxes
timezoneFallbackstring
IANA timezone for leads without one
windowStartinteger
Minutes after midnight
windowEndinteger
daysinteger
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
espMatchingboolean
stopOnReplyboolean
trackClicksboolean
trackOpensboolean
startOnstring | 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
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
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
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 · string
stepIdrequiredpath · string
waitDaysinteger
sameThreadboolean

Returns

okrequiredtrue
cURL
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 · string
stepIdrequiredpath · string

Returns the same fields as Get a campaign with its sequence, schedule and settings.

cURL
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 · string
stepIdrequiredpath · string
torequiredinteger

Returns the same fields as Get a campaign with its sequence, schedule and settings.

cURL
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 · string
stepIdrequiredpath · string
copyFromstring

Returns the same fields as Get a campaign with its sequence, schedule and settings.

cURL
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 · string
variantIdrequiredpath · string
subjectstring
bodystring
HTML or plain text; sanitized on save
weightinteger
activeboolean

Returns

okrequiredtrue
bodyrequiredstring
The body as saved (sanitized)
cURL
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 · string
variantIdrequiredpath · string

Returns the same fields as Get a campaign with its sequence, schedule and settings.

cURL
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 · string
stepsrequiredobject[]

Returns the same fields as Get a campaign with its sequence, schedule and settings.

cURL
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 · string
mode"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

campaignrequiredobject
createdrequiredobject[]
skippedrequiredstring[]
Emails that had nowhere to go (step already has 5 variants, or 10 steps)
cURL
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 · string
statusquery · "not_contacted" | "contacted" | "completed" | "replied" | "rescheduled" | "unsubscribed" | "bounced" | "skipped" | "stopped"[]
searchquery · string
pagequery · integer
pageSizequery · integer

Returns

leadsrequiredobject[]
totalrequirednumber
pagerequirednumber
pageSizerequirednumber
cURL
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 · string
campaignLeadIdrequiredpath · string

Returns

sendsrequiredobject[]
cURL
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 · string
listIdsstring[]
leadIdsstring[]
allLeadsboolean
Every lead in the workspace

Returns

matchedrequirednumber
addedrequirednumber
alreadyInrequirednumber
suppressedrequirednumber
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
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 · string
idsrequiredstring[]
Campaign lead ids

Returns

removedrequirednumber
cURL
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 · string
leadIdquery · string

Returns

leadrequiredobject | null
senderrequiredobject | null
unsubscriberequiredstring
emailsrequiredobject[]
pickerrequiredobject[]
pickerTotalrequirednumber
cURL
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
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
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
curl -X POST https://ballast.to/api/v1/campaigns/<id>/pause \
  -H "Authorization: Bearer $BALLAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
PreviousAnalyticsNextLeads