For the complete documentation index, see llms.txt. This page is also available as Markdown.

Sequences

Build and control multi-step outreach sequences (cadences). A sequence is an ordered series of steps — emails, delays, tasks, and LinkedIn actions — that contacts move through automatically.

Use the action endpoints, not raw CRUD

Create, rename, clone, and delete sequences with the dedicated action endpoints below — not the generic POST / PATCH / DELETE /api/sequences verbs. Creating a sequence also provisions a backing source list, a start step, and a default view; deleting one cascades to its steps, list, and enrollments. The raw verbs skip this scaffolding and leave a sequence that cannot enroll contacts. (PATCH /api/sequences/{sequenceId} is still fine for editing settings like the sending mailbox — see that endpoint for the fields to avoid.)

Lifecycle

A sequence's status moves draftactivepaused. Use /activate and /pause to transition it — they also move in-flight contacts — rather than patching status directly.

Steps

Steps are managed with the regular /api/sequenceSteps CRUD endpoints. Each step has a type (sendEmail, delay, addTask, sendLinkedinMessage, sendLinkedinConnectionRequest, startAutomation, endSequence) and an order. The startSequence step (order 0) is created for you and should not be removed.

List sequences

get

Returns sequences in a workspace. Filter with the where parameter, e.g. {"workspaceId": "<WORKSPACE_UUID>"} or {"workspaceId": "<WORKSPACE_UUID>", "status": "active"}.

The listId field on each sequence is its source list — add that list to a contact's listIds to enroll the contact (see the Sequence Enrollments section).

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Query parameters
fieldsstringOptional

Comma-separated list of fields to return. Defaults to all fields.

Example: id,name,domain
wherestringOptional

JSON-encoded filter object. All top-level conditions are combined with AND logic. Use $or for OR logic.

The available operators depend on the data type of the field you are filtering on.


String fields

Fields like name, domain, description, linkedin, source, externalId, location.

OperatorDescriptionExample
(exact)Exact match{"name": "Linear"}
$eqExplicit exact match{"name": {"$eq": "Linear"}}
$notNot equal{"source": {"$not": "import"}}
$inMatches any value in array{"domain": {"$in": ["linear.app", "granola.so"]}}
$notInMatches none of the values{"source": {"$notIn": ["import", "api"]}}
$containsCase-insensitive word-boundary substring match{"name": {"$contains": "YC"}}
$notContainsDoes not contain{"name": {"$notContains": "Test"}}
$containsAnyContains any of the given strings{"name": {"$containsAny": ["YC", "Techstars"]}}
$startsWithStarts with prefix{"domain": {"$startsWith": "app."}}
$endsWithEnds with suffix{"email": {"$endsWith": "@zero.inc"}}
$existsField is present and truthy{"linkedin": {"$exists": true}}
$notExistsField is absent, null, or empty{"linkedin": {"$notExists": true}}

Number fields

Fields like value, confidence.

OperatorDescriptionExample
(exact)Exact match{"value": 5000}
$eqExplicit exact match{"value": {"$eq": 5000}}
$notNot equal{"value": {"$not": 0}}
$gtGreater than{"value": {"$gt": 10000}}
$gteGreater than or equal{"value": {"$gte": 5000}}
$ltLess than{"value": {"$lt": 10000}}
$lteLess than or equal{"value": {"$lte": 50000}}
$inMatches any value in array{"confidence": {"$in": [0.25, 0.5, 0.75]}}
$notInMatches none of the values{"confidence": {"$notIn": [0, 1]}}
$existsField is present and truthy{"value": {"$exists": true}}
$notExistsField is absent, null, or zero{"value": {"$notExists": true}}

Multiple operators can be combined on one field:

{"value": {"$gte": 5000, "$lt": 10000}}

Date fields

Fields like closeDate, startDate, endDate, createdAt, updatedAt.

Values can be ISO 8601 strings ("2026-01-01", "2026-01-01T00:00:00Z") or relative time macros.

Relative time macros: +Nd / -Nd (days), +Nw / -Nw (weeks), +Nm / -Nm (months), +Ny / -Ny (years), +Nh / -Nh (hours), +Ns / -Ns (seconds), now().

