Email sequences
A campaign's email sequence: read, replace or delete it, preview it for one contact and send a test.
Return the campaign email sequence
/v1/campaigns/{campaignId}/email-sequenceemail-sequences.getParameters
400 workspace_required).Response 200
data is a EmailSequenceModel.
curl -X GET "https://api.ken.so/v1/campaigns/812/email-sequence" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": {
"id": 2210,
"campaignId": 4821,
"segmentId": 1207,
"name": "Engineering leaders",
"isActive": true,
"steps": [
{
"id": 8841,
"stepOrder": 1,
"variant": "a",
"subject": "Onboarding new engineers at {{company}}",
"body": "Hi {{first_name}},\n\nMost engineering teams lose a new hire's first two weeks to setup and access requests. We help teams like yours get that down to two days.\n\nWorth a 15-minute look next week?\n\n{{sender_first_name}}",
"bodyFormat": "plain",
"waitDays": 0,
"isActive": true,
"openTrackingEnabled": false,
"handwrittenEnabled": false
},
{
"id": 8842,
"stepOrder": 2,
"variant": "a",
"subject": "",
"body": "Hi {{first_name}}, following up on this. Happy to send a 2-minute video instead if that is easier.\n\n{{sender_first_name}}",
"bodyFormat": "plain",
"waitDays": 3,
"isActive": true,
"openTrackingEnabled": false,
"handwrittenEnabled": false
}
],
"createdAt": "2026-09-23T15:02:11Z",
"modifiedAt": "2026-10-14T09:41:27Z"
}
}Replace the campaign email sequence
/v1/campaigns/{campaignId}/email-sequenceemail-sequences.replaceCreates the sequence when none exists. Requires SequenceEditAccess. A link the URL reputation check refuses is 400 validation_failed with one link_reputation_blocked detail per link: fieldsteps[i].subject or steps[i].body, rule, stepOrder and, for a saved step, stepId. Send expectedModifiedAt (the modifiedAt from your last read) so an edit made since is not overwritten.
Parameters
400 workspace_required).Request body
application/json, optional.
modifiedAt from your last read. When the live sequence changed since, the replace is refused with 409 conflict and detail code stale_write, so you do not overwrite someone else's edit.Response 200
data is a EmailSequenceModel.
curl -X PUT "https://api.ken.so/v1/campaigns/812/email-sequence" \
-H "Authorization: Bearer $KEN_API_KEY" \
-H "Ken-Version: 2026-11-02" \
-H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"isActive": true,
"steps": [
{
"id": 812,
"stepOrder": 1,
"variant": "string",
"name": "string",
"subject": "string",
"body": "string",
"bodyFormat": "string",
"waitDays": 1,
"isActive": true,
"openTrackingEnabled": true,
"handwrittenEnabled": true,
"handwrittenBackground": "string",
"handwrittenIntro": "string",
"studioTemplateVersionId": 812
}
],
"expectedModifiedAt": "2026-09-23T15:02:11Z"
}'{
"success": true,
"data": {
"id": 2210,
"campaignId": 4821,
"segmentId": 1207,
"name": "Engineering leaders",
"isActive": true,
"steps": [
{
"id": 8841,
"stepOrder": 1,
"variant": "a",
"subject": "Onboarding new engineers at {{company}}",
"body": "Hi {{first_name}},\n\nMost engineering teams lose a new hire's first two weeks to setup and access requests. We help teams like yours get that down to two days.\n\nWorth a 15-minute look next week?\n\n{{sender_first_name}}",
"bodyFormat": "plain",
"waitDays": 0,
"isActive": true,
"openTrackingEnabled": false,
"handwrittenEnabled": false
},
{
"id": 8842,
"stepOrder": 2,
"variant": "a",
"subject": "",
"body": "Hi {{first_name}}, following up on this. Happy to send a 2-minute video instead if that is easier.\n\n{{sender_first_name}}",
"bodyFormat": "plain",
"waitDays": 3,
"isActive": true,
"openTrackingEnabled": false,
"handwrittenEnabled": false
}
],
"createdAt": "2026-09-23T15:02:11Z",
"modifiedAt": "2026-10-14T09:41:27Z"
}
}Delete the campaign email sequence
/v1/campaigns/{campaignId}/email-sequenceemail-sequences.deleteParameters
400 workspace_required).Response 204
curl -X DELETE "https://api.ken.so/v1/campaigns/812/email-sequence" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
HTTP/1.1 204 No Content
Preview the campaign email sequence for one contact
/v1/campaigns/{campaignId}/email-sequence/previewemail-sequences.previewRequires ReadAccess. Variable types are lowercase snake_case. Each step shows the text dispatch sends the contact: a contact routed to another language gets the approved localization with its language, English mirrorSubject and mirrorBody, and qaScore. language previews as a contact in that language instead. Pass contactId, or useRandom=true to preview a random contact of the campaign; with neither the call is 400 validation_failed on contactId. A contact outside the campaign, or a campaign with no contacts to pick, is 404 not_found. senderEmailId previews from that inbox of the campaign, as the test send sends from it: its names, signature and unsubscribe host fill the steps, and sender names it. Without it, or with an inbox the campaign does not use, the first sender by email fills them.
Parameters
senderEmailId: its names, signature and unsubscribe host fill the steps, and sender names it. An inbox that is not one of the campaign's, or none, previews from the first sender.400 workspace_required).Response 200
data is a EmailSequencePreviewModel.
curl -X GET "https://api.ken.so/v1/campaigns/812/email-sequence/preview" \ -H "Authorization: Bearer $KEN_API_KEY" \ -H "Ken-Version: 2026-11-02" \ -H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID"
{
"success": true,
"data": {
"steps": [
{
"stepNumber": 1,
"subject": "string",
"body": "string",
"waitDays": 1,
"variables": [
{
"name": "string",
"type": "string",
"value": "string",
"placeholder": "string"
}
],
"language": "string",
"mirrorSubject": "string",
"mirrorBody": "string",
"qaScore": 1
}
],
"contact": {
"id": 812,
"fullName": "string",
"company": "string",
"title": "string",
"email": "[email protected]"
},
"sender": {
"id": 812,
"email": "[email protected]",
"status": "string",
"warmupReputation": 1,
"healthScore": 0.5
},
"senders": [
{
"id": 812,
"email": "[email protected]",
"status": "string",
"warmupReputation": 1,
"healthScore": 0.5
}
]
}
}Send the campaign email sequence to test recipients
/v1/campaigns/{campaignId}/email-sequence/test-sendemail-sequences.test-sendtargetEmails takes at most 5 valid addresses, none on the workspace blocklist or hard bounced. Once the campaign has inboxes, senderEmailId must be one of them. Each recipient x step counts against the workspace's daily test-send emails (429 when used up). Requires SequenceEditAccess. Each step goes out as dispatch sends it to the contact, in the contact's language or in language; notes names a step sent as an approved translation.
Parameters
400 workspace_required).Request body
application/json, optional.
Response 200
data is a EmailSequenceTestSendModel.
curl -X POST "https://api.ken.so/v1/campaigns/812/email-sequence/test-send" \
-H "Authorization: Bearer $KEN_API_KEY" \
-H "Ken-Version: 2026-11-02" \
-H "X-Ken-Workspace-Id: $KEN_WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '{
"contactId": 812,
"targetEmails": "string",
"senderEmailId": 812,
"language": "string"
}'{
"success": true,
"data": {
"stepsSent": 1,
"emailsAttempted": 1,
"emailsSent": 1,
"sentTo": [
"string"
],
"failures": [
"string"
],
"notes": [
"string"
]
}
}