Skip to main content
Sequences are cold-outreach campaigns. You define an audience with lead criteria, a throttle that governs pacing and business hours, and then launch the sequence to enroll matching leads into a per-contact dispatch queue. Every endpoint on this page operates inside the calling organization’s tenant — you cannot read or write sequences from another organization with the same key.
Only the call channel is dispatchable today. SequenceChannel also defines whatsapp and email, but those channels are deferred. POST /sequences accepts channel: "call" only.

Lifecycle

A sequence moves through a fixed set of SequenceStatus states:
draft  →  running  ⇄  paused  →  completed
  • draft — newly created. Editable and deletable. Nothing is enqueued yet.
  • running — launched. The dispatch worker is processing the contact queue.
  • paused — temporarily halted. Resume to continue from where it left off.
  • completed — auto-set when the queue drains (every contact reached a terminal state). Terminal.
Transition rules — illegal transitions return 400 BAD_REQUEST:
ActionAllowed fromNotes
PATCH (edit)draft onlyOnce launched, the configuration is frozen.
DELETEdraft onlyLaunched sequences keep their contact history and cannot be deleted.
launchdraft onlyRequires a non-empty audience of at most 5000 eligible leads.
pauserunning only
resumepaused only

List sequences

GET /sequences
Scope: sequences:read. Returns every sequence for the organization, newest first. This endpoint is not paginated — it returns a flat data array.

Query parameters

ParamTypeNotes
statusenumOptional. Filter by SequenceStatus: draft, running, paused, or completed. An invalid value returns 400 VALIDATION_ERROR.

Response 200

Each sequence carries a progress object derived from its contact queue.
{
  "data": [
    {
      "id": "seq_...",
      "organizationId": "org_...",
      "name": "Q3 cold callbacks",
      "channel": "call",
      "status": "running",
      "criteria": {
        "statuses": ["new", "contacted"],
        "stageIds": ["b1f2...-uuid"],
        "sources": ["meta", "website"],
        "minScore": 40
      },
      "channelConfig": {},
      "throttle": {
        "maxPerMinute": 5,
        "businessHoursStart": "09:00",
        "businessHoursEnd": "18:00",
        "timezone": "America/Santo_Domingo",
        "weekdays": [1, 2, 3, 4, 5]
      },
      "createdBy": null,
      "createdAt": "2026-06-20T14:00:00.000Z",
      "updatedAt": "2026-06-21T09:30:00.000Z",
      "startedAt": "2026-06-21T09:30:00.000Z",
      "completedAt": null,
      "progress": {
        "total": 320,
        "pending": 210,
        "inProgress": 4,
        "sent": 100,
        "failed": 5,
        "skipped": 1
      }
    }
  ]
}

The progress object

Counts of contacts by SequenceContactStatus. total is the sum of the rest.
FieldDescription
totalTotal contacts enrolled in the sequence.
pendingQueued, not yet attempted.
inProgressCurrently being dispatched (in_progress).
sentSuccessfully dispatched.
failedDispatch failed after retries.
skippedSkipped (e.g. lead opted out or became ineligible).

Create a sequence

POST /sequences
Scope: sequences:write. Creates a sequence in draft status. Nothing is enqueued until you launch it.

Request body

{
  "name": "Q3 cold callbacks",
  "channel": "call",
  "criteria": {
    "statuses": ["new", "contacted"],
    "stageIds": ["b1f2...-uuid"],
    "sources": ["meta", "website"],
    "minScore": 40
  },
  "throttle": {
    "maxPerMinute": 5,
    "businessHoursStart": "09:00",
    "businessHoursEnd": "18:00",
    "timezone": "America/Santo_Domingo",
    "weekdays": [1, 2, 3, 4, 5]
  }
}
FieldRequiredNotes
nameyes1..120 chars (trimmed).
channelnoDefaults to call. Only call is accepted (SequenceChannel).
criteriayesAudience filter. See below.
throttleyesPacing rules. See below.

criteria — audience filter

All fields are optional and combine with AND. An empty object {} matches every lead in the organization.
FieldTypeNotes
statusesstring[]Match leads whose status is one of these LeadStatus values.
stageIdsstring[] (uuid)Match leads in any of these pipeline stages. Discover stage IDs via GET /pipeline/stages.
sourcesstring[]Match leads whose source is one of these LeadSource values.
minScoreinteger (0–100)Match leads with score >= minScore.