OperatorDescriptionExample
$gteOn or after{"closeDate": {"$gte": "2026-01-01"}}
$lteOn or before{"closeDate": {"$lte": "2026-03-31"}}
$gtAfter{"createdAt": {"$gt": "2026-01-01T00:00:00Z"}}
$ltBefore{"createdAt": {"$lt": "now()"}}
$dateExact date match (compares date portion only){"closeDate": {"$date": "2026-01-15"}}
$existsField is present and truthy{"closeDate": {"$exists": true}}
$notExistsField is absent or null{"closeDate": {"$notExists": true}}

Date range example:

{"closeDate": {"$gte": "2026-01-01", "$lte": "2026-03-31"}}

Relative date example (closing in next 30 days):

{"closeDate": {"$gte": "now()", "$lte": "+30d"}}

Array fields

Fields like listIds, ownerIds, contactIds.

OperatorDescriptionExample
$includesArray contains the given value (use this — bare exact match is not supported){"listIds": {"$includes": "<LIST_UUID>"}}
$notIncludesArray does not contain the given value{"ownerIds": {"$notIncludes": "<USER_UUID>"}}
$overlapsArray contains at least one of the given values{"ownerIds": {"$overlaps": ["<UUID_1>", "<UUID_2>"]}}
$notOverlapsArray contains none of the given values{"listIds": {"$notOverlaps": ["<UUID_1>", "<UUID_2>"]}}
$allArray contains all of the given values{"listIds": {"$all": ["<UUID_1>", "<UUID_2>"]}}
$lengthFilter by array length (supports nested operators){"contactIds": {"$length": {"$gte": 2}}}
$existsField is present and non-empty{"ownerIds": {"$exists": true}}
$notExistsField is absent or empty{"ownerIds": {"$notExists": true}}

UUID / ID fields

Fields like id, workspaceId, companyId, stage.

OperatorDescriptionExample
(exact)Exact match{"stage": "<PIPELINE_STAGE_UUID>"}
$inMatches any value in array{"stage": {"$in": ["<UUID_1>", "<UUID_2>"]}}
$notInMatches none of the values{"stage": {"$notIn": ["<UUID_1>"]}}
$notNot equal{"stage": {"$not": "<UUID>"}}

Boolean fields

Fields like archived.

OperatorDescriptionExample
(exact)Exact match{"archived": false}
$notNot equal{"archived": {"$not": true}}

Logical operators

These work across all data types.

$or — matches if any sub-condition is true:

{
  "workspaceId": "<WORKSPACE_UUID>",
  "$or": [
    {"ownerIds": {"$overlaps": ["<USER_UUID_1>", "<USER_UUID_2>"]}},
    {"closeDate": {"$gte": "2026-01-01"}}
  ]
}

$and — matches if all sub-conditions are true (useful when you need multiple conditions on the same field):

{
  "$and": [
    {"name": {"$contains": "Enterprise"}},
    {"name": {"$notContains": "Test"}}
  ]
}

Dot-notation (relation filtering)

Use dot-syntax to filter records based on properties of related objects:

{"company.name": "Linear"}
{"company.domain": {"$in": ["linear.app", "granola.so"]}}
{"company.location.city": "San Francisco"}
{"companyProfile.categories": {"$overlaps": ["Sales", "Marketing"]}}

All operators available for the target field's data type can be used with dot-notation.


Custom property filtering

Custom properties are stored in the custom object on records, keyed by UUID. Use GET /api/columns to discover the available custom property IDs, types, and options for a workspace.

Filter on custom properties using custom.<COLUMN_ID> with operators appropriate for the column's type.

Note: For select and multiselect columns, option values are UUIDs (the key field from the column's options array). Use the UUID, not the human-readable name.

// Text custom property
{"custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$contains": "enterprise"}}

// Select custom property (use the option key UUID)
{"custom.a1b2c3d4-e5f6-7890-abcd-ef1234567890": "3e839b5c-b311-4887-b2da-727d2d75cdd6"}

// Multi-select custom property (use option key UUIDs)
{"custom.b2c3d4e5-f6a7-8901-bcde-f12345678901": {"$overlaps": ["a1b1c1d1-e1f1-1111-aaaa-111111111111", "b2b2c2d2-e2f2-2222-bbbb-222222222222"]}}

// Currency/number custom property
{"custom.c3d4e5f6-a7b8-9012-cdef-123456789012": {"$gte": 100000}}

