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

Audiences tools

Group contacts into static lists or dynamic audiences defined by conditions, and let segment rules move engaged contacts into an audience automatically.

create_audience

Create an audience. Without `condition`: STATIC (membership added manually or by segment rules). With `condition`: DYNAMIC (membership computed from contact data on every read). Same-slug re-create with the same kind+condition is idempotent; a different kind or condition is a 409. Use preview_audience first to see who a condition would match.

namestringrequired
slugstring
conditionobject (any keys)[]
AND-list of 1-10 predicates making this a DYNAMIC audience: membership is computed live from contact data (never stored — no manual adds, no audience_added trigger; a contact whose data changes moves in/out automatically). Predicates: {kind:'field', field:'phone'|'email'|'name', op, value} or {kind:'property', prop:'<ingested property name>', op, value}. Ops: eq | in (value: 1-100 strings, matches ANY) | starts_with | ends_with | contains | not_contains | exists | not_exists (exists/not_exists take NO value). starts_with/ends_with/contains ALSO accept a 1-100 value array = matches if ANY needle matches (e.g. Triangle by both area codes: {"kind":"field","field":"phone","op":"starts_with","value":["+1919","+1984"]}); not_contains with an array = contains NONE of them. eq stays single-value — `in` is its any-of form. Values are strings, max 200 chars, matched ASCII-case-insensitively after trimming. Predicates AND together; there is no cross-field OR (compose with `in`/arrays, or create separate audiences). Use list_contact_fields to see which fields/properties exist before building one.
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_audiences

List the team's audiences: id, name, slug, kind (default | static | dynamic), computed member_count, and — for dynamic audiences — the stored condition. Use this to READ what an audience targets before binding, mirroring, or editing it (there is exactly one default per team; its kind is 'default').

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_audience

Rename an audience and/or change its condition (slug or id; 'everyone' = the protected default, which rejects condition changes). condition: a new array edits/converts to DYNAMIC (static→dynamic DELETES stored memberships — the response reports members_removed; refused while an audience_added sequence or segment rule references the audience); explicit null converts to STATIC with EMPTY membership (refused while the audience gates a contact_added sequence); omitted preserves. Response includes the computed member_count.

audiencestringrequired
Audience slug or id; 'everyone' targets the team default.
namestring
conditionobject (any keys)[] | null
AND-list of 1-10 predicates making this a DYNAMIC audience: membership is computed live from contact data (never stored — no manual adds, no audience_added trigger; a contact whose data changes moves in/out automatically). Predicates: {kind:'field', field:'phone'|'email'|'name', op, value} or {kind:'property', prop:'<ingested property name>', op, value}. Ops: eq | in (value: 1-100 strings, matches ANY) | starts_with | ends_with | contains | not_contains | exists | not_exists (exists/not_exists take NO value). starts_with/ends_with/contains ALSO accept a 1-100 value array = matches if ANY needle matches (e.g. Triangle by both area codes: {"kind":"field","field":"phone","op":"starts_with","value":["+1919","+1984"]}); not_contains with an array = contains NONE of them. eq stays single-value — `in` is its any-of form. Values are strings, max 200 chars, matched ASCII-case-insensitively after trimming. Predicates AND together; there is no cross-field OR (compose with `in`/arrays, or create separate audiences). Use list_contact_fields to see which fields/properties exist before building one. Pass null to convert to static.
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.

preview_audience

Preview a dynamic-audience condition WITHOUT creating anything: returns the computed match count and up to 5 sample contacts. Use before create_audience/update_audience to sanity-check a condition. 429 if another preview is running for this team (retry shortly); a zero match is a normal 200 with count 0.

