JavaScript SDK: swarmhit.campaigns.updateStep(campaignId, stepId, params)
Partially updates one existing sequence step's copy and/or media while
preserving its id, wiring, delays and other A/B variants. Use the step
and variant ids returned by GET /campaigns/{id}. When variantId is
omitted, variant A is updated; pass another existing variantId to
update that variant without changing variant A. This endpoint is
preferred over replacing the full sequence for copy, attachment and
recorded-voice edits, except for a recorded voice note that records per
sender: those recordings are replaced through the campaign's sequence.
On a launched campaign, an update that leaves the step with nothing to
send is a 400 with code: empty-step (see
PATCH /campaigns/{id}).
Authorization
bearerAuth An API key created on the Access tokens page.
In: header
Path Parameters
Stable sequence step id returned by the campaign detail.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Content fields depend on the target step type: message uses
text/fallbackText; invite uses note/fallbackNote; InMail and
email also accept subject/fallbackSubject; AI voice note uses
script/fallbackScript; comment post uses prompt; call uses
instructions. Message and
InMail accept attachments only (a voice on them is refused: voice
notes have their own steps); recorded voice note accepts voice. A
recorded voice note that records per sender (its config
carries voiceAssignments) is rejected here: its recordings live per
sender, not per variant, so replace them through the campaign's
sequence instead.
Content fields depend on the target step type: message uses
text/fallbackText; invite uses note/fallbackNote; InMail and
email also accept subject/fallbackSubject; AI voice note uses
script/fallbackScript; comment post uses prompt; call uses
instructions. Message and
InMail accept attachments only (a voice on them is refused: voice
notes have their own steps); recorded voice note accepts voice. A
recorded voice note that records per sender (its config
carries voiceAssignments) is rejected here: its recordings live per
sender, not per variant, so replace them through the campaign's
sequence instead.
Response Body
application/json
application/json
application/json
application/json
curl -X PATCH "https://example.com/campaigns/string/sequence/string" \ -H "Content-Type: application/json" \ -d '{ "text": "{{firstName}}, is that the kind of gap you run into too?" }'{ "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 } } ] } }}Update a campaign PATCH
**JavaScript SDK:** [`swarmhit.campaigns.update(campaignId, params)`](/smart-api/sdk/methods#campaigns) 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.
List supported filters GET
**JavaScript SDK:** [`swarmhit.database.capabilities()`](/smart-api/sdk/methods#database) The filters, company sorts and suggestion fields the database supports for this workspace. The set can be narrower than the full filter list documented on the search endpoints; a search using a filter that is not listed here is rejected with 400 and the filter named. Free, no credits. An entity is `null` when the database is unavailable for it.