// Date custom property
{"custom.d4e5f6a7-b8c9-0123-defa-234567890123": {"$gte": "2026-01-01"}}

// Boolean custom property
{"custom.e5f6a7b8-c9d0-1234-efab-345678901234": true}

// Check if custom property has a value
{"custom.f6a7b8c9-d0e1-2345-fabc-456789012345": {"$exists": true}}

Complex example

All top-level keys are ANDed together:

{
  "name": {"$contains": "Zero"},
  "location.city": "Helsinki",
  "location.country": {"$in": ["United Kingdom", "Germany", "Sweden"]},
  "value": {"$gte": 10000},
  "closeDate": {"$gte": "2026-01-01", "$lte": "2026-03-31"},
  "ownerIds": {"$includes": "<USER_UUID>"},
  "stage": {"$in": ["<UUID_1>", "<UUID_2>"]},
  "lastActivity": {"$exists": true},
  "companyProfile.categories": {"$overlaps": ["Sales", "Marketing"]},
  "custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$contains": "enterprise"}
}
Example: {"stage":"<PIPELINE_STAGE_UUID>"}
limitintegerOptional

Maximum number of records to return

Default: 100
offsetintegerOptional

Pagination offset

Default: 0
orderBystringOptional

JSON string for sort order

Example: {"name":"asc"}
Responses
200

Successful response

application/json
totalintegerOptional
get/api/sequences

Create a sequence

post

Creates a draft sequence and provisions everything it needs: a backing source list (returned as listId), a default startSequence step, and a default view.

Use this endpoint instead of the generic POST /api/sequences — the generic verb creates a bare row with no source list, which cannot enroll contacts.

The new sequence starts in draft. Add steps with POST /api/sequenceSteps, then call POST /api/sequences/activate to start it.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
workspaceIdstring · uuidRequired
namestringOptional

Sequence name. Defaults to "New Sequence". Also used as the source list's name.

sendingWindowTimezonestringOptional

IANA timezone for the start step's sending window (e.g. "America/New_York"). Invalid values fall back to "UTC".

orderintegerOptional

Optional sort order among sequences.

Responses
200

Sequence created

application/json
successbooleanOptional
post/api/sequences/create

Get a sequence

get

Retrieve a single sequence by ID. If no sequence matches the ID this returns 200 with data: null (not a 404) — the generic CRUD route doesn't 404. The custom action endpoints (activate, pause, etc.) are the ones that return 404 for a missing sequence.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
sequenceIdstring · uuidRequired
Query parameters
fieldsstringOptional

Comma-separated list of fields to return. Defaults to all fields.

Example: id,name,domain
Responses
200

Successful response

application/json
get/api/sequences/{sequenceId}

Update a sequence

patch

Update editable settings on a sequence, such as the default sending mailboxId, linkedinAccountId, icon, color, or settings.

Do not change name or status here. Use POST /api/sequences/rename to rename (it keeps the source list name in sync) and POST /api/sequences/activate / POST /api/sequences/pause to change status (they also transition in-flight contacts).

If no sequence matches the ID this is a no-op and returns 200 with an empty result (not a 404).

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
sequenceIdstring · uuidRequired
Body

Editable sequence settings. To rename use POST /api/sequences/rename; to change status use /activate or /pause.

mailboxIdstring · uuid · nullableOptional

Default sending mailbox for email steps.

linkedinAccountIdstring · uuid · nullableOptional
sequenceFolderIdstring · uuid · nullableOptional
iconstringOptional
colorstringOptional
orderintegerOptional
settingsobjectOptional
Responses
200

Sequence updated

application/json
dataobjectOptional

Partial sequence object containing only the updated fields.

patch/api/sequences/{sequenceId}

Activate a sequence

post

Sets a draft or paused sequence to active and begins processing enrolled contacts. Resuming from paused re-arms contacts that were paused mid-flight.