conditionobject (any keys)[]required
AND-list of 1-10 predicates making this a DYNAMIC audience: membership is computed live from contact data (never stored — no manual adds, no audience_added trigger; a contact whose data changes moves in/out automatically). Predicates: {kind:'field', field:'phone'|'email'|'name', op, value} or {kind:'property', prop:'<ingested property name>', op, value}. Ops: eq | in (value: 1-100 strings, matches ANY) | starts_with | ends_with | contains | not_contains | exists | not_exists (exists/not_exists take NO value). starts_with/ends_with/contains ALSO accept a 1-100 value array = matches if ANY needle matches (e.g. Triangle by both area codes: {"kind":"field","field":"phone","op":"starts_with","value":["+1919","+1984"]}); not_contains with an array = contains NONE of them. eq stays single-value — `in` is its any-of form. Values are strings, max 200 chars, matched ASCII-case-insensitively after trimming. Predicates AND together; there is no cross-field OR (compose with `in`/arrays, or create separate audiences). Use list_contact_fields to see which fields/properties exist before building one.
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_to_audience

Add a contact to a STATIC audience by email or phone (fires the audience_added trigger on a new membership). STATIC-ONLY: rule-based (dynamic) audiences compute membership and reject manual adds with a 422; adding to 'everyone' (the default) is a vacuous success (added: false, nothing fires — membership there is implicit).

audiencestringrequired
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.

remove_from_audience

Remove one contact's membership from a STATIC audience (slug or id) by email or phone — dynamic and the Everyone default reject with a 422 (membership is computed, not stored). Does NOT delete the contact and does NOT unenroll them — membership is read only at ingest, so an in-flight sequence keeps running (use unenroll_contact to stop it). If a segment rule feeds this audience the removal will not stick: the next sweep re-adds the contact AND re-fires the audience_added trigger — the response says so.

audiencestringrequired
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.

delete_audience

Delete an audience by id or slug. Refused for the team's Everyone (default) audience. Blocked (409, with counts) while ANY sequence (trigger or gate), segment rule, broadcast (any status — the FK blocks even sent ones), weather watch, or open weather claim references it — re-bind or delete those first. Two-step confirm when it has members: call WITHOUT confirm, then re-call with confirm: true and the returned audience_id (confirming by slug is rejected — a slug can be re-created pointing at a different audience). Memberships are removed; contacts are NOT deleted.

audiencestringrequired
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.

create_segment_rule

Create an engagement segment rule: when a contact first matches the condition they enter the audience (enter-once ratchet), firing audience_added sequences; optionally stop their enrollment in one sequence.

namestringrequired
slugstring
conditionobject (any keys)[]required
AND-list of predicates. Kinds: {kind:'opened_count'|'clicked_count', op:'>='|'<=', value:int, sequence_id?:uuid (not slug)} · {kind:'sent_count', op:'>=', value:int, sequence_id?:uuid (not slug)} · {kind:'no_opens_in_days', days:int} (also requires ≥1 send in the window) · {kind:'has_tag', tag:string} · {kind:'property', prop, op:'eq'|'in', value}. All engagement counts in one rule share one sequence scope; max one no_opens_in_days. OR = create multiple rules feeding the same audience.
audiencestringrequired
Audience id or slug the rule feeds.
stop_sequencestring
Sequence (id or slug) to STOP the contact's enrollment in on entry.
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_segment_rules

List this team's segment rules.

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_segment_rule

Get one segment rule with its audience member count.

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_segment_rule

Update a segment rule (pause/resume, rename, edit condition — future-only: contacts already entered stay; set stop_sequence to null to clear). The audience is immutable.

idstringrequired
namestring
statusenum
active | paused
conditionobject (any keys)[]
AND-list of predicates. Kinds: {kind:'opened_count'|'clicked_count', op:'>='|'<=', value:int, sequence_id?:uuid (not slug)} · {kind:'sent_count', op:'>=', value:int, sequence_id?:uuid (not slug)} · {kind:'no_opens_in_days', days:int} (also requires ≥1 send in the window) · {kind:'has_tag', tag:string} · {kind:'property', prop, op:'eq'|'in', value}. All engagement counts in one rule share one sequence scope; max one no_opens_in_days. OR = create multiple rules feeding the same audience.
stop_sequencestring | null
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_segment_rule

Delete a segment rule. The audience and its members are untouched.

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.