sequence

Book a demo

Tell us a little about your business. We'll reply within one business day to set up a 20-minute call.

Get started

Sequences tools

Build follow-ups: pick a trigger, add email and text steps with waits or anchored times, A/B test email steps, enroll contacts and read the results.

create_sequence

Create a linear sequence bound to one trigger (+ optional equality/in filter, + optional audience gate).

recipientsenum
customers | staff
Create-time only: customers (default) or staff. Staff requires trigger_type=event and matches contacts with is_staff=true.
exit_eventsobject[]
Up to 10 exit entries: event name, optional eq/in filter (AND), and scope. contact (default) exits this contact; subject exits all recipients for the subject; contact_subject exits this contact for this subject. subject and contact_subject require an anchored sequence. Empty array clears exits.
exit_events[].eventstringrequired
exit_events[].filterobject[]default []
exit_events[].filter[].propstringrequired
exit_events[].filter[].openumrequired
eq | in
exit_events[].filter[].valuestring | number | boolean | (string | number | boolean)[]required
exit_events[].scopeenumdefault "contact"
contact | subject | contact_subject
anchor_propertystring
Create-time only event property holding an ISO-8601 timestamp with offset, e.g. due_at. Requires an event trigger and subject_id; steps use anchor timing; omit wait_for. Missing/invalid anchors skip enrollment.
namestringrequired
slugstring
trigger_typeenumrequired
contact_added | audience_added | event
trigger_event_namestring
trigger_audiencestring
trigger_audience_idstring
trigger_filterobject[]
trigger_filter[].propstringrequired
trigger_filter[].openumrequired
eq | in
trigger_filter[].valueanyrequired
trigger_filter_audience_keystring | null
Audience GATE: only members of this audience (slug, or the literal 'everyone') enroll when the trigger fires — a membership test at enrollment time, never a branch, and never retroactive. Provide EITHER this OR trigger_filter_audience_id, not both. A STATIC audience cannot gate a contact_added sequence (a brand-new contact has no stored membership — it would enroll nobody): use a dynamic audience or 'everyone' there. Omitted = everyone.
trigger_filter_audience_idstring | null
Audience gate by uuid — same rules as trigger_filter_audience_key (XOR).
statusenum
draft | active | paused | archived
from_namestring
from_emailstring
reply_tostring
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

update_sequence

Update a sequence's name, per-sequence sending identity (from_name, from_email, reply_to — pass null to clear/inherit the team; a from_email must be on a verified sending domain), and/or its trigger. Re-binding the trigger is FUTURE-ONLY: it changes who ENROLLS going forward — contacts already in the sequence are untouched. To change trigger type/event/audience, pass trigger_type plus its spec (trigger_event_name for 'event'; trigger_audience slug or trigger_audience_id for 'audience_added'). trigger_filter can be changed on its own. Steps are edited via add_step / insert_step / delete_step / reorder_steps / update_step.

sequence_idstringrequired
exit_eventsobject[]
Up to 10 exit entries: event name, optional eq/in filter (AND), and scope. contact (default) exits this contact; subject exits all recipients for the subject; contact_subject exits this contact for this subject. subject and contact_subject require an anchored sequence. Empty array clears exits.
exit_events[].eventstringrequired
exit_events[].filterobject[]default []
exit_events[].filter[].propstringrequired
exit_events[].filter[].openumrequired
eq | in
exit_events[].filter[].valuestring | number | boolean | (string | number | boolean)[]required
exit_events[].scopeenumdefault "contact"
contact | subject | contact_subject
namestring
from_namestring | null
from_emailstring | null
reply_tostring | null
trigger_typeenum
contact_added | audience_added | event
trigger_event_namestring | null
trigger_audiencestring | null
trigger_audience_idstring | null
trigger_filterobject[]
trigger_filter[].propstringrequired
trigger_filter[].openumrequired
eq | in
trigger_filter[].valueanyrequired
trigger_filter_audience_keystring | null
Audience GATE: only members of this audience (slug, or the literal 'everyone') enroll when the trigger fires — a membership test at enrollment time, never a branch, and never retroactive. Provide EITHER this OR trigger_filter_audience_id, not both. A STATIC audience cannot gate a contact_added sequence (a brand-new contact has no stored membership — it would enroll nobody): use a dynamic audience or 'everyone' there. Omitted = everyone. Pass null to reset the gate to everyone. Future-only: in-flight enrollments are untouched.
trigger_filter_audience_idstring | null
Audience gate by uuid — same rules as trigger_filter_audience_key (XOR; null resets).
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

delete_sequence

