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
- update_sequence
- delete_sequence
- list_sequences
- add_step
- insert_step
- delete_step
- update_step
- get_step_variants
- update_step_variants
- reorder_steps
- set_sequence_status
- get_sequence_graph
- enroll_contact
- unenroll_contact
- get_sequence_stats
- get_step_stats
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[].eventstringrequiredexit_events[].filterobject[]default []exit_events[].filter[].propstringrequiredexit_events[].filter[].openumrequired- eq | in
exit_events[].filter[].valuestring | number | boolean | (string | number | boolean)[]requiredexit_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.
namestringrequiredslugstringtrigger_typeenumrequired- contact_added | audience_added | event
trigger_event_namestringtrigger_audiencestringtrigger_audience_idstringtrigger_filterobject[]trigger_filter[].propstringrequiredtrigger_filter[].openumrequired- eq | in
trigger_filter[].valueanyrequiredtrigger_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_namestringfrom_emailstringreply_tostringteamstringrequired- 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_idstringrequiredexit_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[].eventstringrequiredexit_events[].filterobject[]default []exit_events[].filter[].propstringrequiredexit_events[].filter[].openumrequired- eq | in
exit_events[].filter[].valuestring | number | boolean | (string | number | boolean)[]requiredexit_events[].scopeenumdefault "contact"- contact | subject | contact_subject
namestringfrom_namestring | nullfrom_emailstring | nullreply_tostring | nulltrigger_typeenum- contact_added | audience_added | event
trigger_event_namestring | nulltrigger_audiencestring | nulltrigger_audience_idstring | nulltrigger_filterobject[]trigger_filter[].propstringrequiredtrigger_filter[].openumrequired- eq | in
trigger_filter[].valueanyrequiredtrigger_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_idstringrequiredconfirmbooleanteamstringrequired- 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_idstringrequiredtemplate_idstringrequiredwait_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_idstringrequiredvariants[].weightnumbervariants[].labelstringteamstringrequired- 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_idstringrequiredtemplate_idstringrequiredafter_step_idstringrequiredwait_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_idstringrequiredstep_idstringrequiredteamstringrequired- 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_idstringrequiredstep_idstringrequiredwait_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_idstringrequiredstep_idstringrequiredteamstringrequired- 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_idstringrequiredstep_idstringrequiredweightsobject[]requiredweights[].idstringrequiredweights[].weightnumberrequiredteamstringrequired- 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_idstringrequiredstep_idsstring[]requiredteamstringrequired- 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_idstringrequiredstatusenumrequired- 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_idstringrequiredteamstringrequired- 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_idstringrequiredemailstringphonestringteamstringrequired- 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_idstringrequiredemailstringphonestringteamstringrequired- 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_idstringrequiredrangestring- 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_idstringrequiredstep_idstringrequiredrangestring- 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.