API referenceCampaigns
PATCH
/campaigns/{id}

JavaScript SDK: swarmhit.campaigns.update(campaignId, params)

Updates any subset of a campaign's writable fields: name, status (set active to start sending, paused to stop), the sender pool (linkedinAccountIds), the outreach sequence, the send schedule, aiInterestEnabled, the email unsubscribe line and tracking, and the lead-exclusion rules (excludeListIds plus the exclude* flags). sequence and schedule are replaced wholesale — send the complete object you want, not a partial patch of it.

A full sequence replacement can update the content of any step or A/B variant. For variant A, keep the step's legacy flat copy/media fields identical to the corresponding values in config.variants[0]; conflicting values are rejected with 400. Updating a later variant only requires changing that variant object. For a single existing step or variant, prefer PATCH /campaigns/{id}/sequence/{stepId} so unrelated sequence structure cannot be overwritten.

Once a campaign has leads in progress, the sequence may only be edited safely: you can change step messages and delays and append new steps, but removing, reordering or retyping existing steps is rejected with 400 (a lead's progress is pinned to a step id). Duplicate the campaign to rework its sequence from scratch.

An active campaign must keep at least one sender: sending an empty linkedinAccountIds while the campaign is (or is being set) active is rejected with 400.

A campaign won't go active while a step has nothing to send: a message, inmail, email or whatsapp_message variant with no text (a file alone will do on a message or whatsapp_message), a voice_note without its recording, an ai_voice_note without its script, or the first email of a path without a subject. That is a 400 with code: empty-step: message names the steps by their number in the sequence, and details.steps lists them ([{ id, type }]) to fix with PATCH /campaigns/{id}/sequence/{stepId}. Once a campaign has been launched, a sequence that empties a step is refused the same way.

With accounts of senders in its pools, a campaign won't go active, nor an active one change its pools, while a sender (or an account without one on the primary channel: LinkedIn when the sequence has a LinkedIn step or no step, else email, else WhatsApp) has no account on a channel the sequence uses and no account without a sender is there to share: a 400 with code: sender-no-mailbox or sender-no-whatsapp. Attaching senders with senderIds has its own refusals, listed there.

Authorization

bearerAuth
AuthorizationBearer <token>

An API key created on the Access tokens page.

In: header

Path Parameters

id*string

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Any subset of these fields. For a copy-only change to an existing sequence step, use PATCH /campaigns/{id}/sequence/{stepId}. If a full sequence contains both legacy flat content fields and config.variants, their variant-A copy and media values must agree.

Response Body

application/json

application/json

application/json

application/json

curl -X PATCH "https://example.com/campaigns/string" \  -H "Content-Type: application/json" \  -d '{    "status": "active"  }'
{  "data": {    "id": "string",    "name": "string",    "status": "draft",    "stats": {      "total": 0,      "done": 0,      "failed": 0    },    "aiInterestEnabled": true,    "unsubscribe": {      "enabled": true,      "text": "string"    },    "tracking": {      "opens": "mailbox",      "clicks": "mailbox"    },    "linkedinAccountIds": [      "string"    ],    "emailAccountIds": [      "string"    ],    "whatsappAccountIds": [      "string"    ],    "senderIds": [      "string"    ],    "excludeListIds": [      "string"    ],    "listId": "string",    "excludeOtherCampaigns": true,    "excludeOtherSenders": true,    "excludeSameSenderOtherCampaigns": true,    "companyLimit": {      "max": 1,      "period": "day",      "scope": "campaign"    },    "pauseCompanyOnReply": true,    "outOfOffice": {      "enabled": true,      "fallbackDays": 7    },    "matchEmailProvider": true,    "schedule": {      "startDate": "2019-08-24T14:15:22Z",      "endDate": "2019-08-24T14:15:22Z",      "timezone": "string",      "activeHours": {        "from": "string",        "to": "string"      },      "activeDays": [        0      ]    },    "createdAt": "2019-08-24T14:15:22Z",    "updatedAt": "2019-08-24T14:15:22Z",    "sequence": {      "steps": [        {          "id": "string",          "type": "if_connected",          "parent": "string",          "branch": "yes",          "config": {},          "nextDelayHours": 0,          "branchDelays": {            "yes": 0,            "no": 0          }        }      ]    }  }}