openapi: 3.0.0
info:
  title: Flows
  version: "5.0"
  description: |
    Use the Flows endpoints to list your flows, view the details of a single flow (including its
    versions and stages), and change a flow's status. These
    endpoints read and control existing flows; they do not create them.

    <Note>
      The Flows endpoints are in early access. MoEngage enhances these endpoints based on feedback during this period, but does not make breaking changes.
    </Note>

    The API exposes the following endpoints:

    - `POST /v5/flows/search` — paginated listing with filters (status, delivery type, tags,
      teams, name, creator, creation-date range).
    - `GET /v5/flows/{flow_id}` — single flow detail. Use the optional `version_no` query
      parameter to view a specific version; the default is the last published version, or
      the draft if none is published.
    - `GET /v5/flows/{flow_id}/versions/{version_id}` — the details of a flow as it was in a
      specific version, identified by its ID.
    - `PATCH /v5/flows/{flow_id}/status` — lifecycle transition (`pause`, `resume`, `stop`,
      `retire`) or the flow-level `archive` / `unarchive` toggle.

    **Conventions**

    - IDs are 24-character identifiers. `flow_id` identifies the flow; `version_id` identifies one
      of its versions.
    - Every successful response uses the format `{response_id, type, data}`. The `response_id`
      echoes the `request_id` you send; if you omit it, the server uses the first 12 characters
      of a system-generated UUID.
    - Dates and times are in ISO 8601 UTC format (`YYYY-MM-DDThh:mm:ssZ`).
    - The search endpoint returns results one page at a time. To fetch the next page, send the
      `next_cursor` from the previous response back as the `cursor` value.

    **Permissions**

    Flows reuse the `campaigns` permission for scope checks. Read endpoints require the
    `campaigns:view` permission; the status endpoint requires `campaigns:create_manage`.

    **Status Model**

    Public flow statuses: `DRAFT`, `ACTIVE`, `SCHEDULED`, `PAUSED`, `STOPPED`, `COMPLETED`,
    `RETIRED`, `UNDER_REVIEW`, `REJECTED`. `archived` is a separate boolean flag
    (it spans every version of the flow), not a status.

    **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 for the search,
    get, and status endpoints.

     <Note>
       Breaching any limit rejects the request with a `429` response.
     </Note>

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: []

