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