Skip to main content

Endpoints

A triggered flow enrolls contacts when they match a trigger and moves them through a graph of steps — sending emails, waiting, branching, updating fields. See the Triggered Flows guide for the concepts; this page covers the API surface. Flow status is draft, active, paused, or archived. Structure (triggers, steps, reentry policy) is only editable while the flow is a draft or paused — pause an active flow before changing it, then reactivate.
Drafts may be incomplete. Step and trigger format is validated on every write, but completeness (a send_email step without an email, a trigger without its list) is only enforced when you activate. Activation failures return the missing pieces.

Create a Flow

Triggers and steps can be supplied here or configured incrementally before activation.

Request Example

A welcome series — send an email, wait three days, then follow up only if the first email wasn’t opened:
Members who open the welcome email exit at check-opened (its true branch has no edge); everyone else gets the follow-up.

Response Example

201 Created with the flow object. All flow and step endpoints on this page return this same shape, except the member endpoints:

Triggers

A flow can have up to 25 triggers; a contact entering via any of them joins the flow, subject to the reentry policy. Each trigger is an object discriminated on type: Replace the full trigger list with:

Steps

Steps form a graph. Every step needs a unique step_id (1-120 characters) and links to the next step through edge fields — next_step_id for linear steps, or true_step_id / false_step_id / default_step_id on condition steps. Omitting the edge ends the flow after that step. An optional label names the step in the UI and member history.

Condition Rules

condition_check and condition-mode wait steps take the same rule tree as blast audiences, plus one extra source that is only legal inside flows: email_step, which tests engagement with an earlier send_email step.
metric is one of sent, delivered, opened, clicked, bounced, or unsubscribed, and nodeId references the step_id of a send_email step in the same flow.

Editing Steps

PUT takes {"steps": [...]} and replaces the whole list. POST inserts one step, wrapped in a step key, plus at most one placement selector — position (start or end, default end), before_step_id, or after_step_id:
Inserting does not rewrite edges — set the *_step_id fields yourself to wire the step in. Duplicate step IDs return 409 Conflict with error_code: "campaign_flow_duplicate_step_id". PATCH also wraps the partial update in a step key; only the provided fields are merged onto the existing step, and step_id cannot be changed:
Deleting a step that other steps still reference fails with 409 Conflict (campaign_flow_step_referenced) unless you pass repair_edges:
Use null as the replacement to detach the dangling edges instead.

Set a Step’s Email

Only valid for send_email steps. Takes the same body as a blast’s Set the Email: {"source": "existing", "email_id": "..."} or an inline email seeded from a template_id, your own html, or a blank branded scaffold. Inline emails start as drafts and must be approved before the flow can activate — the created email_id appears on the step in the response.

Lifecycle

Activation requires a Pro or Max plan. Free workspaces can create and edit flows through the API, but POST .../activate returns 403 Forbidden with error_code: "paid_plan_required":
Activation also validates the whole flow. If anything is incomplete, the API returns 400 Bad Request with error_code: "campaign_flow_not_ready" and the missing fields:
Pausing stops new work without dropping members — they resume when you reactivate. Active flows must be paused before archiving or deleting. Triggers fire on new events only; contacts already on a list do not enter an added_to_static_list flow retroactively.

Members

Add a Contact

Manually enrolls a contact into an active flow. Optionally pass per-member context that emails and webhooks in this run can reference as {{campaign.dynamic.<key>}} merge tokens:
Merge tokens — {{contact.*}} and {{campaign.dynamic.*}} alike — accept an optional case format, e.g. {{campaign.dynamic.couponCode:uppercase}}. See Formatting values. Enrollment respects the flow’s rules: 409 Conflict if the contact is already in the flow (campaign_flow_already_in_flow) or blocked by no_reentry (campaign_flow_reentry_denied), and 400 Bad Request if disqualification rules match (campaign_flow_contact_disqualified). 201 Created

Trigger a Flow (API trigger)

Enrolls a contact through the flow’s tented_api trigger — 409 Conflict (flow_api_trigger_not_configured) if the flow doesn’t have one. Identify the contact with exactly one of contact_id, email, or phone (the latter two are looked up against existing contacts), and optionally pass token values:
Each token becomes a {{campaign.dynamic.<key>}} merge token for the run’s emails and webhooks — {{campaign.dynamic.coupon_code}} above. The rules:
  • Values must be JSON scalars (string, number, or boolean); keys start with a letter and use letters/numbers/underscores. "trigger" is reserved.
  • If the flow’s tented_api trigger declares fields, keys are restricted to the declared names and values must match the declared types (campaign_flow_trigger_unknown_token / campaign_flow_trigger_invalid_token_type). A trigger with no declared fields accepts any keys.
  • The resolved payload must stay under 64 KB (campaign_flow_trigger_payload_too_large).
Enrollment follows the same rules as Add a Contact (reentry policy, disqualification) and returns 201 Created with the membership.

Remove a Contact

Drops the contact’s current run. Returns 200 OK with the updated membership, or 204 No Content if the contact was not in the flow.

List Members

Each member entry includes the contact identity, run status, current step, timestamps, and the steps executed so far.

Run Details

Returns one member’s full run: status, current position, failure info, and a timeline of events (entered flow, step executed, email sent/delivered/opened/clicked, dropped) with timestamps.

List Flows

Takes the same shape as listing blasts: status (draft, active, paused, archived, or any), archived, sort_by (updated_at, created_at, name), sort_order, page, limit, and search. Responses contain flows and a pagination object. Each flow includes aggregate detailstotal_entered, active_count, waiting_count, completed_count, dropped_count, and most_recent_entry_at.

Update, Archive, Delete

  • PATCH /v1/email-flows/{flowId} patches name, description, reentry_policy, triggers, steps, disqualification_rules, or settings. triggers and steps are full replacements — use the step endpoints for incremental edits. Setting disqualification_rules on an active flow immediately drops current members that match.
  • POST /v1/email-flows/{flowId}/archive archives a non-active flow.
  • DELETE /v1/email-flows/{flowId} deletes it and returns {"flow_id": "...", "deleted": true}. Active flows must be paused first.

Common Errors

Back to API Overview

Review the full public API endpoint map.