paths:
  /v5/flows/search:
    post:
      operationId: searchFlows
      summary: Search Flows
      description: |
        This API returns a paginated list of the flows in your workspace, filtered by the criteria
        you send in the request body. Requires the `campaigns:view` permission.
      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/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, most recently updated first. Sorting is not supported in this version.
          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 the full details of one flow, including its settings, targeting, conversion
        goal, and stage-by-stage structure. Requires the `campaigns:view` permission.
      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/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, addressed by its version ID.
        Use it to audit what was live before a change. Requires the `campaigns:view` permission.
      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/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. Requires the `campaigns:create_manage` permission.
      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/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:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: |
        Authentication is done via Basic Auth. This requires a base64-encoded string of your credentials in the format `username:password`.

        - **Username**: Use your MoEngage Workspace ID (also known as the App ID). Find it in the MoEngage dashboard at **Settings** > **Account** > **API keys**.
        - **Password**: Use an API key from **Settings** > **Account** > **API keys**.

        Refer to [API Key Dashboard](/user-guide/settings/account/api-and-api-keys/api-key-dashboard) for details on creating and managing API keys.

  headers:
    XMoeRequestId:
      description: Echoed request ID. If you do not provide one, the server generates it.
      schema:
        type: string

    XMoeRequestIdEchoed:
      description: Echoes the X-MOE-Request-Id that you supplied.
      schema:
        type: string

  parameters:
    FlowId:
      name: flow_id
      in: path
      required: true
      description: >
        The 24-character ID of the flow. This must be the flow's own ID, not a version ID;
        passing a version ID returns `400`.
      schema:
        type: string
        pattern: '^[a-f0-9]{24}$'
        example: "6a3b09c938da57c8f5838880"

    XMoeRequestIdHeader:
      name: X-MOE-Request-Id
      in: header
      required: false
      description: >
        Client-supplied trace ID. The server echoes it in the `X-MOE-Request-Id` response header
        and in `response_id`. If you omit it, the server generates one.
      schema:
        type: string


    VersionName:
      name: version_name
      in: query
      required: false
      description: Flow version to query. Defaults to the active version.
      schema:
        type: string
        enum:
          - "Version 1"
          - "Version 2"
          - "All Versions"
        example: "Version 2"

  schemas:
    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

    DeliveryTypeEnum:
      type: string
      description: Indicates how users enter the flow.
      enum:
        - ONE_TIME
        - PERIODIC
        - ON_FLOW_EXIT
        - EVENT_TRIGGERED
        - BUSINESS_EVENT_TRIGGERED

    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.

    FlowSummary:
      type: object
      description: One flow as it appears in a search or list result.
      properties:
        flow_id:
          type: string
          pattern: '^[a-f0-9]{24}$'
          description: The ID of the flow.
        name:
          type: string
          description: Display name of the flow.
        status:
          allOf:
            - $ref: '#/components/schemas/FlowStatusEnum'
          description: Lifecycle status of the flow's active version.
        archived:
          type: boolean
          default: false
          description: Whether the flow is archived (spans all versions). Independent of `status`.
        delivery_type:
          $ref: '#/components/schemas/DeliveryTypeEnum'
        active_version_name:
          type: string
          nullable: true
          description: Display name of the active version, such as `Version 3`.
        tags:
          type: array
          description: Tag names attached to the flow.
          items:
            type: string
        created_at:
          type: string
          nullable: true
          description: ISO 8601 UTC creation time.
        updated_at:
          type: string
          nullable: true
          description: ISO 8601 UTC last-update time of the active version.
        published_at:
          type: string
          nullable: true
          description: ISO 8601 UTC publish time of the active version; null if never published.
        created_by:
          type: string
          nullable: true
          description: Email of the flow's creator.

    FlowSearchResponse:
      type: object
      properties:
        response_id:
          type: string
          description: Echo of the `X-MOE-Request-Id` that you supplied. When you omit it, MoEngage returns the first 12 characters of a system-generated UUID.
        type:
          type: string
          description: The type of resource the response describes.
          enum: [flow]
        data:
          type: object
          properties:
            flows:
              type: array
              items:
                $ref: '#/components/schemas/FlowSummary'
            has_more:
              type: boolean
              description: Whether another page exists after this one.
            next_cursor:
              type: string
              nullable: true
              description: Cursor to pass as `cursor` for the next page. Null on the last page.

    FlowVersion:
      type: object
      description: One version of a flow, as listed in a detail response's `versions`.
      properties:
        version_id:
          type: string
          pattern: '^[a-f0-9]{24}$'
        version_name:
          type: string
          description: Display name, such as `Version 2`.
        version_no:
          type: integer
          nullable: true
          description: The numeric version, parsed from the trailing integer of `version_name`.
        status:
          allOf:
            - $ref: '#/components/schemas/FlowStatusEnum'
          description: This version's own lifecycle status.

    FlowNode:
      type: object
      description: One stage of the flow, such as a trigger, an action, a wait, a condition, or a split.
      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
          nullable: true
          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
          nullable: true
          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
              filters:
                - action_name: MOE_EMAIL_CLICK
                  executed: true
                  filter_type: actions
                  execution:
                    count: 1
                    type: atleast
                  attributes:
                    filter_operator: and
                    filters: []
            wait:
              duration: 5
              unit: mins
            evaluation_timing: SINCE_PREVIOUS_STAGE

    FlowDetailData:
      allOf:
        - $ref: '#/components/schemas/FlowSummary'
        - type: object
          description: >
            Full single-flow detail. Carries every `FlowSummary` field plus the version list,
            publish metadata, settings, attribution, conversion goal, and its stages.
          properties:
            active_version_name:
              type: string
              nullable: true
              description: Display name of the flow's active version.
            versions:
              type: array
              nullable: true
              description: All versions of the flow, sorted by `version_no`. Null for a single-version flow.
              items:
                $ref: '#/components/schemas/FlowVersion'
            published_by:
              type: string
              nullable: true
              description: Email of the user who published this version.
            approvers:
              type: array
              nullable: true
              description: Approver emails (CAF), when set.
              items:
                type: string
            global_control_group_enabled:
              type: boolean
              default: false
              description: Whether the global control group is enabled for this flow.
            settings:
              $ref: '#/components/schemas/FlowSettings'
            attribution:
              $ref: '#/components/schemas/FlowAttribution'
            conversion_goal_details:
              $ref: '#/components/schemas/ConversionGoalDetails'
            structure:
              type: object
              description: The stages of the flow.
              properties:
                nodes:
                  type: array
                  items:
                    $ref: '#/components/schemas/FlowNode'

    FlowSettings:
      type: object
      description: Flow-level settings. Null-valued fields may be omitted.
      properties:
        control_group:
          type: object
          properties:
            enabled:
              type: boolean
              nullable: true
              description: Whether a control group (holdout) is enabled for this flow.
            percentage:
              type: number
              nullable: true
              description: The percentage of users held out as a control group.
            stickiness:
              type: boolean
              nullable: true
              description: Keeps a user in the same control or treatment assignment across re-entry.
        frequency_capping:
          type: object
          properties:
            ignore:
              type: boolean
              nullable: true
              description: Ignores frequency capping for this flow.
            ignore_and_count:
              type: boolean
              nullable: true
              description: Ignores capping but still counts sends toward it.
        inactive_eviction_days:
          type: integer
          nullable: true
          description: The number of days of user inactivity after which a user is evicted from the flow.
        on_failure:
          type: string
          nullable: true
          description: Defines the behavior when a stage fails.
        bypass_dnd:
          type: boolean
          nullable: true
          description: Sends messages even during the workspace Do-Not-Disturb window.

    FlowAttribution:
      type: object
      nullable: true
      description: >
        Click and impression attribution windows for the flow, derived from its channel action
        nodes. Null when no channel action declares them.
      properties:
        click_track_hours:
          type: integer
          nullable: true
        impression_track_hours:
          type: integer
          nullable: true

    ConversionGoalDetails:
      type: object
      nullable: true
      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
              nullable: true
              description: The name of the conversion-goal event.
            goal_name:
              type: string
              nullable: true
        secondary_goals:
          type: array
          items:
            type: object
            properties:
              event:
                type: string
                nullable: true
              goal_name:
                type: string
                nullable: true
        revenue_tracking:
          type: boolean
          description: Whether revenue is attributed for the primary goal.
        revenue_attribute:
          type: string
          nullable: true
          description: Event attribute carrying the revenue amount. Present only when `revenue_tracking` is true.
        revenue_currency:
          type: string
          nullable: true
          description: Currency of the revenue attribute. Present only when `revenue_tracking` is true.
        exit_on_conversion:
          type: boolean
          nullable: true
          description: Whether a user exits the flow once they convert.

    FlowDetailResponse:
      type: object
      properties:
        response_id:
          type: string
          description: Echo of the `X-MOE-Request-Id` that you supplied. When you omit it, MoEngage returns the first 12 characters of a system-generated UUID.
        type:
          type: string
          description: The type of resource the response describes.
          enum: [flow]
        data:
          $ref: '#/components/schemas/FlowDetailData'

    FlowStatusRequest:
      type: object
      required: [action, updated_by]
      properties:
        action:
          type: string
          description: The lifecycle operation to apply. `publish` is not available in this phase.
          enum: [pause, resume, stop, retire, archive, unarchive]
        version_no:
          type: integer
          minimum: 1
          description: >
            Optional. For lifecycle actions (`pause`, `resume`, `stop`, `retire`), acts on this
            version (default: the active version). Rejected for `archive` / `unarchive`.
        updated_by:
          type: string
          format: email
          description: Email of the user performing the action. Recorded in the audit log.
        request_id:
          type: string
          description: Optional if supplied via the `X-MOE-Request-Id` header; echoed in `response_id`.

    FlowStatusResponse:
      type: object
      properties:
        response_id:
          type: string
          description: Echo of the `X-MOE-Request-Id` that you supplied. When you omit it, MoEngage returns the first 12 characters of a system-generated UUID.
        type:
          type: string
          description: The type of resource the response describes.
          enum: [flow]
        data:
          type: object
          properties:
            flow_id:
              type: string
              description: The flow acted on.
            status:
              $ref: '#/components/schemas/FlowStatusEnum'

    ErrorResponse:
      type: object
      required: [error, response_id]
      properties:
        response_id:
          type: string
          description: Echo of the `X-MOE-Request-Id` that you supplied. When you omit it, MoEngage returns the first 12 characters of a system-generated UUID.
        error:
          type: object
          description: The details of the failure.
          required: [code, message]
          properties:
            code:
              type: string
              description: A machine-readable code that identifies the type of failure.
              enum:
                - VALIDATION_FAILED
                - BAD_REQUEST
                - NOT_FOUND
                - UNAUTHORIZED
                - FORBIDDEN
                - RATE_LIMITED
                - INTERNAL_ERROR
            message:
              type: string
              description: A human-readable explanation of the failure.
            target:
              type: string
              description: The component or field the error relates to.
            details:
              type: array
              description: One entry per failing check.
              items:
                type: object
                properties:
                  target:
                    type: string
                    description: The field that failed the check.
                  message:
                    type: string
                    description: An explanation of why the field failed the check.

  responses:
    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.
    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"
    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: []