Delete a sequence and ALL its data (steps, enrollments, send history — cascades, irreversible). Two-step confirm: call WITHOUT confirm first; if the sequence has enrollments (subscribers) it is NOT deleted and you get back requires_confirmation + the enrollment counts to show the user. Re-call with confirm: true to actually delete. A sequence with no enrollments deletes immediately.

sequence_idstringrequired
confirmboolean
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

list_sequences

List sequences for the team.

teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

add_step

Append a step at the END of a sequence (references a team template + wait_for). Contacts still walking reach the new step; contacts who already completed are NOT re-engaged (they re-enter on the next trigger firing). To insert mid-sequence instead, use insert_step. Optional A/B: pass exactly 2 `variants` (each a template_id + optional weight/label) to split this step's content; the sweep picks one per contact deterministically and records it. Compare them with get_step_stats; promote a winner with update_step_variants.

anchor_offsetstring | null
Anchored only: signed minute/hour/day/week terms from the anchor, from -30 days to +30 days (e.g. -15 minutes or 1 day 2 hours). Mutually exclusive with local time/day offset. omit wait_for; interval-only steps must have non-decreasing offsets.
anchor_local_timestring | null
Anchored only: local clock time HH:MM or HH:MM:SS (00:00–23:59:59), interpreted in the enrollment time zone. Use with optional day offset, never anchor_offset; omit wait_for.
anchor_day_offsetnumber | null
Integer -30 to 30 days relative to the anchor local date; only with anchor_local_time. Omitted/null means 0 (same day).
sequence_idstringrequired
template_idstringrequired
wait_forstring
Normal step delay: nonnegative integer minute/hour/day/week terms, singly or combined (e.g. 0 minutes, 3 days, 1 day 2 hours), totaling at most 90 days. For anchored steps, omit wait_for and choose anchor_offset OR anchor_local_time with optional anchor_day_offset.
variantsobject[]
Optional A/B test: exactly 2 template variants for this step.
variants[].template_idstringrequired
variants[].weightnumber
variants[].labelstring
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

insert_step

Insert a step MID-sequence, immediately after an existing step (after_step_id). Live-safe and FORWARD-ONLY: contacts at or before the anchor step receive the new email in turn; contacts already past it never get it. Use add_step to append at the end (after_step_id pointing at the last step is rejected — that's an append).

anchor_offsetstring | null
Anchored only: signed minute/hour/day/week terms from the anchor, from -30 days to +30 days (e.g. -15 minutes or 1 day 2 hours). Mutually exclusive with local time/day offset. omit wait_for; interval-only steps must have non-decreasing offsets.
anchor_local_timestring | null
Anchored only: local clock time HH:MM or HH:MM:SS (00:00–23:59:59), interpreted in the enrollment time zone. Use with optional day offset, never anchor_offset; omit wait_for.
anchor_day_offsetnumber | null
Integer -30 to 30 days relative to the anchor local date; only with anchor_local_time. Omitted/null means 0 (same day).
sequence_idstringrequired
template_idstringrequired
after_step_idstringrequired
wait_forstring
Normal step delay: nonnegative integer minute/hour/day/week terms, singly or combined (e.g. 0 minutes, 3 days, 1 day 2 hours), totaling at most 90 days. For anchored steps, omit wait_for and choose anchor_offset OR anchor_local_time with optional anchor_day_offset.
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

delete_step

Remove a step from a sequence (soft-delete — preserves send history). Live-safe and FORWARD-ONLY: a contact currently waiting on the step is skipped forward (it is never sent to them); contacts already past it are untouched; nobody who already received it is affected.

sequence_idstringrequired
step_idstringrequired
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

update_step

Edit wait_for on a normal step, or anchor_offset / anchor_local_time + anchor_day_offset on an anchored step (the latter recomputes pending schedules). wait_for is the delay before a normal step's email (e.g. '1 hour', '3 days', '1 week', up to 90 days). In-place edit; order and template are unchanged. Applies to future sends — enrollments already mid-wait keep their scheduled time.

anchor_offsetstring | null
Anchored only: signed minute/hour/day/week terms from the anchor, from -30 days to +30 days (e.g. -15 minutes or 1 day 2 hours). Mutually exclusive with local time/day offset. omit wait_for; interval-only steps must have non-decreasing offsets.
anchor_local_timestring | null
Anchored only: local clock time HH:MM or HH:MM:SS (00:00–23:59:59), interpreted in the enrollment time zone. Use with optional day offset, never anchor_offset; omit wait_for.
anchor_day_offsetnumber | null
Integer -30 to 30 days relative to the anchor local date; only with anchor_local_time. Omitted/null means 0 (same day).
sequence_idstringrequired
step_idstringrequired
wait_forstring
Normal step delay: nonnegative integer minute/hour/day/week terms, singly or combined (e.g. 0 minutes, 3 days, 1 day 2 hours), totaling at most 90 days. For anchored steps, omit wait_for and choose anchor_offset OR anchor_local_time with optional anchor_day_offset.
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

get_step_variants

List an A/B step's variants (id, template_id, weight, label). Use the returned ids with update_step_variants to promote a winner; empty list ⇒ the step has no A/B test.

sequence_idstringrequired
step_idstringrequired
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

update_step_variants

Adjust an A/B step's variant weights (e.g. promote a winner by setting it 100/0). Get variant ids from get_step_variants or get_step_stats. Forward-only: already-sent emails keep their recorded variant.

sequence_idstringrequired
step_idstringrequired
weightsobject[]required
weights[].idstringrequired
weights[].weightnumberrequired
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

reorder_steps

Reorder a sequence's steps — DRAFT-ONLY (requires status='draft' with no enrollments; rejected on a live/activated sequence, since a forward walk can't be coherently re-ordered — there, 'move' a step with delete_step + insert_step). step_ids must be an exact permutation of the sequence's current steps.

