Campaigns
Create, read, schedule, launch, pause and delete campaigns, and manage the emails and mailboxes each one uses.
List campaigns
Lists all campaigns for the authenticated user's space with optional filtering by status and folder. Supports pagination.
Parameters
- page integer in query
Page number (default: 1)
- limit integer in query
Page size (default: 20, maximum: 200)
- status string in query
Filter by status
One of: "not_started", "running", "completed", "paused", "draft" - folderId integer in query
Filter by folder ID
Responses
- 200 List of campaigns · ListCampaignsResponse
- 400 Invalid query parameters · ErrorResponse
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 500 Failed to retrieve campaigns · ErrorResponse
Fields in the 200 response
- campaigns array of CampaignListItem
8 fields inside campaigns
- createdAt string
- emoji string
- flow string
- id integer
- name string
- stats CampaignStats
- status string
- updatedAt string
- hasMore boolean
- limit integer
- page integer
- total integer
Request
curl -X GET "https://api.emailchaser.com/r/campaigns" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"campaigns": [
{
"createdAt": "string",
"emoji": "string",
"flow": "string",
"id": 123,
"name": "Jane Doe",
"stats": {
"bouncedLeadsCount": 123,
"contactedLeadsCount": 123,
"emailsSentCount": 123,
"leadsRespondedPositivelyCount": 123,
"repliedLeadsCount": 123,
"senderEmailsConnected": 123,
"senderEmailsDisconnected": 123,
"senderEmailsTotal": 123
},
"status": "string",
"updatedAt": "string"
}
],
"hasMore": true,
"limit": 123,
"page": 123,
"total": 123
}Create a campaign
Creates a campaign in the API key's workspace. The campaign starts in draft status and is placed in the workspace's default folder. Before it can be launched with POST /campaigns/{id}/resume, it needs four things: a sequence (PUT /campaigns/{id}/sequence), sending days (PUT /campaigns/{id}/schedule; there is no default), at least one email account (POST /campaigns/{id}/sender-emails), and at least one lead (POST /leads with campaignId). Campaigns with flow api can launch without leads.
Request bodyJSON · CreateCampaignRequest
- allowNonBusinessEmails boolean
- dailyLimit integer
DailyLimit caps the total emails (initial + follow-ups) this campaign may schedule per calendar day in the campaign timezone. Omit for no campaign-level cap; per-inbox limits still apply either way.
Minimum 1. Maximum 10000 - emoji stringAt least 1 characters. At most 10 characters
- flow string
Flow defaults to multiple_leads_scheduled, which is what the app creates, so a campaign made through the API behaves identically to one made in the UI. The api flow skips lead validation and the processing-leads guard at launch; pass it only if you want that.
One of: "multiple_leads_scheduled", "api" - ignoreOutOfOfficeReplies boolean
- isEnabledCatchallValidated boolean
- isEnabledEmailVerifier boolean
- isEnabledIgnoreHardBouncedLeads boolean
- isEnabledIgnoreLeadsWhoAlreadyResponded boolean
- isEnabledLlm boolean
Settings - all optional, mirroring UpdateCampaignRequest
- isEnabledSkipLeadIfAlreadyExists boolean
- isEnabledStopFollowUpsForSameCompany boolean
- isEnabledStopFollowUpsOnReply boolean
- maximumSendingLimitPerSenderEmail integerMinimum 1. Maximum 10000
- maximumSendingLimitPerSenderEmailVariation integerMinimum 0. Maximum 100
- maximumTimeBetweenEmails integerMinimum 2. Maximum 30
- minimumHealthScore integer
MinimumHealthScore, 1-100, is the lowest email account health score (see healthScore on the sender emails) that may send in this campaign. An account below it, or with no score yet, sends nothing here, first emails and follow-ups alike, until its score is back at or above it; its conversations wait for it and never move to another account. Omit or send 0 for no minimum.
Minimum 0. Maximum 100. Example:80 - minimumTimeBetweenEmails integerMinimum 2. Maximum 30
- name string requiredAt least 1 characters. At most 255 characters
- timezone string
Responses
- 201 Campaign created successfully · CreateCampaignResponse
- 400 Invalid request body · ErrorInvalidRequest
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 500 Failed to create campaign · ErrorFailedToCreateCampaign
Fields in the 201 response
- campaign CreatedCampaign
8 fields inside campaign
- createdAt stringExample:
2024-01-15T10:30:00Z - emoji stringExample:
📥 - flow stringExample:
multiple_leads_scheduled - id integerExample:
8589949820 - name stringExample:
RB2B High Intent - status stringExample:
draft - timezone stringExample:
America/New_York - updatedAt stringExample:
2024-01-15T10:30:00Z
- message stringExample:
campaign created successfully
Request
curl -X POST "https://api.emailchaser.com/r/campaigns" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"allowNonBusinessEmails": true,
"dailyLimit": 1,
"emoji": "string",
"flow": "multiple_leads_scheduled",
"ignoreOutOfOfficeReplies": true,
"isEnabledCatchallValidated": true,
"isEnabledEmailVerifier": true,
"isEnabledIgnoreHardBouncedLeads": true,
"isEnabledIgnoreLeadsWhoAlreadyResponded": true,
"isEnabledLlm": true,
"isEnabledSkipLeadIfAlreadyExists": true,
"isEnabledStopFollowUpsForSameCompany": true,
"isEnabledStopFollowUpsOnReply": true,
"maximumSendingLimitPerSenderEmail": 1,
"maximumSendingLimitPerSenderEmailVariation": 123,
"maximumTimeBetweenEmails": 2,
"minimumHealthScore": 80,
"minimumTimeBetweenEmails": 2,
"name": "Jane Doe",
"timezone": "America/New_York"
}'Response
{
"campaign": {
"createdAt": "2024-01-15T10:30:00Z",
"emoji": "📥",
"flow": "multiple_leads_scheduled",
"id": 8589949820,
"name": "RB2B High Intent",
"status": "draft",
"timezone": "America/New_York",
"updatedAt": "2024-01-15T10:30:00Z"
},
"message": "campaign created successfully"
}Get a campaign by ID
Retrieves detailed information about a specific campaign including settings, schedule, statistics, and email counts. schedule.daysSchedule is one comma-separated string of weekday numbers, such as "1,2,3,4,5", not an array. minimumHealth lists each connected email account on the campaign with its health score and whether the campaign's minimum health score (settings.minimumHealthScore) holds it back; when every account is held back, allHeldBack is true and message says the campaign is sending nothing.
Parameters
- id integer required in path
Campaign ID
Responses
- 200 Campaign details · GetCampaignResponse
- 400 Invalid campaign ID · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 500 Failed to retrieve campaign · ErrorResponse
Fields in the 200 response
- createdAt stringExample:
2024-01-10T10:30:00Z - emails CampaignEmailCounts
20 fields inside emails
- blocked integerExample:
2 - bounced integerExample:
20 - canceled integerExample:
15 - catchAll integerExample:
12 - deferred integerExample:
5 - delivered integerExample:
280 - draft integerExample:
20 - dropped integerExample:
3 - errorOnSent integerExample:
5 - followUp integerExample:
50 - followUpCanceled integerExample:
10 - followUpDraft integerExample:
10 - invalid integerExample:
8 - pending integerExample:
100 - replied integerExample:
50 - scheduled integerExample:
500 - sent integerExample:
300 - spamReport integerExample:
2 - total integerExample:
1000 - waitingForReschedule integerExample:
5
- emoji stringExample:
🚀 - flow stringExample:
multiple_leads_scheduled - id integerExample:
123 - launchAt string
"0001-01-01T00:00:00Z" until the campaign is first launched.
Example:2024-01-15T09:00:00Z - minimumHealth CampaignMinimumHealth
MinimumHealth is what the campaign's minimum health score is doing: each connected account's score, which accounts it holds back and why. Null only when the scores could not be read this time.
5 fields inside minimumHealth
- accounts array of CampaignAccountHealth
Accounts are the campaign's connected email accounts, the held-back ones first.
- allHeldBack boolean
AllHeldBack is true when a minimum is set and every connected account is below it, so the campaign sends nothing.
Example:false - heldBackCount integer
HeldBackCount is how many of those accounts the minimum holds back.
Example:1 - message string
Message says what the minimum is doing, in plain words. Null when it holds nothing back.
Example:1 of 3 email accounts is below this campaign's minimum health score of 80% and sends nothing in it until its score is back up. - minimumHealthScore integer
MinimumHealthScore is the campaign's minimum, 1-100. Null when it has none.
Example:80
- name stringExample:
Q1 Outreach Campaign - schedule CampaignSchedule
7 fields inside schedule
- cronSchedule stringExample:
0 9 * * 1-5 - daysSchedule string
DaysSchedule is the sending days as one comma-separated string of weekday numbers, where Sunday is 0: "1,2,3,4,5" is Monday to Friday. It is not an array. Empty until days are set with PUT /campaigns/{id}/schedule.
Example:1,2,3,4,5 - endSchedule stringExample:
17:00 - everySchedule integerExample:
30 - maximumTimeBetweenEmails integerExample:
15 - minimumTimeBetweenEmails integerExample:
5 - startSchedule stringExample:
09:00
- sendAt string
"0001-01-01T00:00:00Z" while not set.
Example:2024-01-15T10:00:00Z - settings CampaignSettings
15 fields inside settings
- allowNonBusinessEmails booleanExample:
false - dailyLimit integer
DailyLimit is the campaign-level cap on total emails scheduled per calendar day (campaign timezone). null means no campaign-level cap.
Example:200 - ignoreOutOfOfficeReplies booleanExample:
true - isEnabledCatchallValidated booleanExample:
true - isEnabledEmailVerifier booleanExample:
false - isEnabledIgnoreHardBouncedLeads booleanExample:
true - isEnabledIgnoreLeadsWhoAlreadyResponded booleanExample:
true - isEnabledLlm booleanExample:
true - isEnabledSkipLeadIfAlreadyExists booleanExample:
false - isEnabledStopFollowUpsAcrossCampaigns booleanExample:
true - isEnabledStopFollowUpsForSameCompany booleanExample:
false - isEnabledStopFollowUpsOnReply booleanExample:
true - maximumSendingLimitPerSenderEmail integerExample:
50 - maximumSendingLimitPerSenderEmailVariation integerExample:
10 - minimumHealthScore integer
MinimumHealthScore is the lowest email account health score that may send in this campaign, 1-100. null means no minimum.
Example:80
- stats CampaignDetailStats
5 fields inside stats
- bouncedLeadsCount integer
- contactedLeadsCount integer
- emailsSentCount integer
- leadsRespondedPositivelyCount integer
- repliedLeadsCount integer
- status stringExample:
running - timezone stringExample:
America/New_York - updatedAt stringExample:
2024-01-15T10:30:00Z
Request
curl -X GET "https://api.emailchaser.com/r/campaigns/123" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"createdAt": "2024-01-10T10:30:00Z",
"emails": {
"blocked": 2,
"bounced": 20,
"canceled": 15,
"catchAll": 12,
"deferred": 5,
"delivered": 280,
"draft": 20,
"dropped": 3,
"errorOnSent": 5,
"followUp": 50,
"followUpCanceled": 10,
"followUpDraft": 10,
"invalid": 8,
"pending": 100,
"replied": 50,
"scheduled": 500,
"sent": 300,
"spamReport": 2,
"total": 1000,
"waitingForReschedule": 5
},
"emoji": "🚀",
"flow": "multiple_leads_scheduled",
"id": 123,
"launchAt": "2024-01-15T09:00:00Z",
"minimumHealth": {
"accounts": [
{
"address": "john@example.com",
"healthScore": 72,
"heldBack": true,
"reason": "Health score 72% is below this campaign's minimum of 80%.",
"senderEmailId": 123
}
],
"allHeldBack": false,
"heldBackCount": 1,
"message": "1 of 3 email accounts is below this campaign's minimum health score of 80% and sends nothing in it until its score is back up.",
"minimumHealthScore": 80
},
"name": "Q1 Outreach Campaign",
"schedule": {
"cronSchedule": "0 9 * * 1-5",
"daysSchedule": "1,2,3,4,5",
"endSchedule": "17:00",
"everySchedule": 30,
"maximumTimeBetweenEmails": 15,
"minimumTimeBetweenEmails": 5,
"startSchedule": "09:00"
},
"sendAt": "2024-01-15T10:00:00Z",
"settings": {
"allowNonBusinessEmails": false,
"dailyLimit": 200,
"ignoreOutOfOfficeReplies": true,
"isEnabledCatchallValidated": true,
"isEnabledEmailVerifier": false,
"isEnabledIgnoreHardBouncedLeads": true,
"isEnabledIgnoreLeadsWhoAlreadyResponded": true,
"isEnabledLlm": true,
"isEnabledSkipLeadIfAlreadyExists": false,
"isEnabledStopFollowUpsAcrossCampaigns": true,
"isEnabledStopFollowUpsForSameCompany": false,
"isEnabledStopFollowUpsOnReply": true,
"maximumSendingLimitPerSenderEmail": 50,
"maximumSendingLimitPerSenderEmailVariation": 10,
"minimumHealthScore": 80
},
"stats": {
"bouncedLeadsCount": 123,
"contactedLeadsCount": 123,
"emailsSentCount": 123,
"leadsRespondedPositivelyCount": 123,
"repliedLeadsCount": 123
},
"status": "running",
"timezone": "America/New_York",
"updatedAt": "2024-01-15T10:30:00Z"
}Update a campaign by ID
Updates campaign properties such as name, emoji, timezone, and various settings. Only provided fields will be updated. minimumHealthScore (1-100) stops any email account whose health score is below it, or that has no score yet, from sending in this campaign until its score is back up; its conversations wait for it and never move to another account. Send 0 to remove the minimum.
Parameters
- id integer required in path
Campaign ID
Request bodyJSON · UpdateCampaignRequest
- allowNonBusinessEmails boolean
- dailyLimit integer
DailyLimit caps the total emails (initial + follow-ups) this campaign may schedule per calendar day in the campaign timezone. Omit to leave the cap unchanged; it cannot be cleared through this endpoint.
Minimum 1. Maximum 10000 - emoji stringAt least 1 characters. At most 10 characters
- ignoreOutOfOfficeReplies boolean
- isEnabledCatchallValidated boolean
- isEnabledEmailVerifier boolean
- isEnabledIgnoreHardBouncedLeads boolean
- isEnabledIgnoreLeadsWhoAlreadyResponded boolean
- isEnabledLlm boolean
Settings - all optional boolean flags
- isEnabledSkipLeadIfAlreadyExists boolean
- isEnabledStopFollowUpsAcrossCampaigns boolean
- isEnabledStopFollowUpsForSameCompany boolean
- isEnabledStopFollowUpsOnReply boolean
- maximumSendingLimitPerSenderEmail integerMinimum 1. Maximum 10000
- maximumSendingLimitPerSenderEmailVariation integerMinimum 0. Maximum 100
- maximumTimeBetweenEmails integerMinimum 2. Maximum 30
- minimumHealthScore integer
MinimumHealthScore, 1-100, is the lowest email account health score (see healthScore on the sender emails) that may send in this campaign. An account below it, or with no score yet, sends nothing here, first emails and follow-ups alike, until its score is back at or above it; its conversations wait for it and never move to another account. Send 0 to remove the minimum; omit to leave it unchanged. A running campaign re-plans its unsent emails at once.
Minimum 0. Maximum 100. Example:80 - minimumTimeBetweenEmails integerMinimum 2. Maximum 30
- name stringAt least 1 characters. At most 255 characters
- timezone string
Responses
- 200 Campaign updated successfully · UpdateCampaignResponse
- 400 Invalid campaign ID or request body · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 500 Failed to update campaign · ErrorFailedToUpdateCampaign
Fields in the 200 response
- campaign object
4 fields inside campaign
- emoji stringExample:
🚀 - id integerExample:
123 - minimumHealthScore integer
MinimumHealthScore is the campaign's minimum email account health score after this update, null when it has none.
Example:80 - name stringExample:
Q1 Outreach Campaign
- message stringExample:
campaign updated successfully
Request
curl -X PUT "https://api.emailchaser.com/r/campaigns/123" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"allowNonBusinessEmails": true,
"dailyLimit": 1,
"emoji": "string",
"ignoreOutOfOfficeReplies": true,
"isEnabledCatchallValidated": true,
"isEnabledEmailVerifier": true,
"isEnabledIgnoreHardBouncedLeads": true,
"isEnabledIgnoreLeadsWhoAlreadyResponded": true,
"isEnabledLlm": true,
"isEnabledSkipLeadIfAlreadyExists": true,
"isEnabledStopFollowUpsAcrossCampaigns": true,
"isEnabledStopFollowUpsForSameCompany": true,
"isEnabledStopFollowUpsOnReply": true,
"maximumSendingLimitPerSenderEmail": 1,
"maximumSendingLimitPerSenderEmailVariation": 123,
"maximumTimeBetweenEmails": 2,
"minimumHealthScore": 80,
"minimumTimeBetweenEmails": 2,
"name": "Jane Doe",
"timezone": "America/New_York"
}'Response
{
"campaign": {
"emoji": "🚀",
"id": 123,
"minimumHealthScore": 80,
"name": "Q1 Outreach Campaign"
},
"message": "campaign updated successfully"
}Delete a campaign
Deletes a campaign and all associated data including emails, sequences, and scheduled tasks.
Parameters
- id integer required in path
Campaign ID
Responses
- 200 Campaign deleted successfully · DeleteCampaignResponse
- 400 Invalid campaign ID · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 500 Failed to delete campaign · ErrorFailedToDeleteCampaign
Fields in the 200 response
- id integerExample:
123 - message stringExample:
campaign deleted successfully
Request
curl -X DELETE "https://api.emailchaser.com/r/campaigns/123" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"id": 123,
"message": "campaign deleted successfully"
}Move a lead to another campaign
Removes a lead from the source campaign (deleting its unsent emails) and adds it to the target campaign. If the target campaign is running, emails for the lead are enqueued.
Parameters
- id integer required in path
Source campaign ID
- leadId integer required in path
Lead ID
Request bodyJSON · MoveLeadRequest
- targetCampaignId integer required
Responses
- 200 Lead moved successfully · MoveLeadResponse
- 400 Invalid campaign ID, lead ID or request body · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 403 Forbidden - lead does not belong to your space · ErrorForbidden
- 404 Campaign, target campaign or lead not found · ErrorCampaignNotFound
- 500 Failed to move lead · ErrorFailedToMoveLead
Fields in the 200 response
- leadId integerExample:
123 - message stringExample:
lead moved successfully - sourceCampaignId integerExample:
1 - targetCampaignId integerExample:
2
Request
curl -X POST "https://api.emailchaser.com/r/campaigns/123/leads/123/move" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"targetCampaignId": 123
}'Response
{
"leadId": 123,
"message": "lead moved successfully",
"sourceCampaignId": 1,
"targetCampaignId": 2
}Pause a campaign
Pauses a running campaign and cancels all scheduled emails.
Parameters
- id integer required in path
Campaign ID
Responses
- 200 Campaign paused successfully · PauseCampaignResponse
- 400 Invalid campaign ID · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 500 Failed to pause campaign · ErrorFailedToPauseCampaign
Fields in the 200 response
- campaign object
3 fields inside campaign
- id integerExample:
123 - name stringExample:
Q1 Outreach Campaign - status stringExample:
paused
- message stringExample:
campaign paused successfully
Request
curl -X POST "https://api.emailchaser.com/r/campaigns/123/pause" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"campaign": {
"id": 123,
"name": "Q1 Outreach Campaign",
"status": "paused"
},
"message": "campaign paused successfully"
}Launch or resume a campaign
Launches a new campaign or resumes a paused campaign. Validates campaign configuration before launching: the campaign needs sending days, at least one email account, a sequence, and, unless its flow is api, at least one lead. A missing one is refused with 400 and an error naming it.
Parameters
- id integer required in path
Campaign ID
Responses
- 200 Campaign launched/resumed successfully · LaunchCampaignResponse
- 400 Campaign validation failed (missing configuration) · ErrorCampaignValidation
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 409 Campaign is currently processing leads · ErrorResponse
- 500 Failed to launch/resume campaign · ErrorFailedToLaunchCampaign
Fields in the 200 response
- campaign object
3 fields inside campaign
- id integerExample:
123 - name stringExample:
Q1 Outreach Campaign - status stringExample:
running
- message stringExample:
campaign launched/resumed successfully
Request
curl -X POST "https://api.emailchaser.com/r/campaigns/123/resume" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"campaign": {
"id": 123,
"name": "Q1 Outreach Campaign",
"status": "running"
},
"message": "campaign launched/resumed successfully"
}Update campaign schedule
Updates the sending schedule for a campaign including timezone, days, time windows, and frequency. daysSchedule is sent as an array of days, but the response returns it as one comma-separated string of weekday numbers, such as "1,2,3,4,5". GET /campaigns/{id} returns it the same way.
Parameters
- id integer required in path
Campaign ID
Request bodyJSON · UpdateCampaignScheduleRequest
- daysSchedule array of string
DaysSchedule is the set of weekdays the campaign may send on. Accepts weekday numbers as strings, where Sunday is 0 ("1" is Monday), or weekday names such as "monday". Names are matched case-insensitively and common short forms ("mon", "tues") work. It is sent as an array, but stored as numbers and returned as one comma-separated string: a request sending Monday to Friday by name reads back as "1,2,3,4,5".
For multiple leads scheduled campaigns (flow 3) and API campaigns.
Example:["1","2","3","4","5"] - endSchedule string
- everySchedule integerMinimum 1
- maximumTimeBetweenEmails integerMinimum 2. Maximum 30
- minimumTimeBetweenEmails integerMinimum 2. Maximum 30
- sendAt string
For single lead scheduled campaigns (flow 2)
- startSchedule string
- timezone string required
Common field for all flows
Responses
- 200 Campaign schedule updated successfully · UpdateCampaignScheduleResponse
- 400 Invalid request body or schedule configuration · ErrorResponse
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 500 Failed to update campaign schedule · ErrorResponse
Fields in the 200 response
- campaign object
9 fields inside campaign
- daysSchedule string
DaysSchedule comes back as one comma-separated string of weekday numbers, where Sunday is 0, even though the request sends an array.
Example:1,2,3,4,5 - endSchedule stringExample:
17:00 - everySchedule integerExample:
30 - id integerExample:
123 - maximumTimeBetweenEmails integerExample:
15 - minimumTimeBetweenEmails integerExample:
5 - name stringExample:
Q1 Outreach Campaign - startSchedule stringExample:
09:00 - timezone stringExample:
America/New_York
- message stringExample:
campaign schedule updated successfully
Request
curl -X PUT "https://api.emailchaser.com/r/campaigns/123/schedule" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"daysSchedule": [
"1",
"2",
"3",
"4",
"5"
],
"endSchedule": "string",
"everySchedule": 1,
"maximumTimeBetweenEmails": 2,
"minimumTimeBetweenEmails": 2,
"sendAt": "string",
"startSchedule": "string",
"timezone": "America/New_York"
}'Response
{
"campaign": {
"daysSchedule": "1,2,3,4,5",
"endSchedule": "17:00",
"everySchedule": 30,
"id": 123,
"maximumTimeBetweenEmails": 15,
"minimumTimeBetweenEmails": 5,
"name": "Q1 Outreach Campaign",
"startSchedule": "09:00",
"timezone": "America/New_York"
},
"message": "campaign schedule updated successfully"
}Attach sender emails to a campaign
Attaches connected sender emails from your workspace to a campaign. A running campaign only sends through the sender emails attached to it, so this call decides which mailboxes the campaign uses. Idempotent: already-attached senders are left untouched and only missing ones are added. The call is refused whole when any requested sender email is not yours (404) or not connected (409). Attaching to a running campaign triggers a reschedule so the new senders are picked up.
Parameters
- id integer required in path
Campaign ID
Request bodyJSON · AttachCampaignSendersRequest
- senderEmailIds array of integer required
SenderEmailIDs are the sender emails to attach. Every ID must be a connected sender email in your workspace; the call is refused whole if any is not.
At least 1 item. Example:[1,2]
Responses
- 200 Sender emails attached · AttachCampaignSendersResponse
- 400 Invalid campaign ID or request body · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign or sender email not found · ErrorCampaignNotFound
- 409 Sender email is not connected · ErrorSenderEmailNotConnected
- 500 Failed to attach sender emails · ErrorResponse
Fields in the 200 response
- alreadyAttached array of integer
AlreadyAttached lists the requested sender emails that were attached before this call (the call is idempotent: they are left untouched).
Example:[3] - attached array of integer
Attached lists the sender emails newly attached by this call.
Example:[1,2] - campaignId integerExample:
10 - message stringExample:
sender emails attached successfully - senderEmailIds array of integer
SenderEmailIDs lists every sender email attached to the campaign after this call.
Example:[1,2,3]
Request
curl -X POST "https://api.emailchaser.com/r/campaigns/123/sender-emails" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"senderEmailIds": [
1,
2
]
}'Response
{
"alreadyAttached": [
3
],
"attached": [
1,
2
],
"campaignId": 10,
"message": "sender emails attached successfully",
"senderEmailIds": [
1,
2,
3
]
}Detach a sender email from a campaign
Detaches a sender email from a campaign. A running campaign only sends through the sender emails attached to it, so after this call the campaign stops sending through this mailbox: unsent follow-ups to emails this sender already sent are canceled, the sender is removed from the campaign's unsent emails, and a running campaign is rescheduled onto its remaining senders. Emails already sent are untouched. Idempotent: detaching a sender that is not attached is a no-op.
Parameters
- id integer required in path
Campaign ID
- senderEmailId integer required in path
Sender Email ID
Responses
- 200 Sender email detached · DetachCampaignSenderResponse
- 400 Invalid campaign or sender email ID · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign or sender email not found · ErrorCampaignNotFound
- 500 Failed to detach sender email · ErrorResponse
Fields in the 200 response
- campaignId integerExample:
10 - detached boolean
Detached is false when the sender email was not attached to the campaign (the call is idempotent and does nothing in that case).
Example:true - message stringExample:
sender email detached successfully - senderEmailIds array of integer
SenderEmailIDs lists every sender email still attached to the campaign after this call.
Example:[2,3]
Request
curl -X DELETE "https://api.emailchaser.com/r/campaigns/123/sender-emails/123" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"campaignId": 10,
"detached": true,
"message": "sender email detached successfully",
"senderEmailIds": [
2,
3
]
}Get a campaign's sequence
Returns the ordered emails that make up a campaign's sequence, including any A/B variants. delayDays on each step is counted from the previous step; the first step is always 0.
Parameters
- id integer required in path
Campaign ID
Responses
- 200 Campaign sequence · GetSequenceResponse
- 400 Invalid campaign ID · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 500 Failed to retrieve campaign sequence · ErrorFailedToRetrieveSequence
Fields in the 200 response
- campaignId integerExample:
8589949820 - signature stringExample:
<p>Robby Frank</p> - steps array of SequenceStep
7 fields inside steps
- body stringExample:
<p>Hi {first_name},</p> - contentType stringExample:
html - delayDays integerExample:
0 - order integerExample:
1 - subject stringExample:
Quick question, {first_name} - useSameThread booleanExample:
true - variants array of SequenceVariant
- total integerExample:
3
Request
curl -X GET "https://api.emailchaser.com/r/campaigns/123/sequence" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"campaignId": 8589949820,
"signature": "<p>Robby Frank</p>",
"steps": [
{
"body": "<p>Hi {first_name},</p>",
"contentType": "html",
"delayDays": 0,
"order": 1,
"subject": "Quick question, {first_name}",
"useSameThread": true,
"variants": [
{
"body": "<p>Hi {first_name},</p>",
"label": "B",
"subject": "Quick question about {company_name}"
}
]
}
],
"total": 3
}Replace a campaign's sequence
Replaces the campaign's whole sequence with the steps provided. The operation is idempotent, so sending the same payload twice leaves the same state and a retried request cannot duplicate steps. delayDays is counted from the previous step and the first step must be 0. Editing a running campaign is allowed and re-queues future sends; already-sent emails are untouched. Merge tags take ONE brace, e.g. {first_name}, {last_name}, {company_name}, {job_title}, plus any key set in a lead's customVariables; a fallback is {first_name}[there] or {first_name|there}. Placeholders written in another tool's syntax ({{first_name}}, [[first_name]], [First Name]) are rejected with a 400 that names the tag to write instead, because they are not substituted and would be sent exactly as typed ("Hi [First Name],").
Parameters
- id integer required in path
Campaign ID
Request bodyJSON · ReplaceSequenceRequest
- signature string
Signature omitted keeps the campaign's current signature; pass an empty string to clear it. Editing one body should not silently drop a signature the caller never asked about.
- At least 1 item. At most 20 items
7 fields inside steps
- body string requiredAt least 1 characters
- contentType stringOne of: "html", "text"
- delayDays integerMinimum 0. Maximum 365
- order integerMinimum 1
- subject string requiredAt least 1 characters. At most 998 characters
- useSameThread boolean
- variants array of SequenceVariantInputAt most 25 items
3 fields inside variants
- body string
- label string requiredAt least 1 characters. At most 2 characters
- subject string requiredAt least 1 characters. At most 998 characters
Responses
- 200 Campaign sequence replaced successfully · ReplaceSequenceResponse
- 400 Invalid campaign ID or sequence payload · ErrorInvalidSequence
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 422 Campaign flow does not support sequences · ErrorUnsupportedCampaignFlow
- 500 Failed to replace campaign sequence · ErrorFailedToReplaceSequence
Fields in the 200 response
- campaignId integerExample:
8589949820 - message stringExample:
campaign sequence replaced successfully - signature stringExample:
<p>Robby Frank</p> - steps array of SequenceStep
7 fields inside steps
- body stringExample:
<p>Hi {first_name},</p> - contentType stringExample:
html - delayDays integerExample:
0 - order integerExample:
1 - subject stringExample:
Quick question, {first_name} - useSameThread booleanExample:
true - variants array of SequenceVariant
- total integerExample:
3
Request
curl -X PUT "https://api.emailchaser.com/r/campaigns/123/sequence" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"signature": "string",
"steps": [
{
"body": "string",
"contentType": "html",
"delayDays": 123,
"order": 1,
"subject": "Quick question about Acme",
"useSameThread": true,
"variants": [
{
"body": "string",
"label": "string",
"subject": "Quick question about Acme"
}
]
}
]
}'Response
{
"campaignId": 8589949820,
"message": "campaign sequence replaced successfully",
"signature": "<p>Robby Frank</p>",
"steps": [
{
"body": "<p>Hi {first_name},</p>",
"contentType": "html",
"delayDays": 0,
"order": 1,
"subject": "Quick question, {first_name}",
"useSameThread": true,
"variants": [
{
"body": "<p>Hi {first_name},</p>",
"label": "B",
"subject": "Quick question about {company_name}"
}
]
}
],
"total": 3
}Get campaign performance stats
Returns campaign performance in one call: totals, per-A/B-variant results, per-sequence-step results, and a daily (UTC) time series. Sent and bounced count outbound emails; replied and positive count distinct leads; totals.meetings counts the campaign's leads with a booked meeting recorded (see POST /leads/{id}/meeting). Variant sent counts initial emails only, while steps attribute replies to the exact email that was answered. There is no opens metric anywhere in this response: Emailchaser does not track opens, so its absence is deliberate, not an omission.
Parameters
- id integer required in path
Campaign ID
Responses
- 200 Campaign performance stats · GetCampaignStatsResponse
- 400 Invalid campaign ID · ErrorInvalidCampaignID
- 401 Unauthorized - invalid or missing API key · ErrorUnauthorized
- 404 Campaign not found · ErrorCampaignNotFound
- 500 Failed to retrieve campaign stats · ErrorResponse
Fields in the 200 response
- campaignId integerExample:
123 - daily array of CampaignStatsDay
4 fields inside daily
- date stringExample:
2026-07-01 - positive integerExample:
1 - replied integerExample:
3 - sent integerExample:
40
- steps array of CampaignStatsStep
3 fields inside steps
- index integerExample:
0 - replied integerExample:
45 - sent integerExample:
600
- totals CampaignStatsTotals
5 fields inside totals
- bounced integerExample:
14 - meetings integerExample:
7 - positive integerExample:
32 - replied integerExample:
85 - sent integerExample:
1200
- variants array of CampaignStatsVariant
4 fields inside variants
- label stringExample:
A - positive integerExample:
18 - replied integerExample:
45 - sent integerExample:
600
Request
curl -X GET "https://api.emailchaser.com/r/campaigns/123/stats" \
-H "Authorization: Bearer $EMAILCHASER_API_KEY"Response
{
"campaignId": 123,
"daily": [
{
"date": "2026-07-01",
"positive": 1,
"replied": 3,
"sent": 40
}
],
"steps": [
{
"index": 0,
"replied": 45,
"sent": 600
}
],
"totals": {
"bounced": 14,
"meetings": 7,
"positive": 32,
"replied": 85,
"sent": 1200
},
"variants": [
{
"label": "A",
"positive": 18,
"replied": 45,
"sent": 600
}
]
}Generated from the Emailchaser API's own OpenAPI definition, so it always matches the running API.