throttle — pacing and business hours

All fields are required.
FieldTypeNotes
maxPerMinuteinteger (1–60)Max contacts dispatched per minute.
businessHoursStartstring "HH:MM"Start of the daily dispatch window, in timezone local time.
businessHoursEndstring "HH:MM"End of the daily dispatch window.
timezonestringIANA timezone (e.g. America/Santo_Domingo), 1..64 chars.
weekdaysinteger[]ISO weekdays the sequence may dispatch on (Mon=1 … Sun=7). At least one, at most seven.

Response 201

{ "id": "seq_..." }

Common errors

  • 400 VALIDATION_ERROR — invalid body (e.g. empty name, channel other than call, malformed throttle).

Get a sequence

GET /sequences/{sequenceId}
Scope: sequences:read. Returns the same shape as a list item, including the progress object. 404 NOT_FOUND if the sequence doesn’t exist or belongs to another org.

Update a sequence

PATCH /sequences/{sequenceId}
Scope: sequences:write. Draft-only — editing a launched sequence returns 400 BAD_REQUEST.

Request body

All fields optional; send only what you want to change. channel cannot be changed.
{
  "name": "Q3 cold callbacks (refined)",
  "criteria": { "statuses": ["new"], "minScore": 60 },
  "throttle": {
    "maxPerMinute": 8,
    "businessHoursStart": "10:00",
    "businessHoursEnd": "17:00",
    "timezone": "America/Santo_Domingo",
    "weekdays": [1, 2, 3, 4, 5]
  }
}
criteria and throttle are replaced wholesale when provided — send the complete object, not a partial patch.

Response 200

{ "id": "seq_..." }

Common errors

  • 400 BAD_REQUEST"Only draft sequences can be edited".
  • 400 VALIDATION_ERROR — invalid body.
  • 404 NOT_FOUND — unknown sequence.

Delete a sequence

DELETE /sequences/{sequenceId}
Scope: sequences:write. Draft-only. Launched sequences own their contact queue and history (who was dialed, results, provider references), so they are kept as a record and cannot be deleted.

Response 200

{ "deleted": true, "id": "seq_..." }

Common errors

  • 400 BAD_REQUEST"Only draft sequences can be deleted; launched sequences keep their contact history".
  • 404 NOT_FOUND — unknown sequence.

Preview the audience

POST /sequences/preview-audience
Scope: sequences:read. Counts how many leads currently match a set of criteria — without creating or launching anything. Use it to size an audience before committing, and to confirm it sits under the 5000-lead launch ceiling.

Request body

{
  "criteria": {
    "statuses": ["new", "contacted"],
    "sources": ["meta"],
    "minScore": 40
  }
}
The criteria object follows the same schema as on create.

Response 200

{ "count": 1840 }

Launch a sequence

POST /sequences/{sequenceId}/launch
Scope: sequences:write. Draft-only. Resolves the audience from the sequence’s criteria, enrolls each matching lead into the contact queue, and flips the sequence to running.
Launching charges your monthly API quota proportionally to the audience size. Unlike every other endpoint — which costs one unit — a launch consumes one unit per enqueued contact. A launch that enrolls 1,200 leads costs 1,200 units against your monthly quota. Preview the audience first, and see Rate limits for how the weighted monthly cost is accounted.

Response 200

{ "id": "seq_...", "enqueued": 1200 }
enqueued is the number of contacts enrolled (the number of units charged).

Common errors

  • 400 BAD_REQUEST"Only draft sequences can be launched" (already running, paused, or completed).
  • 400 BAD_REQUEST"No eligible leads match this sequence's criteria" (empty audience).
  • 400 BAD_REQUEST"Audience too large (over 5000 eligible leads). Narrow the criteria before launching."
  • 404 NOT_FOUND — unknown sequence.

Pause a sequence

POST /sequences/{sequenceId}/pause
Scope: sequences:write. Running-only. Halts dispatch; in-flight contacts finish, but no new contacts are picked up.

Response 200

{ "id": "seq_..." }

Common errors

  • 400 BAD_REQUEST"Only running sequences can be paused".

Resume a sequence

POST /sequences/{sequenceId}/resume
Scope: sequences:write. Paused-only. Returns the sequence to running and the worker continues from the remaining pending contacts.

Response 200

{ "id": "seq_..." }

Common errors

  • 400 BAD_REQUEST"Only paused sequences can be resumed".