Validation runs first: the sequence must have at least one step after the start step, and every sendEmail step must have a sending mailbox (step-level or the sequence's mailboxId). If validation fails the endpoint returns 400 with a message.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
sequenceIdstring · uuidRequired
Responses
200

Sequence activated (or already active)

application/json
successbooleanOptional
post/api/sequences/activate

Pause a sequence

post

Sets an active sequence to paused and snapshots every in-flight contact so it can resume from the same point when the sequence is re-activated. A sequence already in draft or paused is returned unchanged.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
sequenceIdstring · uuidRequired
Responses
200

Sequence paused (or already paused/draft)

application/json
successbooleanOptional
pausedContactsbooleanOptional

Present and true when in-flight contacts were paused.

post/api/sequences/pause

Rename a sequence

post

Renames the sequence and its source list together, keeping them in sync. Prefer this over patching name directly.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
sequenceIdstring · uuidRequired
namestringRequired
Responses
200

Sequence renamed

application/json
successbooleanOptional
post/api/sequences/rename

Clone a sequence

post

Duplicates an existing sequence into a new draft sequence with a fresh, empty source list. Steps and sequence-scoped email templates are copied (the auto-managed aiCompose step is regenerated; replyToStepId references are remapped to the new steps). Enrolled contacts are not copied.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
sourceSequenceIdstring · uuidRequired
namestringOptional

Name for the copy. Defaults to " (copy)".

Responses
200

Sequence cloned

application/json
successbooleanOptional
post/api/sequences/clone

Delete a sequence

post

Permanently deletes a sequence and cascades to its steps, source list and views, email templates, enrollments (SequenceContactStatus rows), and any scheduled emails. This is not reversible. Use this instead of the generic DELETE /api/sequences/{id}, which would orphan the related records.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
sequenceIdstring · uuidRequired
Responses
200

Sequence deleted

application/json
successbooleanOptional
post/api/sequences/delete

List sequence steps

get

Returns the steps of a sequence. Filter with where, e.g. {"workspaceId": "<WORKSPACE_UUID>", "sequenceId": "<SEQUENCE_UUID>"}, and order by order: orderBy={"order":"asc"}.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Query parameters
fieldsstringOptional

Comma-separated list of fields to return. Defaults to all fields.

Example: id,name,domain
wherestringOptional

JSON-encoded filter object. All top-level conditions are combined with AND logic. Use $or for OR logic.

The available operators depend on the data type of the field you are filtering on.


String fields

Fields like name, domain, description, linkedin, source, externalId, location.

OperatorDescriptionExample
(exact)Exact match{"name": "Linear"}
$eqExplicit exact match{"name": {"$eq": "Linear"}}
$notNot equal{"source": {"$not": "import"}}
$inMatches any value in array{"domain": {"$in": ["linear.app", "granola.so"]}}
$notInMatches none of the values{"source": {"$notIn": ["import", "api"]}}
$containsCase-insensitive word-boundary substring match{"name": {"$contains": "YC"}}
$notContainsDoes not contain{"name": {"$notContains": "Test"}}
$containsAnyContains any of the given strings{"name": {"$containsAny": ["YC", "Techstars"]}}
$startsWithStarts with prefix{"domain": {"$startsWith": "app."}}
$endsWithEnds with suffix{"email": {"$endsWith": "@zero.inc"}}
$existsField is present and truthy{"linkedin": {"$exists": true}}
$notExistsField is absent, null, or empty{"linkedin": {"$notExists": true}}

Number fields

Fields like value, confidence.

OperatorDescriptionExample
(exact)Exact match{"value": 5000}
$eqExplicit exact match{"value": {"$eq": 5000}}
$notNot equal{"value": {"$not": 0}}
$gtGreater than{"value": {"$gt": 10000}}
$gteGreater than or equal{"value": {"$gte": 5000}}
$ltLess than{"value": {"$lt": 10000}}
$lteLess than or equal{"value": {"$lte": 50000}}
$inMatches any value in array{"confidence": {"$in": [0.25, 0.5, 0.75]}}
$notInMatches none of the values{"confidence": {"$notIn": [0, 1]}}
$existsField is present and truthy{"value": {"$exists": true}}
$notExistsField is absent, null, or zero{"value": {"$notExists": true}}

Multiple operators can be combined on one field:

{"value": {"$gte": 5000, "$lt": 10000}}

Date fields

Fields like closeDate, startDate, endDate, createdAt, updatedAt.

Values can be ISO 8601 strings ("2026-01-01", "2026-01-01T00:00:00Z") or relative time macros.

Relative time macros: +Nd / -Nd (days), +Nw / -Nw (weeks), +Nm / -Nm (months), +Ny / -Ny (years), +Nh / -Nh (hours), +Ns / -Ns (seconds), now().

OperatorDescriptionExample
$gteOn or after{"closeDate": {"$gte": "2026-01-01"}}
$lteOn or before{"closeDate": {"$lte": "2026-03-31"}}
$gtAfter{"createdAt": {"$gt": "2026-01-01T00:00:00Z"}}
$ltBefore{"createdAt": {"$lt": "now()"}}
$dateExact date match (compares date portion only){"closeDate": {"$date": "2026-01-15"}}
$existsField is present and truthy{"closeDate": {"$exists": true}}
$notExistsField is absent or null{"closeDate": {"$notExists": true}}

Date range example:

{"closeDate": {"$gte": "2026-01-01", "$lte": "2026-03-31"}}

Relative date example (closing in next 30 days):

{"closeDate": {"$gte": "now()", "$lte": "+30d"}}

Array fields

Fields like listIds, ownerIds, contactIds.

OperatorDescriptionExample
$includesArray contains the given value (use this — bare exact match is not supported){"listIds": {"$includes": "<LIST_UUID>"}}
$notIncludesArray does not contain the given value{"ownerIds": {"$notIncludes": "<USER_UUID>"}}
$overlapsArray contains at least one of the given values{"ownerIds": {"$overlaps": ["<UUID_1>", "<UUID_2>"]}}
$notOverlapsArray contains none of the given values{"listIds": {"$notOverlaps": ["<UUID_1>", "<UUID_2>"]}}
$allArray contains all of the given values{"listIds": {"$all": ["<UUID_1>", "<UUID_2>"]}}
$lengthFilter by array length (supports nested operators){"contactIds": {"$length": {"$gte": 2}}}
$existsField is present and non-empty{"ownerIds": {"$exists": true}}
$notExistsField is absent or empty{"ownerIds": {"$notExists": true}}

UUID / ID fields

Fields like id, workspaceId, companyId, stage.

OperatorDescriptionExample
(exact)Exact match{"stage": "<PIPELINE_STAGE_UUID>"}
$inMatches any value in array{"stage": {"$in": ["<UUID_1>", "<UUID_2>"]}}
$notInMatches none of the values{"stage": {"$notIn": ["<UUID_1>"]}}
$notNot equal{"stage": {"$not": "<UUID>"}}

Boolean fields

Fields like archived.

OperatorDescriptionExample
(exact)Exact match{"archived": false}
$notNot equal{"archived": {"$not": true}}

Logical operators

These work across all data types.

$or — matches if any sub-condition is true:

{
  "workspaceId": "<WORKSPACE_UUID>",
  "$or": [
    {"ownerIds": {"$overlaps": ["<USER_UUID_1>", "<USER_UUID_2>"]}},
    {"closeDate": {"$gte": "2026-01-01"}}
  ]
}

$and — matches if all sub-conditions are true (useful when you need multiple conditions on the same field):

{
  "$and": [
    {"name": {"$contains": "Enterprise"}},
    {"name": {"$notContains": "Test"}}
  ]
}

Dot-notation (relation filtering)

Use dot-syntax to filter records based on properties of related objects:

{"company.name": "Linear"}
{"company.domain": {"$in": ["linear.app", "granola.so"]}}
{"company.location.city": "San Francisco"}
{"companyProfile.categories": {"$overlaps": ["Sales", "Marketing"]}}

All operators available for the target field's data type can be used with dot-notation.


Custom property filtering

Custom properties are stored in the custom object on records, keyed by UUID. Use GET /api/columns to discover the available custom property IDs, types, and options for a workspace.

Filter on custom properties using custom.<COLUMN_ID> with operators appropriate for the column's type.

Note: For select and multiselect columns, option values are UUIDs (the key field from the column's options array). Use the UUID, not the human-readable name.

// Text custom property
{"custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$contains": "enterprise"}}

// Select custom property (use the option key UUID)
{"custom.a1b2c3d4-e5f6-7890-abcd-ef1234567890": "3e839b5c-b311-4887-b2da-727d2d75cdd6"}

// Multi-select custom property (use option key UUIDs)
{"custom.b2c3d4e5-f6a7-8901-bcde-f12345678901": {"$overlaps": ["a1b1c1d1-e1f1-1111-aaaa-111111111111", "b2b2c2d2-e2f2-2222-bbbb-222222222222"]}}

// Currency/number custom property
{"custom.c3d4e5f6-a7b8-9012-cdef-123456789012": {"$gte": 100000}}

// Date custom property
{"custom.d4e5f6a7-b8c9-0123-defa-234567890123": {"$gte": "2026-01-01"}}

// Boolean custom property
{"custom.e5f6a7b8-c9d0-1234-efab-345678901234": true}

// Check if custom property has a value
{"custom.f6a7b8c9-d0e1-2345-fabc-456789012345": {"$exists": true}}

Complex example

All top-level keys are ANDed together:

{
  "name": {"$contains": "Zero"},
  "location.city": "Helsinki",
  "location.country": {"$in": ["United Kingdom", "Germany", "Sweden"]},
  "value": {"$gte": 10000},
  "closeDate": {"$gte": "2026-01-01", "$lte": "2026-03-31"},
  "ownerIds": {"$includes": "<USER_UUID>"},
  "stage": {"$in": ["<UUID_1>", "<UUID_2>"]},
  "lastActivity": {"$exists": true},
  "companyProfile.categories": {"$overlaps": ["Sales", "Marketing"]},
  "custom.54e1ca7d-69c3-4b77-8266-8085b5834116": {"$contains": "enterprise"}
}
Example: {"stage":"<PIPELINE_STAGE_UUID>"}
limitintegerOptional

Maximum number of records to return

Default: 100
offsetintegerOptional

Pagination offset

Default: 0
orderBystringOptional

JSON string for sort order

Example: {"name":"asc"}
Responses
200

Successful response

application/json
totalintegerOptional
get/api/sequenceSteps

Add a step

post

Adds a step to a sequence. Set type to one of sendEmail, delay, addTask, sendLinkedinMessage, sendLinkedinConnectionRequest, startAutomation, or endSequence, and order to position it after the start step (which is order 0).

Per-step configuration lives in the freeform settings and triggerSettings objects, and the fields differ by type. The reference below lists the commonly-used fields for each type.

Applies to every type:

  • settings.backgroundPhases is managed by the server — don't set it; whatever you send is overwritten.

  • Text fields on email, LinkedIn, and task steps support macros such as {{contact.firstName}}, {{contact.email}}, {{contact.company.name}}, and {{mailbox.name}}.

  • You don't create the startSequence step (order 0) — it ships with the sequence, but you can PATCH it to tune scheduling (see below). Never create an aiCompose step; it is auto-managed — enable AI instead by setting settings.ai.enabled = true on a send step.

sendEmail

Field
Type
Notes

settings.mailboxId

uuid

Sending mailbox. Falls back to the sequence's mailboxId; one of the two is required to activate.

settings.subject

string

Subject line (macros supported).

settings.content

Tiptap doc

Email body (macros supported).

settings.draft

boolean

true creates a draft for a user to send manually; false (or omitted) sends automatically.

settings.replyToStepId

uuid

Send as a reply within an earlier sendEmail step's thread. Must reference an earlier email step in the same sequence.

settings.stopOnReply

boolean

End the sequence for a contact who replies.

settings.ai

object

Set {"enabled": true, "mode": "full"} to AI-compose the email (this adds the auto-managed aiCompose step).

The recipient is always the contact's email, and from defaults to the mailbox identity.

{
  "settings": {
    "mailboxId": "<MAILBOX_UUID>",
    "subject": "Quick question, {{contact.firstName}}",
    "content": {"type": "doc", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "Hi {{contact.firstName}}, wanted to reach out."}]}]},
    "draft": false
  }
}

