Skip to main content
Use the Flows endpoints to discover flows, view a single flow (including its versions and stages), and change a flow’s status. These endpoints read and control flows; they do not create them.
The Flows endpoints are in early access. MoEngage enhances these endpoints based on feedback during this period, but does not make breaking changes.

Endpoints

The Flows API is a collection of the following endpoints:

Authentication

Authenticate with Basic Auth using your MoEngage Workspace ID (App ID) as the username and your API Key as the password. You can find these in the MoEngage dashboard at Settings > Account > APIs. Flows reuse the Campaigns permissions. Enable the matching checkboxes on your API key:
  • View (campaigns:view) for the read endpoints — Search Flows, Get a Single Flow, and Get a Specific Version of a Flow.
  • Create & Manage (campaigns:create_manage) for Update Flow Status.
The X-MOE-Tenant-ID header (your Workspace ID) is optional — when omitted, the workspace is resolved from the Basic Auth credentials in the Authorization header. You can also send an optional X-MOE-Request-Id. For more information on authentication and getting your credentials, refer to Getting your credentials. Requests go to your data center’s host, https://api-{dc}.moengage.com. For the full list of data centers and their identifiers, refer to Data Centers.

Conventions

  • IDs are raw 24-character ObjectIds. flow_id addresses the flow; version_id addresses one version.
  • Every successful response uses the envelope {response_id, type, data}.
  • Datetimes are ISO 8601 UTC (YYYY-MM-DDThh:mm:ssZ).
  • Search results are paginated. Each response includes a next_cursor. To get the next page, send that value as the cursor parameter in your next request.

Flow Structure and Nodes

Get a single flow and Get a specific version of a flow return the flow’s stages in data.structure.nodes[]. Each entry is a node (one stage of the flow). Nodes share a common envelope and carry a config object whose shape depends on the node’s type and sub_type. Every node includes these fields: The sections below describe the config shape for each node type. Field sets are documented from real flows; a node may include additional keys not shown here.

Condition Nodes

A CONDITION node evaluates a condition and routes users down one of two paths. child_stage_ids always has exactly two entries: index 0 is the path taken when the condition matches, and index 1 is the path when it does not. config fields:
  • condition — the rule to evaluate. It reuses the same filter grammar as a trigger’s event filter (filter_operator, filters[], and per-filter action_name, executed, execution.type/execution.count, and nested attributes).
  • wait — how long to wait before evaluating, as { duration, unit }. unit is mins, hours, or days.
  • evaluation_timing — when the condition is evaluated: ON_ENTRY or SINCE_PREVIOUS_STAGE.
Observed sub_type values: HAS_DONE_EVENT, ON_EMAIL_CLICK, ON_EMAIL_OPEN.
Two-way CONDITION node

Branch Nodes

A BRANCH node represents a single arm of a parent CONDITION or SPLIT. Its sub_type mirrors the parent’s sub_type, and its single child is the next real stage on that path. Its config depends on the parent:
  • Arm of a CONDITION (explicit YES/NO pattern): config is { "outcome": "YES" } or { "outcome": "NO" }.
  • Arm of a CONDITIONAL_SPLIT: config carries branch_index (0-based) and, for a conditioned arm, branch_type: "main" with a condition object. The catch-all arm uses branch_type: "default" and has no condition.
  • Arm of an AB_SPLIT or IPO: config carries name and percentage.
BRANCH arms of a CONDITIONAL_SPLIT

Split Nodes

A SPLIT node splits users into more than two paths (or two paths for IPO). Its child_stage_ids map one-to-one to BRANCH children. config fields depend on the sub_type:
  • CONDITIONAL_SPLIT routes each user down a branch based on a condition. Its config carries branch_order (the ordered list of child stage_ids), evaluation_timing, and wait.
  • AB_SPLIT divides users randomly by percentage. Its config.branches[] lists each arm as { stage_id, name, percentage }.
  • IPO (Intelligent Path Optimizer) uses the same config.branches[] as AB_SPLIT, plus an optimization_metric (observed value: ENGAGEMENT). The ordering comes from branches[], so there is no branch_order.
Multi-way CONDITIONAL_SPLIT
AB_SPLIT

Action Nodes

An ACTION node sends a campaign or selects a channel. For a channel send (EMAIL, PUSH, SMS, WHATSAPP, and so on), config carries campaign_id, channel, and campaign_name. The NBA (Next Best Action) sub_type is an ACTION node — it occupies the same slot as channel sends, not a separate node type. Its config fields:
  • channels[] — one entry per eligible channel, each { channel, stage_id, campaign_id }. stage_id references a sibling ACTION node (of that channel) that owns the actual send; the NBA node itself holds no campaign content.
  • fallback_channel — the channel used when the best channel can’t be determined (observed value: PUSH).
  • best_time_to_send — the send-time strategy (observed shape: { "default_time": "SEND_IMMEDIATELY" }).
ACTION node with NBA sub_type

Control Nodes

A CONTROL node manages flow control and path convergence. Observed sub_type values:
  • EXIT — exits the user from the flow.
  • WAIT_FOR_TIMER — holds the user for a set duration.
  • GO_TO — routes the user to a shared downstream stage (config.target_stage_id), used to re-converge parallel branches.

FAQs

No, this isn’t supported. You can search, read, and change the status of existing flows.
You do not enroll users directly. For event-triggered flows, use the Track Event API — a user enters the flow when a tracked event matches the flow’s entry condition. For business-event-triggered flows, use the Trigger Business Event API. Periodic flows are audience-driven and do not support API enrollment.
flow_id identifies the flow. version_id identifies one of its versions. To read a specific version, either pass version_no on Get a single flow, or call Get a specific version of a flow with the version_id.
You can pause, resume, stop, retire, archive, and unarchive a flow. Each change is validated against the flow’s current status; an invalid change returns a 409. Publish isn’t available.
The read endpoints (search, get flow, get version) require the campaigns:view permission. The status endpoint requires the campaigns:create_manage permission.