sequence_idstringrequired
step_idsstring[]required
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

set_sequence_status

Set a sequence's status (draft | active | paused | archived).

sequence_idstringrequired
statusenumrequired
draft | active | paused | archived
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

get_sequence_graph

Get a sequence's trigger + filter + ordered steps with their templates (timeline view).

sequence_idstringrequired
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

enroll_contact

Manually enroll a contact (by email or phone) into a specific ACTIVE sequence at its first step, bypassing the trigger but NOT the audience gate: on a gated sequence the database evaluates membership atomically with the insert, and a non-member is refused (422 naming the audience) — manual enrollment can never sidestep targeting (creates the contact if new). Anchored sequences reject manual enrollment. Also refused for a draft/paused sequence, a sequence with no steps, or a suppressed contact; a no-op (already: true) if the contact is already enrolled. For trigger-driven enrollment of many contacts, use send_event / add_to_audience instead.

sequence_idstringrequired
emailstring
phonestring
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

unenroll_contact

Stop a contact's enrollment in a sequence (operator action — preserves send history; does NOT suppress the contact globally, so other sequences continue). Identify by sequence_id + email or phone, plus subject_id for an anchored enrollment. Without subject_id, multiple active subjects return 409. Best-effort against an email already in flight this sweep.

subject_idstring
Stable subject identity shared by all participants, e.g. crm:appointment:123; use <source>:<entity>:<id>. Trimmed, nonblank, at most 200 characters. Selects one subject when the contact has multiple active enrollments; omission in that case returns 409.
sequence_idstringrequired
emailstring
phonestring
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

get_sequence_stats

Per-step stats + Trend series for a sequence over a date range. SMS steps report Delivered/Replied/Failed (email reports Open/Click/Bounce); each row carries `channel`.

sequence_idstringrequired
rangestring
Preset window for the volume/engagement metrics + Trend sparkline (recent | today | yesterday | last_7d | last_30d | this_month | last_month | this_year | last_year | all; default 'recent'). Point-in-time KPIs (active now / completed) are never windowed. For a custom window pass from/to instead of range.
fromstring
Custom window start, ISO 8601 (overrides range). Optional open lower bound.
tostring
Custom window end, ISO 8601 (overrides range). Optional open upper bound.
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.

get_step_stats

Stats for a single step over a date range. `stats` is an array with one row per A/B variant (each carrying variant_id + counts); a non-test step has a single row with variant_id null. SMS steps reinterpret the engagement counts as Delivered/Replied/Failed (channel='sms'). Compare email variants on clicks (primary) / opens, then promote with update_step_variants.

sequence_idstringrequired
step_idstringrequired
rangestring
Preset window for the volume/engagement metrics + Trend sparkline (recent | today | yesterday | last_7d | last_30d | this_month | last_month | this_year | last_year | all; default 'recent'). Point-in-time KPIs (active now / completed) are never windowed. For a custom window pass from/to instead of range.
fromstring
Custom window start, ISO 8601 (overrides range). Optional open lower bound.
tostring
Custom window end, ISO 8601 (overrides range). Optional open upper bound.
teamstringrequired
Brand/team to act on (slug or id) → X-Cadence-Team. Required — your account key authorizes every brand you own, so this picks which one.