Less boo. More booked. Halloween offer: 30 days free on any paid plan. Claim 30 days freeEvery new account gets one free mailbox for warmup and replies. No domain to buy. See how it works

Skip to content

Steps

API referenceCampaigns

From the Campaigns API reference. Requests use the base URL https://app.warmerly.com/api/v1 and an API key, see Authentication.

Steps are the ordered sequence of touches (email, LinkedIn) leads move through, with a delay before each one.

API reference

#List steps

text
GET /campaigns/{id}/steps

steps is the sequence in send order. This is the field to read. The response also carries nodes, edges and entryStepId, the same steps as a graph, which the dashboard's visual editor uses; you can ignore them.

A step's waitDays / waitHours is the delay before that step sends, counted from the previous step (the first step's delay is counted from when the lead enters the campaign).

json
{
  "steps": [
    {
      "id": "c1b2a3d4-1111-4b7a-8e2a-1a2b3c4d5e6f",
      "campaignId": "b6a1e7b0-2f2b-4b7a-8e2a-1a2b3c4d5e6f",
      "stepOrder": 1,
      "kind": "email",
      "subject": "Quick question about {{companyName}}",
      "bodyText": "Hi {{firstName}}, ...",
      "bodyHtml": null,
      "waitDays": 0,
      "waitHours": 0,
      "variants": [],
      "createdAt": "2026-06-01T09:00:00.000Z"
    },
    {
      "id": "c1b2a3d4-3333-4b7a-8e2a-1a2b3c4d5e6f",
      "campaignId": "b6a1e7b0-2f2b-4b7a-8e2a-1a2b3c4d5e6f",
      "stepOrder": 2,
      "kind": "email",
      "subject": "Following up",
      "bodyText": "Hi {{firstName}}, just bumping this...",
      "bodyHtml": null,
      "waitDays": 3,
      "waitHours": 0,
      "variants": [],
      "createdAt": "2026-06-01T09:00:00.000Z"
    }
  ],
  "nodes": ["…the same steps…"],
  "edges": ["…how they connect…"],
  "entryStepId": "c1b2a3d4-1111-4b7a-8e2a-1a2b3c4d5e6f"
}

Each step is the stored step row, so it has further fields than shown (for example aiPersonalize, variantMinSampleSize, and the editor's positionX / positionY), and variants lists any A/B variants. kind is one of email, linkedin_connection, linkedin_message.

API reference

#Replace steps

text
PUT /campaigns/{id}/steps

Replace-all: send the whole sequence, in order, as steps (up to 50 entries). stepOrder is assigned from array position, don't send it yourself.

FieldTypeRequired
kind"email" \| "wait" \| "linkedin_connection" \| "linkedin_message"no (default "email")
subjectstring or nullno (needed for an email step to send)
bodyTextstring or nullno (needed for an email step to send)
bodyHtmlstring or nullno
waitDaysinteger (0-365)no (default 0)
waitHoursinteger (0-23)no (default 0)

Two ways to space steps out, and you can mix them:

  • put waitDays / waitHours on the step itself, or
  • insert a { "kind": "wait", "waitDays": 3 } entry between two steps.

A wait entry is not stored as a step of its own. Its delay is added to the next step, so GET returns the example below as two steps, the second with waitDays: 3. A wait at the very end is dropped (there is nothing after it to delay).

Subjects and bodies support merge tags: {{firstName}}, {{lastName}}, {{companyName}}, {{email}}, the sender's {{senderFirstName}} / {{senderName}}, and any customVars key you set on the campaign's leads.

Editing a running campaign: the Nth email step you send keeps the id of the campaign's existing Nth email step, so rewriting the copy of a live sequence does not move leads off the step they are on. On an active or paused campaign, removing a step that leads are currently waiting at is refused with a 409 (step_in_use, with the step ids and lead counts in error.details) and nothing is changed.

bash
curl -X PUT https://app.warmerly.com/api/v1/campaigns/b6a1e7b0-2f2b-4b7a-8e2a-1a2b3c4d5e6f/steps   -H "X-Api-Key: wmv_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"   -H "Content-Type: application/json"   -d '{
    "steps": [
      { "kind": "email", "subject": "Quick question about {{companyName}}", "bodyText": "Hi {{firstName}}, ..." },
      { "kind": "wait", "waitDays": 3 },
      { "kind": "email", "subject": "Following up", "bodyText": "Hi {{firstName}}, just bumping this..." }
    ]
  }'

Returns the saved sequence in the same shape as GET /campaigns/{id}/steps.

Statuserror.codeWhen
400bad_requestThe body is not a valid steps array (the details name the field)
404not_foundThe campaign doesn't exist or isn't yours
409step_in_useYou removed a step leads are currently waiting at, on an active or paused campaign
Was this page helpful?