delay

Waits before the next step runs. Configured via triggerSettings, not settings.

Field
Type
Notes

triggerSettings.delayMs

number

Wait, in milliseconds. Defaults to 86400000 (24h) if omitted.

addTask

Field
Type
Notes

settings.title

string

Task title (macros supported).

settings.description

Tiptap doc / string

Task body.

settings.taskType

string

e.g. call, todo, meeting, follow_up.

settings.priority

integer

1 Low to 4 Urgent.

settings.assignedToIds

uuid[]

Assignee user ids. Defaults to the sequence creator.

settings.continueMode

string

When the sequence advances: immediate, done (default), or deadline.

settings.deadlineDays

number

Days after creation for the deadline.

settings.deadlineTime

string

HH:MM for the deadline (default 09:00).

settings.deadlineTimezone

string

IANA timezone for the deadline.

sendLinkedinMessage and sendLinkedinConnectionRequest

Field
Type
Notes

settings.userId

uuid

Required. The workspace user whose connected LinkedIn account sends.

settings.content

Tiptap doc

Message body / connection note (macros supported). Connection notes are truncated to 300 characters.

settings.skipIfNoLinkedinData

boolean

Both types — skip the contact (instead of erroring) when they don't have a complete LinkedIn profile.

settings.skipIfNotConnected

