Subsequences are the complement of sequences. Sequences are the MAIN chain every lead walks; subsequences are branches that interrupt it. They are managed by different endpoints, use different trigger vocabularies, and measure waits differently.
subsequences_enabled
Every campaign carries a subsequences_enabled flag, returned by GET /campaigns/{campaign_id} and GET /campaigns/{campaign_id}/flow.
It is derived, not a setting — you never write it directly:
Update, delete and manual-move all require the flag to be
true. If it is not, they return 400:
Reading the Graph
GET/api/public/v1/campaigns/{campaign_id}/flow — scope campaigns:read
Node and edge vocabulary
An EVENT edge enters a branch; a TIMEOUT edge is the wait between two branch steps.
variants is populated for SUBSEQUENCE nodes only. A MAIN node returns variants: null because its content is served by the sequences endpoints — returning it in both places would give you two sources of truth for the same step.Creating a Branch
POST/api/public/v1/campaigns/{campaign_id}/flow/subsequences — scope campaigns:update, returns 201
subsequence_id is the entry edge
Entry triggers
Valid
status values are the lead statuses: PENDING, QUEUED, SENT, OPENED, REPLIED, FAILED, BOUNCED, UNSUBSCRIBED, EXTERNAL, BLOCKED.
INTENT_TAG also still honours the legacy single-value shape {"tag_name": "Demo Booked"}, and KEYWORD coerces a bare string into a one-element list.
Steps
At least one step is required — an empty
steps array is a 422 on create and a 400 on update.
condition_type between steps
Leave it at the default ALWAYS.
Variants
Variant field names differ between this endpoint andcampaigns.update:
variant_name defaults to A, B, C… by position when omitted, is uppercased and truncated to 10 characters. weight is clamped to 0–100. variant_label and content_type are also accepted.
A step with no variants at all enrolls and schedules but has nothing to render.
priority
The entry edge’s evaluation order among the campaign’s EVENT edges. Higher is evaluated first.
entry_from_node_id
The MAIN node the branch hangs off. Omit it unless you have a reason not to — the server resolves the campaign’s root MAIN node and creates one if the campaign predates the graph. Supplying a node that is not MAIN returns 400.
Updating a Branch
PUT/api/public/v1/campaigns/{campaign_id}/flow/subsequences/{subsequence_id} — scope campaigns:update
steps array is a 400.
Updatable fields: label, trigger_type, trigger_params, priority, is_active, steps. Setting is_active: false parks the branch without deleting it.
Deleting a Branch
DELETE/api/public/v1/campaigns/{campaign_id}/flow/subsequences/{subsequence_id} — scope campaigns:update
400:
subsequences_enabled back to false.
Moving Leads by Hand
POST/api/public/v1/campaigns/{campaign_id}/leads/move-to-subsequence — scope leads:update
Note the path: this lives under /leads, not /flow.
- enrolls each lead in the target branch;
- invalidates their pending MAIN follow-ups, so they stop receiving the main chain;
- skips leads already enrolled, reporting them in
skipped_leads; - emits a
subsequence_enteredwebhook event per new enrollment.
entry_edge_id is null for a manual move — no edge fired. That, plus the trigger_reason, is how you tell a hand move from an automatic entry downstream.
Per-Branch Analytics
GET/api/public/v1/analytics/campaigns/{campaign_id}/subsequences — scope campaigns:read
A campaign belonging to another team is a
404, indistinguishable from one that does not exist.
Lead Journey
GET/api/public/v1/campaigns/{campaign_id}/leads/{lead_id}/journey — scope leads:read
The whole of one lead’s path through the campaign graph — main chain and branches together, in send order.
node_key is the node ID for branch steps and step:{step_number} for main-chain steps, which is what lets one timeline mix both.
This is the fastest way to answer “why did this lead stop getting emails” — read trigger_invalidated down the steps and check enrollments.
Error Codes
Flow errors return a plain string indetail, not an object.
Failed mutations roll back — a
400 mid-create leaves no partial branch behind.
Next Steps
Follow-up Sequences
The MAIN chain that branches interrupt.
Leads
Find the lead IDs a manual move needs.
Webhook Events
subsequence_entered and subsequence_completed.Analytics
Campaign-level metrics alongside per-branch numbers.

