Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Flows API
version: '5.0'
description: "Use the Flows endpoints to list your flows, view the details of a single flow (including its\nversions and stages), and change a flow's status. These\nendpoints read and control existing flows; they do not create them.\n\n<Note>\n The Flows endpoints are in early access. MoEngage enhances these endpoints based on feedback during this period, but does not make breaking changes.\n</Note>\n\nThe API exposes the following endpoints:\n\n- `POST /v5/flows/search` — paginated listing with filters (status, delivery type, tags,\n teams, name, creator, creation-date range).\n- `GET /v5/flows/{flow_id}` — single flow detail. Use the optional `version_no` query\n parameter to view a specific version; the default is the last published version, or\n the draft if none is published.\n- `GET /v5/flows/{flow_id}/versions/{version_id}` — the details of a flow as it was in a\n specific version, identified by its ID.\n- `PATCH /v5/flows/{flow_id}/status` — lifecycle transition (`pause`, `resume`, `stop`,\n `retire`) or the flow-level `archive` / `unarchive` toggle.\n\n**Conventions**\n\n- IDs are 24-character identifiers. `flow_id` identifies the flow; `version_id` identifies one\n of its versions.\n- Every successful response uses the format `{response_id, type, data}`. The `response_id`\n echoes the `request_id` you send; if you omit it, the server uses the first 12 characters\n of a system-generated UUID.\n- Dates and times are in ISO 8601 UTC format (`YYYY-MM-DDThh:mm:ssZ`).\n- The search endpoint returns results one page at a time. To fetch the next page, send the\n `next_cursor` from the previous response back as the `cursor` value.\n\n**Permissions**\n\nFlows reuse the `campaigns` permission for scope checks. Read endpoints require the\n`campaigns:view` permission; the status endpoint requires `campaigns:create_manage`.\n\n**Status Model**\n\nPublic flow statuses: `DRAFT`, `ACTIVE`, `SCHEDULED`, `PAUSED`, `STOPPED`, `COMPLETED`,\n`RETIRED`, `UNDER_REVIEW`, `REJECTED`. `archived` is a separate boolean flag\n(it spans every version of the flow), not a status.\n\n**Rate Limits**: The rate limits are at the workspace level. A maximum of 10 requests per second,\n100 requests per minute, and 6,000 requests per hour are allowed per workspace for the search,\nget, and status endpoints.\n\n <Note>\n Breaching any limit rejects the request with a `429` response.\n </Note>\n"
servers:
- url: https://api-{dc}.moengage.com
variables:
dc:
default: '01'
description: 'MoEngage data center identifier. Replace it with the number assigned to your account, such as 01 (US), 02 (EU), 03 (India), 04 (US), 05 (Singapore), or 06 (Indonesia). For example, https://api-01.moengage.com. Data center 101 is not supported.
'
enum:
- '01'
- '02'
- '03'
- '04'
- '05'
- '06'
security:
- basicAuth: []
tags:
- name: Flows
paths:
/v5/flows/search:
post:
operationId: searchFlows
summary: Search Flows
description: 'This API returns a paginated list of flows matching your filters. Send filters in the
request body — all are optional and combine with AND. Multi-valued filters (`status`,
`delivery_type`, `tags`) match ANY of the supplied values, and archived flows are excluded
unless `include_archived` is `true`.
Each response includes a `next_cursor`. To get the next page, send that value as the
`cursor` in your next request. Sorting is not supported in this version; results are
returned most recent first. Your API key must have the `campaigns:view` permission (see
[Authentication](/api/flows/flows-overview#authentication)).
'
x-mint:
content: '#### Rate Limits
The rate limits are at the workspace level. A maximum of 10 requests per second, 100 requests per minute, and 6,000 requests per hour are allowed per workspace.
'
tags:
- Flows
security:
- basicAuth: []
parameters:
- $ref: '#/components/parameters/XMoeTenantId'
- $ref: '#/components/parameters/XMoeRequestIdHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FlowSearchRequest'
examples:
defaultPage:
summary: First page, default filters
value:
limit: 20
byStatus:
summary: Filter by status
value:
status:
- ACTIVE
- PAUSED
limit: 20
byDeliveryType:
summary: Filter by delivery type
value:
delivery_type:
- EVENT_TRIGGERED
- PERIODIC
limit: 20
byName:
summary: Name substring match
value:
name: test
limit: 20
byCreationDateRange:
summary: Creation-date range
value:
creation_start_time: '2025-01-01T00:00:00Z'
creation_end_time: '2026-12-31T23:59:59Z'
limit: 20
nextPage:
summary: Fetch the next page with a cursor
value:
limit: 20
cursor: eyJpZCI6ICI2OWYxZGU4NGY5ZTQwMWEyZDdkOWE5MzEifQ==
responses:
'200':
description: Flows matching the filters.
headers:
X-MOE-Request-Id:
$ref: '#/components/headers/XMoeRequestId'
content:
application/json:
schema:
$ref: '#/components/schemas/FlowSearchResponse'
example:
response_id: abc-701
type: flow
data:
flows:
- flow_id: 69f1de84f9e401a2d7d9a931
name: Welcome journey
status: ACTIVE
archived: false
delivery_type: EVENT_TRIGGERED
active_version_name: Version 2
tags:
- onboarding
created_at: '2026-01-05T10:00:00Z'
updated_at: '2026-02-01T09:30:00Z'
published_at: '2026-01-06T08:00:00Z'
created_by: agent@example.com
has_more: true
next_cursor: eyJpZCI6ICI2OWYxZGU4NGY5ZTQwMWEyZDdkOWE5MzEifQ==
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalServerError'
/v5/flows/{flow_id}:
get:
operationId: getFlow
summary: Get a Single Flow
description: 'This API returns everything about one flow — its settings, targeting, conversion
goal, and full stage-by-stage structure — typically after you find its `flow_id` with Search
Flows. Use the optional `version_no` query parameter to view a specific version; by default,
you get the last published version, or the draft if the flow was never published. Your API
key must have the `campaigns:view` permission (see the
[Authentication](/api/flows/flows-overview#authentication) section).
'
x-mint:
content: '#### Rate Limits
The rate limits are at the workspace level. A maximum of 10 requests per second, 100 requests per minute, and 6,000 requests per hour are allowed per workspace.
'
tags:
- Flows
security:
- basicAuth: []
parameters:
- $ref: '#/components/parameters/FlowId'
- name: version_no
in: query
required: false
description: 'View a specific version of the flow by its version number (the trailing integer of the version name, for example `Version 3` becomes `3`). When omitted, the last published version is returned, or the draft if none is published. A non-integer value returns `400`; a number that does not exist for this flow returns `404`.
'
schema:
type: integer
minimum: 1
- $ref: '#/components/parameters/XMoeTenantId'
- $ref: '#/components/parameters/XMoeRequestIdHeader'
responses:
'200':
description: Flow found.
headers:
X-MOE-Request-Id:
$ref: '#/components/headers/XMoeRequestId'
content:
application/json:
schema:
$ref: '#/components/schemas/FlowDetailResponse'
example:
response_id: abc-100
type: flow
data:
flow_id: 69f1de84f9e401a2d7d9a931
name: Welcome journey
status: ACTIVE
archived: false
delivery_type: EVENT_TRIGGERED
tags:
- onboarding
created_at: '2026-01-05T10:00:00Z'
updated_at: '2026-02-01T09:30:00Z'
published_at: '2026-01-06T08:00:00Z'
created_by: agent@example.com
published_by: agent@example.com
global_control_group_enabled: false
active_version_name: Version 2
versions:
- version_id: 69f1de84f9e401a2d7d9a931
version_name: Version 1
version_no: 1
status: RETIRED
- version_id: 7a02ef95f9e401a2d7d9aa42
version_name: Version 2
version_no: 2
status: ACTIVE
settings:
control_group:
enabled: false
frequency_capping:
ignore: false
ignore_and_count: false
bypass_dnd: false
attribution:
click_track_hours: 24
impression_track_hours: 24
conversion_goal_details:
primary_goal:
event: Purchase
goal_name: Made a purchase
secondary_goals: []
revenue_tracking: true
revenue_attribute: amount
revenue_currency: USD
exit_on_conversion: false
structure:
nodes:
- stage_id: n1
type: TRIGGER
sub_type: EVENT
parent_stage_id: null
child_stage_ids:
- n2
label: App Opened
config:
schedule:
delivery: one_time
start_time: '2026-01-06T08:00:00Z'
timezone: Asia/Kolkata
segmentation:
audience_type: all_users
- stage_id: n2
type: ACTION
sub_type: EMAIL
parent_stage_id: n1
child_stage_ids: []
label: Welcome email
config:
campaign_id: 69f1de84f9e401a2d7d9a999
channel: EMAIL
campaign_name: Welcome email
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalServerError'
/v5/flows/{flow_id}/versions/{version_id}:
get:
operationId: getFlowVersion
summary: Get a Specific Version of a Flow
description: 'This API returns a flow exactly as it was in a past version — for example,
to audit what was live before a recent change. If you already have the version number
rather than its ID, use `version_no` on Get a Single Flow instead. The `version_id` must
belong to `flow_id`, otherwise the API returns `404`. Your API key must have the
`campaigns:view` permission (see the
[Authentication](/api/flows/flows-overview#authentication) section).
'
x-mint:
content: '#### Rate Limits
The rate limits are at the workspace level. A maximum of 10 requests per second, 100 requests per minute, and 6,000 requests per hour are allowed per workspace.
'
tags:
- Flows
security:
- basicAuth: []
parameters:
- $ref: '#/components/parameters/FlowId'
- name: version_id
in: path
required: true
description: 'The 24-character ID of a specific version of the flow. Must belong to `flow_id`.
'
schema:
type: string
pattern: ^[a-f0-9]{24}$
- $ref: '#/components/parameters/XMoeTenantId'
- $ref: '#/components/parameters/XMoeRequestIdHeader'
responses:
'200':
description: Flow version found.
headers:
X-MOE-Request-Id:
$ref: '#/components/headers/XMoeRequestId'
content:
application/json:
schema:
$ref: '#/components/schemas/FlowDetailResponse'
example:
response_id: abc-102
type: flow
data:
flow_id: 69f1de84f9e401a2d7d9a931
name: Welcome journey
status: RETIRED
archived: false
delivery_type: EVENT_TRIGGERED
tags:
- onboarding
created_at: '2026-01-05T10:00:00Z'
updated_at: '2026-01-20T09:30:00Z'
published_at: '2026-01-06T08:00:00Z'
created_by: agent@example.com
published_by: agent@example.com
global_control_group_enabled: false
active_version_name: Version 1
versions:
- version_id: 7a02ef95f9e401a2d7d9aa42
version_name: Version 1
version_no: 1
status: RETIRED
settings:
control_group:
enabled: false
frequency_capping:
ignore: false
ignore_and_count: false
bypass_dnd: false
attribution:
click_track_hours: 24
impression_track_hours: 24
conversion_goal_details:
primary_goal:
event: Purchase
goal_name: Made a purchase
secondary_goals: []
revenue_tracking: true
revenue_attribute: amount
revenue_currency: USD
exit_on_conversion: false
structure:
nodes:
- stage_id: n1
type: TRIGGER
sub_type: EVENT
parent_stage_id: null
child_stage_ids:
- n2
label: App Opened
config:
schedule:
delivery: one_time
start_time: '2026-01-06T08:00:00Z'
timezone: Asia/Kolkata
segmentation:
audience_type: all_users
- stage_id: n2
type: ACTION
sub_type: EMAIL
parent_stage_id: n1
child_stage_ids: []
label: Welcome email
config:
campaign_id: 69f1de84f9e401a2d7d9a999
channel: EMAIL
campaign_name: Welcome email
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalServerError'
/v5/flows/{flow_id}/status:
patch:
operationId: updateFlowStatus
summary: Update Flow Status
description: 'This API changes a flow''s lifecycle state. It validates the requested transition against the flow''s
current state before applying it; an invalid transition returns `409`. Your API key must have the
`campaigns:create_manage` permission (see the [Authentication](/api/flows/flows-overview#authentication) section).
'
x-mint:
content: 'Lifecycle actions (`pause`, `resume`, `stop`, `retire`) accept an optional `version_no` and act on that
version (default: the active version). `archive` / `unarchive` apply to the whole flow and reject a `version_no`.
| Action | Allowed from | Result |
| --- | --- | --- |
| `pause` | `ACTIVE`, `SCHEDULED` | `PAUSED` |
| `resume` | `PAUSED` | `ACTIVE` |
| `stop` | `ACTIVE`, `SCHEDULED`, `PAUSED`, `RETIRED` | `STOPPED` |
| `retire` | `ACTIVE`, `PAUSED` | `RETIRED` |
| `archive` | `PAUSED`, `STOPPED`, `COMPLETED` (and not already archived) | sets `archived=true` |
| `unarchive` | any archived flow | sets `archived=false` |
#### Rate Limits
The rate limits are at the workspace level. A maximum of 10 requests per second, 100 requests per minute, and 6,000 requests per hour are allowed per workspace.
'
tags:
- Flows
security:
- basicAuth: []
parameters:
- $ref: '#/components/parameters/FlowId'
- name: Idempotency-Key
in: header
required: true
description: Client-generated UUID v4. Reusing the same key replays the original response instead of re-applying the transition.
schema:
type: string
format: uuid
- $ref: '#/components/parameters/XMoeTenantId'
- $ref: '#/components/parameters/XMoeRequestIdHeader'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/FlowStatusRequest'
examples:
pause:
summary: Pause an active flow
value:
action: pause
updated_by: agent@example.com
archive:
summary: Archive a flow
value:
action: archive
updated_by: agent@example.com
responses:
'200':
description: Flow status updated.
headers:
X-MOE-Request-Id:
$ref: '#/components/headers/XMoeRequestId'
content:
application/json:
schema:
$ref: '#/components/schemas/FlowStatusResponse'
example:
response_id: abc-200
type: flow
data:
flow_id: 69f1de84f9e401a2d7d9a931
status: PAUSED
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/ForbiddenStatusWrite'
'404':
$ref: '#/components/responses/NotFound'
'409':
description: The requested action is not a valid transition from the flow's current status.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
response_id: abc-409
error:
code: BAD_REQUEST
target: action
message: Cannot resume a flow that is not paused.
details: []
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalServerError'
components:
responses:
NotFound:
description: The flow (or the requested version) does not exist in this workspace.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
response_id: abc-100
error:
code: NOT_FOUND
target: flow
message: Flow not found.
details:
- target: flow_id
message: Flow not found.
RateLimited:
description: Per-app rate limit exceeded. Retry after the interval indicated in the `Retry-After` header.
headers:
Retry-After:
schema:
type: integer
description: Seconds until the rate-limit window resets.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
response_id: abc-101
error:
code: RATE_LIMITED
message: Rate limit exceeded for app key.
details: []
InternalServerError:
description: Unhandled server-side failure.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
response_id: abc-101
error:
code: INTERNAL_ERROR
message: Internal server error.
details: []
Unauthorized:
description: Authentication failed (missing or invalid credentials).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
response_id: abc-101
error:
code: UNAUTHORIZED
message: Invalid or missing credentials.
details: []
Forbidden:
description: You do not have the required permission for this operation.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
response_id: abc-450
error:
code: FORBIDDEN
target: permission
message: You do not have the required permission for this operation.
details:
- target: permission
message: 'Required permission: campaigns:view'
ForbiddenStatusWrite:
description: You do not have the required permission for this operation.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
response_id: abc-450
error:
code: FORBIDDEN
target: permission
message: You do not have the required permission for this operation.
details:
- target: permission
message: 'Required permission: campaigns:create_manage'
BadRequest:
description: 'The request failed validation — for example, a bad filter value, a malformed cursor, a non-integer `version_no`, an invalid date range, or a `flow_id` that is actually a version ID.
'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
response_id: abc-101
error:
code: VALIDATION_FAILED
target: request
message: One or more request parameters failed validation.
details:
- target: request
message: Check the request parameters and try again.
schemas:
ConversionGoalDetails:
type:
- object
- 'null'
description: Conversion-goal configuration from the entry node. Null when the flow has no conversion goal.
properties:
primary_goal:
type: object
properties:
event:
type:
- string
- 'null'
description: The name of the conversion-goal event.
goal_name:
type:
- string
- 'null'
secondary_goals:
type: array
items:
type: object
properties:
event:
type:
- string
- 'null'
goal_name:
type:
- string
- 'null'
revenue_tracking:
type: boolean
description: Whether revenue is attributed for the primary goal.
revenue_attribute:
type:
- string
- 'null'
description: Event attribute carrying the revenue amount. Present only when `revenue_tracking` is true.
revenue_currency:
type:
- string
- 'null'
description: Currency of the revenue attribute. Present only when `revenue_tracking` is true.
exit_on_conversion:
type:
- boolean
- 'null'
description: Whether a user exits the flow once they convert.
FlowStatusEnum:
type: string
description: 'Public lifecycle status of a flow (or of a specific version), independent of the `archived` flag.
'
enum:
- DRAFT
- ACTIVE
- SCHEDULED
- PAUSED
- STOPPED
- COMPLETED
- RETIRED
- UNDER_REVIEW
- REJECTED
FlowSearchRequest:
type: object
description: 'Filters for listing flows. All filters are optional and combine with AND. Enum filters (`status`, `delivery_type`) are case-insensitive.
'
properties:
request_id:
type: string
description: Optional if supplied via the `X-MOE-Request-Id` header; echoed in `response_id`.
status:
type: array
description: Keeps only flows whose status is in this set.
items:
$ref: '#/components/schemas/FlowStatusEnum'
delivery_type:
type: array
description: Keeps only flows that have one of these delivery types.
items:
$ref: '#/components/schemas/DeliveryTypeEnum'
tags:
type: array
description: The tag names to match; flows that carry any of them are kept.
items:
type: string
teams:
type: array
description: 'Team names. Required when the Flows-teams feature is enabled for the workspace — omitting it or sending an empty list returns `400 VALIDATION_FAILED` ("teams is required when the team feature is enabled"). When the feature is off, sending `teams` is rejected with `400`.
'
items:
type: string
name:
type: string
description: Matches flows whose name contains this text, case-insensitively.
created_by:
type: array
description: The email addresses of the flow creators to filter by.
items:
type: string
format: email
creation_start_time:
type: string
description: The inclusive lower bound on the creation time, in ISO 8601 UTC format.
example: '2025-01-01T00:00:00Z'
creation_end_time:
type: string
description: The inclusive upper bound on the creation time, in ISO 8601 UTC format. It must be on or after `creation_start_time`.
example: '2026-12-31T23:59:59Z'
include_archived:
type: boolean
default: false
description: '`false` (default) excludes archived flows; `true` returns both archived and non-archived.'
limit:
type: integer
minimum: 1
maximum: 100
default: 20
description: The number of results returned per page.
cursor:
type: string
description: The cursor from a previous page's `next_cursor`. Omit for the first page.
FlowSettings:
type: object
description: Flow-level settings. Null-valued fields may be omitted.
properties:
control_group:
type: object
properties:
enabled:
type:
- boolean
- 'null'
description: Whether a control group (holdout) is enabled for this flow.
percentage:
type:
- number
- 'null'
description: The percentage of users held out as a control group.
stickiness:
type:
- boolean
- 'null'
description: Keeps a user in the same control or treatment assignment across re-entry.
frequency_capping:
type: object
properties:
ignore:
type:
- boolean
- 'null'
description: Ignores frequency capping for this flow.
ignore_and_count:
type:
- boolean
- 'null'
description: Ignores capping but still counts sends toward it.
inactive_eviction_days:
type:
- integer
- 'null'
description: The number of days of user inactivity after which a user is evicted from the flow.
on_failure:
type:
- string
- 'null'
description: Defines the behavior when a stage fails.
bypass_dnd:
type:
- boolean
- 'null'
description: Sends messages even during the workspace Do-Not-Disturb window.
FlowNode:
type: object
description: One stage of the flow, such as a trigger, an action, a wait, a condition, or a split.
required:
- stage_id
properties:
stage_id:
type: string
description: Unique ID of this node within the flow.
type:
type: string
description: The category of this node.
enum:
- TRIGGER
- ACTION
- CONTROL
- CONDITION
- SPLIT
- BRANCH
sub_type:
type: string
description: 'Public sub-type within `type`: `TRIGGER` — `EVENT`, `BUSINESS_EVENT`, `ONE_TIME`, or `PERIODIC`; `ACTION` — a channel (`EMAIL`, `SMS`, `PUSH`, `WHATSAPP`, `IN_APP`, `ONSITE`, `CONNECTOR`, `CARDS`, `FB_AUDIENCE`, `GOOGLE_ADS`, `CONNECTED_APPS`) or `NBA`; `CONTROL` — `EXIT`, `WAIT_FOR_TIMER`, or `GO_TO`; `SPLIT` — `AB_SPLIT`, `IPO`, or `CONDITIONAL_SPLIT`; `CONDITION` — `HAS_DONE_EVENT`, `ON_EMAIL_CLICK`, `ON_EMAIL_OPEN`, or `CHECK_USER_ATTRIBUTE`; `BRANCH` mirrors its parent split or condition.
'
parent_stage_id:
type:
- string
- 'null'
description: ID of the parent node, or null for the entry (`TRIGGER`) node.
child_stage_ids:
type: array
description: IDs of the immediate downstream nodes.
items:
type: string
label:
type:
- string
- 'null'
description: Human-readable label shown in the flow builder.
config:
type: object
additionalProperties: true
description: 'Type-specific configuration. The shape depends on `type` and `sub_type`; null-valued fields are omitted. The example below shows a `CONDITION` node''s config. For the config shape of every node type (`CONDITION`, `BRANCH`, `SPLIT`, `ACTION`/`NBA`, and `CONTROL`), see [Flow structure and nodes](/api/flows/flows-overview#flow-structure-and-nodes).
'
example:
condition:
filter_operator: and
# --- truncated at 32 KB (42 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/moengage/refs/heads/main/openapi/moengage-flows-api-openapi.yml