sequences:read or sequences:write. Three exceptions are called out below: audience discovery returns contact data and needs contacts:read, reply previews need chat-sessions:read, and adding someone who is not a contact yet creates one, which also needs contacts:write.
Lifecycle
A sequence has three stored statuses:- Launch moves
drafttoactiveand arms every eligible candidate. Launching an already active sequence is idempotent: it only arms candidates added since. Launching a paused sequence is refused, resume it instead. - Pause and resume only touch the sequence itself. People keep their cursors; on resume, overdue steps go first.
- There is no stored “done”.
finishedon the stats is derived (nothing left in flight and something already went out), so enrolling more people revives a finished sequence with no status change.
Recommended flow
The API is built for enroll first, author later: land a real audience, then write the steps for it.1
Create the shell
Create with a name and a plain-text brief. Steps can wait.
2
Enroll people
Add contacts by contact id, phone, email or WhatsApp user id, with any facts you know about them in
extra_data. To hand your own identifiers to the sessions the sequence opens — the call, or the session their reply lands in — put them in session_custom_data; they come back on the session as custom data, so a workflow on Call Finished or Ticket Created can update the record they point at. Read the per-person outcomes; a successful call never implies everyone was enrolled. Use batch_key to label the wave. List contacts to review who landed.3
Author steps and bind senders
Set steps on the draft. Set senders per channel; the email and voice catalogs tell you which senders are eligible and why not.
4
Preview, then launch
Launch preview mirrors launch clause for clause: who would start, who is held and why, and what would refuse the launch. Then launch.
5
Keep feeding it
Keep calling add contacts. On an active sequence with steps, new people arm the moment they are enrolled, so a CRM can push leads without anyone pressing launch again. Remove a person to stop every remaining step.
People
Every person in a sequence has one status:
Park reasons are always something a person must fix:
needs_data (a step variable has no value and no fallback), unsendable_person (their own data cannot go on the wire), or template_broken (the step’s template is missing, rejected or mismatched for everyone).
A removal through exit contact is a deletion, not an exit reason. The person leaves every read, and adding them again later starts them fresh from the first step. What was already sent is kept.
Each person also carries a journey: one stamp per step (not_reached, waiting, parked, deferred, skipped, sent, delivered, read, replied, answered, no_answer, busy, failed) with the inbox session of the send when one exists. For the raw event log behind those stamps, read contact events.
Skip a step for one contact
Skip Sequence Step omits the next pending step, the next pending step on a channel, or a specific step for one contact. It preserves intervening outreach, personalization, and all waits. It does not resume a reply-exited contact or release an existing park. After a reply such as “I cannot talk now,” skip the next Phone step and then continue the same enrollment. Continuation counts the next pending step’s wait and preceding skipped waits from resume time. A send already being dispatched cannot be skipped. See the workflow setup.Enrollment outcomes
Add contacts answers per person, index-aligned with what you sent:
Phone numbers must be in international format, emails are lowercased, and duplicates inside one call are reported with
detail.in_batch.
Steps
A step is a channel, its content, anddelay_minutes: how long to wait after the previous step actually sent. The first step must have a delay of zero because launch and enrollment arm it, not a timer.
WhatsApp step
WhatsApp step
References an approved message template by Supply
template_name and template_language. variables is keyed by the template’s body parameter: its positional index ("1", "2") or exact name ("first_name", "course_name"), each bound to a source (see Variables) with an optional fallback. No value and no fallback parks the person; the engine never sends generic filler. A template still under review does not block a launch: armed people wait and send the moment it is approved. A rejected or disabled template refuses the launch.For an existing named template, bind every distinct body parameter by name, without the braces:course_name and brand_name through each person’s attached data. Template sample values are only examples; they are not used as recipient data or automatic fallbacks. Missing or extra parameter bindings prevent sending. Repeated placeholders need only one binding.Named body parameters work with static text headers, static footers, and quick-reply buttons. Variable headers and media headers remain unsupported in sequences. Existing URL-suffix and coupon button bindings still use the button index.Per-person personalization uses the same exact keys in values, for example {"first_name": "Tom", "course_name": "Biblical Hebrew", "brand_name": "Our team"}. Include every body parameter with no extras; previews and sent-message history preserve these names. Positional templates continue to use numeric keys.The companion can use existing named templates. When creating a new WhatsApp template through the companion, use numbered placeholders such as {{1}} and {{2}}; its creation tool rejects named placeholders.Voice step
Voice step
The call brief:
extra_instructions rendered per person and handed to the bound phone agent as call-only guidance. The agent carries the persona (voice, language, tone, tools); the step never overrides it. Both fields are optional for an agent whose persona already holds the whole mission. One step is one dial attempt per person, ever: to retry no-answers, author further voice steps with delays. An answered call is the reply and exits the journey.Email step
Email step
Inline
subject, html and text (all three required). Every {{name}} placeholder must have a binding in variables; an unbound placeholder is refused at authoring time rather than shipped. {{signature}} is a system token filled from the sending mailbox and needs no binding.Variables
Every variable binding is{ "source", "fallback"?, "type"? }. The source names where the value comes from for each person:
display_name,phone,emailread the person’s own columns, as always.- Any other string is the exact name of a key in the data attached to the person at enrollment (
extra_dataon add contacts): a spreadsheet column, a field a workflow or an integration sent. The key is matched verbatim, top level only. The three column names above always win over a same-named key.
fallback; no fallback parks the person on needs_data, naming the source. Attached data is rendered by its type, the same vocabulary columns use: without a type, text and numbers pass through and anything else counts as missing; with one, text is parsed where it is unambiguous ("250" as a number, "true" as a boolean, an ISO-shaped date such as 2026-03-12; other date spellings and epoch numbers count as missing), a date reads as a plain day in the person’s timezone (12 Mar 2026), a list must actually be a list in the data and joins with commas, a boolean reads Yes/No, and a value that cannot be read as the declared type counts as missing.
variable_coverage: for every bound source, how many enrolled people have a value, over a bounded sample. Zero on a populated sequence is almost always a misspelled key; a partial count means the variable needs a fallback or should go. Data keys lists every key the sequence’s people carry, most-covered first and up to 200, for a sequence whose people you did not enroll yourself. A value that cannot go on the wire for its channel — a line break, or, on WhatsApp, values that together push the filled-in message past its length limit — parks that person as unsendable_person rather than being altered; the largest value is named.
Senders
Each channel needs at least one bound sender before launch: WhatsApp numbers, AI phone agents for calls, mailboxes for email. Set senders replaces the binding for one channel. Unbinding the last sender of a channel while an active sequence still has sends pending on it is refused; pause first. The email and voice catalogs report eligibility and the reason when a sender cannot be bound. Email health numbers are information beside eligibility, never a gate.Settings
Settings are read live by the engine, so a change applies to the next send decision in any status.
Qualification
A sequence can also carry qualification criteria and run an enrich and judge pass over its people. Those endpoints exist for the assistant-driven authoring flow and are not needed to run a sequence from the API: people you enroll and never judge always arm. The endpoint pages under Qualification describe them.Consent
The engine enforces the outbound blocklist at enrollment, at launch, and again before every single send. If the blocklist cannot be read, the send is held rather than released.Available endpoints
Create sequence
Create a draft with brief, criteria and settings
List sequences
Every sequence with its live numbers
Get sequence
One sequence’s definition
Update sequence
Name, brief, criteria, reply instructions, settings
Set steps
Replace the step list of a draft
Edit steps
Update, append or remove steps in any status
Update step delay
Change one step’s wait
Add contacts
Enroll people with per-person outcomes
List contacts
Paginated people with status, fit and journey
Get contact
Full judgment and enrichment for one person
Get contact events
The per-person ledger
Update contact
Correct a name or handle
Include anyway
Override a below-cutoff judgment
Remove contact
Stop every remaining step for one person
Launch preview
What launching would do
Launch
Arm eligible candidates
Pause
Stop sending, keep places
Resume
Make people sendable again
Get stats
Numbers plus who is stuck and why
List replies
Who answered, newest first
List senders
Senders bound per channel
Set senders
Replace one channel’s senders
List email senders
Mailboxes with eligibility and health
List voice senders
Phone agents with eligibility and persona
Enrich contacts
Snapshot what the org knows about people
Judge contacts
Score people against the criteria
List qualification runs
Enrich and judge runs, latest first
Get qualification run
One run’s counts and aggregates
Set columns
Project evidence into the People table
Enrichment catalog
Paths a column may project
Data keys
Attached-data keys a variable can bind to
Discover contacts
Find an audience from what customers said