boolean

Messages only — skip contacts who aren't 1st-degree connections instead of erroring.

settings.stopIfNotAccepted

boolean

Connection requests only — end the sequence if the request isn't accepted within settings.stopIfNotAcceptedDays days. Requires stopIfNotAcceptedDays to be set.

settings.stopIfNotAcceptedDays

number

Connection requests only — days to wait before ending the sequence when stopIfNotAccepted is on. 0 or omitted means no timeout is scheduled (the sequence won't end on non-acceptance).

startAutomation

Field
Type
Notes

settings.automationId

uuid

Required. The manual-trigger automation to run for the contact.

endSequence

Takes no settings — it marks the contact complete.

startSequence (PATCH only)

Created with the sequence; PATCH /api/sequenceSteps/{stepId} to adjust enrollment and scheduling.

Field
Type
Notes

settings.rollMode

string

auto (default) enrolls contacts automatically; manual holds new enrollments in waitingForApproval until approved in the app.

settings.dailyStarts

number

Max contacts that may start the sequence per day.

settings.activeDays

string[]

Days sends are allowed, e.g. ["mon", "tue", "wed", "thu", "fri"].

settings.sendingWindow

object

{"start": "09:00", "end": "17:00", "timezone": "<IANA>"}.

settings.staggerMinutes

number

Minimum minutes between auto-sent emails.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
workspaceIdstring · uuidRequired
sequenceIdstring · uuidRequired
typestring · enumRequiredPossible values:
namestringOptional
subjectstringOptional

Email subject (for sendEmail steps).

contentobjectOptional

Step body — a Tiptap document for sendEmail steps.

settingsobjectOptional

Per-type configuration. The fields depend on type — see the endpoint description for the full per-type reference (e.g. mailboxId/subject/content for sendEmail, userId for LinkedIn steps, automationId for startAutomation).

triggerSettingsobjectOptional

Timing configuration. Used by delay steps (delayMs); most other types leave this empty. See the endpoint description.

templateIdstring · uuidOptional
orderintegerOptional

Position after the start step (which is order 0).

Responses
200

Step created

application/json
post/api/sequenceSteps

Batch update steps

patch

Updates multiple steps in one request — typically to reorder them. The body is an object keyed by step ID, where each value is the partial update for that step.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Body
Responses
200

Steps updated

application/json
patch/api/sequenceSteps

Delete a step

delete

Delete a sequence step. Use archive=true for a recoverable soft delete. The startSequence step should not be deleted.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
stepIdstring · uuidRequired
Query parameters
archivebooleanOptional

If true, soft deletes (archives) the step instead of permanently deleting it.

Default: false
Responses
200

Step deleted

application/json
dataone ofOptional

Hard delete (archive omitted or false): returns 1 on success. Soft delete (archive=true): returns a single-element array containing the archived step object.

integerOptionalExample: 1
or
delete/api/sequenceSteps/{stepId}

Update a step

patch

Update a single sequence step.

Authorizations
AuthorizationstringRequired

All API requests require a Bearer token in the Authorization header. Create an API key from Workspace Settings → API keys

Path parameters
stepIdstring · uuidRequired
Body
typestring · enumOptional

Changing a step's type is allowed but uncommon. The auto-managed startSequence and aiCompose types are intentionally excluded (matching SequenceStepCreate).

Possible values:
namestringOptional
subjectstringOptional
contentobjectOptional
settingsobjectOptional
triggerSettingsobjectOptional
templateIdstring · uuidOptional
orderintegerOptional
Responses
200

Step updated

application/json
dataobjectOptional

Partial step object containing only the updated fields.

patch/api/sequenceSteps/{stepId}

Last updated