Update campaign
Update campaign name, sequence, schedule, settings, or mailbox assignments. Mailboxes can be reassigned using any combination of mailboxIds, mailboxEmails, mailboxTags, or mailboxProvider.
curl -X PATCH "https://api.sendkit.ai/v1/campaigns/example_string" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "Q1 Outreach Campaign (Updated)",
"schedule": {
"startTime": "10:00",
"endTime": "18:00",
"skipNationalHolidays": false
},
"settings": {
"stopOnAutoReply": false,
"dailySendLimit": 100,
"espMatchingMode": "auto",
"segCheckMode": "skip_providers",
"segSkipProviders": [
"proofpoint",
"mimecast",
"barracuda"
],
"webhook": {
"enabled": true,
"events": [
"lead.replied",
"email.opened"
]
},
"variantOptimization": {
"enabled": true,
"optimizationMetric": "openRate",
"minimumSendsPerVariant": 100
}
}
}'
import requests
import json
url = "https://api.sendkit.ai/v1/campaigns/example_string"
headers = {
"Content-Type": "application/json",
"X-Api-Key": "YOUR_API_KEY"
}
data = {
"name": "Q1 Outreach Campaign (Updated)",
"schedule": {
"startTime": "10:00",
"endTime": "18:00",
"skipNationalHolidays": false
},
"settings": {
"stopOnAutoReply": false,
"dailySendLimit": 100,
"espMatchingMode": "auto",
"segCheckMode": "skip_providers",
"segSkipProviders": [
"proofpoint",
"mimecast",
"barracuda"
],
"webhook": {
"enabled": true,
"events": [
"lead.replied",
"email.opened"
]
},
"variantOptimization": {
"enabled": true,
"optimizationMetric": "openRate",
"minimumSendsPerVariant": 100
}
}
}
response = requests.patch(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://api.sendkit.ai/v1/campaigns/example_string", {
method: "PATCH",
headers: {
"Content-Type": "application/json",
"X-Api-Key": "YOUR_API_KEY"
},
body: JSON.stringify({
"name": "Q1 Outreach Campaign (Updated)",
"schedule": {
"startTime": "10:00",
"endTime": "18:00",
"skipNationalHolidays": false
},
"settings": {
"stopOnAutoReply": false,
"dailySendLimit": 100,
"espMatchingMode": "auto",
"segCheckMode": "skip_providers",
"segSkipProviders": [
"proofpoint",
"mimecast",
"barracuda"
],
"webhook": {
"enabled": true,
"events": [
"lead.replied",
"email.opened"
]
},
"variantOptimization": {
"enabled": true,
"optimizationMetric": "openRate",
"minimumSendsPerVariant": 100
}
}
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"name": "Q1 Outreach Campaign (Updated)",
"schedule": {
"startTime": "10:00",
"endTime": "18:00",
"skipNationalHolidays": false
},
"settings": {
"stopOnAutoReply": false,
"dailySendLimit": 100,
"espMatchingMode": "auto",
"segCheckMode": "skip_providers",
"segSkipProviders": [
"proofpoint",
"mimecast",
"barracuda"
],
"webhook": {
"enabled": true,
"events": [
"lead.replied",
"email.opened"
]
},
"variantOptimization": {
"enabled": true,
"optimizationMetric": "openRate",
"minimumSendsPerVariant": 100
}
}
}`)
req, err := http.NewRequest("PATCH", "https://api.sendkit.ai/v1/campaigns/example_string", bytes.NewBuffer(data))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Api-Key", "YOUR_API_KEY")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
require 'net/http'
require 'json'
uri = URI('https://api.sendkit.ai/v1/campaigns/example_string')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(uri)
request['Content-Type'] = 'application/json'
request['X-Api-Key'] = 'YOUR_API_KEY'
request.body = '{
"name": "Q1 Outreach Campaign (Updated)",
"schedule": {
"startTime": "10:00",
"endTime": "18:00",
"skipNationalHolidays": false
},
"settings": {
"stopOnAutoReply": false,
"dailySendLimit": 100,
"espMatchingMode": "auto",
"segCheckMode": "skip_providers",
"segSkipProviders": [
"proofpoint",
"mimecast",
"barracuda"
],
"webhook": {
"enabled": true,
"events": [
"lead.replied",
"email.opened"
]
},
"variantOptimization": {
"enabled": true,
"optimizationMetric": "openRate",
"minimumSendsPerVariant": 100
}
}
}'
response = http.request(request)
puts response.body
{
"success": true,
"data": {
"_id": "665a1b2c3d4e5f6a7b8c9d0e",
"name": "Q1 Outreach Campaign (Updated)",
"status": "draft",
"sendingSchedule": {
"timezone": "America/New_York",
"startTime": "08:00",
"endTime": "18:00",
"workingDays": [
1,
2,
3,
4,
5
]
},
"createdAt": "2025-06-10T10:30:00.000Z",
"updatedAt": "2025-06-12T08:00:00.000Z"
}
}
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Campaign not found"
}
}
/v1/campaigns/{campaignId}Target server for requests. Edit to use your own host.
Platform API key (sk_user_...) or Workspace API key (sk_...)
Campaign ID
The media type of the request body
Campaign name
Replace the entire email sequence
REPLACES the entire subsequences array on the campaign — to preserve
existing subsequences across edits, fetch the campaign first, modify
the array, and submit it back (each subsequence keeps its _id /
id to retain identity and avoid orphaning leads enrolled in it).
Same validation rules apply as on POST: max 15 active (non-archived)
subsequences per campaign; at most one active subsequence may have
trigger.type='reply'; active ai_tag-trigger values must be unique
(case-insensitive); inner sequence may start with a wait
(subseq-only relaxation); trigger is immutable once a subsequence has
sent any emails — attempting to change it returns 400 TRIGGER_IMMUTABLE
(archive and create a new one instead).
Update sending schedule (merged into existing)
All settings are optional and merge into existing values
Request Preview
Response
Response will appear here after sending the request
Authentication
API Key for authentication. Platform API key (sk_user_...) or Workspace API key (sk_...)
Path Parameters
Campaign ID
Body
Campaign name
Replace the entire email sequence
emailwaitA/B test variants. If omitted on an email/follow-up step, a default variant "A" is auto-seeded from the step's subject/body so the sender always has something to send.
Single uppercase letter A-Z. Unique within the step; need not be sequential or start at A.
REPLACES the entire subsequences array on the campaign — to preserve
existing subsequences across edits, fetch the campaign first, modify
the array, and submit it back (each subsequence keeps its _id /
id to retain identity and avoid orphaning leads enrolled in it).
Same validation rules apply as on POST: max 15 active (non-archived)
subsequences per campaign; at most one active subsequence may have
trigger.type='reply'; active ai_tag-trigger values must be unique
(case-insensitive); inner sequence may start with a wait
(subseq-only relaxation); trigger is immutable once a subsequence has
sent any emails — attempting to change it returns 400 TRIGGER_IMMUTABLE
(archive and create a new one instead).
Subsequence ID (the _id of the subdocument)
What causes a lead to enter this subsequence. With type='ai_tag', the
subsequence fires when the lead's AI tag (set by reply classification or
manual tagging) matches value (case-insensitive); manual tag changes via
the campaign-lead PATCH endpoint and the MCP tag_conversation tool also
enroll into matching subsequences. With type='reply', the subsequence
fires the first time the lead replies and value is ignored.
ai_tagreplyRequired when type is ai_tag. The AI tag value to match.
emailwaitAuto-assigned by the server (e.g., "Initial Email", "Follow-up 1", "Wait 3 days")
Plain text or HTML; auto-converted to TipTap-compatible HTML
A/B variants. If omitted on an email/follow-up step, a default variant "A" is auto-seeded from the step's subject/body.
Single uppercase letter A-Z. Unique within the step; need not be sequential or start at A.
Total leads that have ever entered this subsequence
Update sending schedule (merged into existing)
All settings are optional and merge into existing values
Controls how this campaign competes for shared mailbox capacity. Changes wake the worker so the new weights apply within ~15s.
autohighnormallowautofollow-ups-firstbalancednew-leads-firstdisabledautouse_specific_mailboxes is legacy and is normalized to disabled on write.
disabledskip_allskip_providersuse_specific_mailboxesEmail addresses to notify on replies. Max 5; submit [] to clear.
AI reply agent ObjectId. Must belong to this workspace — returns 400 AGENT_NOT_FOUND otherwise. Set to null to detach.
replyRateopenRateclickRateResponses
draftactivepausedcompletedarchivedemailwaitcustom is a legacy value kept for read-back compatibility; new writes only accept disabled or auto.
disabledautocustomLegacy custom ESP matching rules. Read-only; new writes are ignored.
use_specific_mailboxes is a legacy value kept for read-back compatibility; on write it is normalized to disabled.
disabledskip_allskip_providersuse_specific_mailboxesSEG provider names to skip when segCheckMode is skip_providers.
proofpointmimecastbarracudaciscoforcepointsophostrendmicrosymantecmcafeemicrosoft_atpgoogle_postiniLegacy field. Read-only; new writes are ignored.
allby_providerindividualLegacy field. Read-only; new writes are ignored.
Legacy field. Read-only; new writes are ignored.
Campaign not found