Loops Workflow nodes API

Create, read, update, delete and reroute the nodes of a workflow graph. 7 operation(s) in the Loops REST API v1 (OpenAPI 1.21.6).

OpenAPI Specification

loops-workflow-nodes-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Loops OpenAPI Spec Workflow nodes API
  description: This is the OpenAPI Spec for the [Loops API](https://loops.so/docs/api).
  version: 1.21.6
servers:
- url: https://app.loops.so/api/v1
tags:
- name: Workflow nodes
  description: View and mutate workflow nodes
paths:
  /workflows/{workflowId}/nodes:
    parameters:
    - name: workflowId
      in: path
      required: true
      description: The ID of the workflow.
      schema:
        type: string
    post:
      tags:
      - Workflow nodes
      summary: Create a workflow node
      operationId: createWorkflowNode
      description: 'Create a new default workflow node and return it with the latest workflow.


        Choose where the node goes with `insertMode`: `between` places it between an existing `fromNodeId` -> `toNodeId` connection, `before` places it before `toNodeId`, and `after` places it after `fromNodeId` when that node has exactly one outgoing connection. `after` is a convenience for simple linear paths, so callers do not need to fetch and pass the current child node ID. It is invalid when `fromNodeId` has no outgoing nodes, multiple outgoing nodes, or is an exit node. When the source has multiple outgoing nodes, use `between` with the exact `toNodeId` instead. For `before`, deprecated `beforeNodeId` requests are still accepted for compatibility, but new callers should use `toNodeId`.


        New nodes start with default settings; update the node after creation to configure it. Branch nodes create their default paths too: `BranchNode` creates two `AudienceFilter` children, and `ExperimentBranchNode` creates two regular `VariantNode` children plus one control `VariantNode`. Public workflows can have up to 300 nodes. Generated children count toward that limit, so a normal create adds 1 node, `BranchNode` adds 3, and `ExperimentBranchNode` adds 4. To add a sibling child path to a branch or experiment branch, use the `POST /v1/workflows/{workflowId}/nodes/{nodeId}/add-branch` endpoint. Branch paths can be edited with create-node, but a workflow cannot be started unless each direct `BranchNode` child is an `AudienceFilter`. For experiments, use create-node only to insert a missing `VariantNode` before non-variant content; use add-branch for another variant path.'
      x-mint:
        href: /api-reference/create-workflow-node
        content: 'Choose where the node goes with `insertMode`:

          - `between` places it between an existing `fromNodeId` -> `toNodeId` connection

          - `before` places it before `toNodeId`

          - `after` places it after `fromNodeId` when that node has exactly one outgoing connection.


          Use `after` for simple linear paths when you do not want to fetch and pass the current child node ID. `after` is invalid when `fromNodeId` has no outgoing nodes, multiple outgoing nodes, or is an exit node. When the source has multiple outgoing nodes, use `between` with the exact `toNodeId` instead. For `before`, deprecated `beforeNodeId` requests are still accepted for compatibility, but new callers should use `toNodeId`.


          New nodes start with default settings; update the node after creation to configure it. Branch nodes create their default paths too: `BranchNode` creates two `AudienceFilter` children, and `ExperimentBranchNode` creates two regular `VariantNode` children plus one control `VariantNode`.


          Public workflows can have up to 300 nodes. Generated children count toward that limit, so a normal create adds 1 node, `BranchNode` adds 3, and `ExperimentBranchNode` adds 4. To add a sibling child path to a branch or experiment branch, use the `POST /v1/workflows/{workflowId}/nodes/{nodeId}/add-branch` endpoint. Branch paths can be edited with create-node, but a workflow cannot be started unless each direct `BranchNode` child is an `AudienceFilter`. For experiments, use create-node only to insert a missing `VariantNode` before non-variant content; use add-branch for another variant path.'
        metadata:
          sidebarTitle: Create a node
          description: Create a new default workflow node and return it with the latest workflow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWorkflowNodeRequest'
      responses:
        '200':
          description: Workflow node created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateWorkflowNodeResponse'
        '400':
          description: Invalid request. Details will be shown in `message`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '401':
          description: Invalid API key.
        '404':
          description: Workflow or workflow node not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '405':
          description: Wrong HTTP request method.
        '409':
          description: '`expectedRevisionId` is stale.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
      security:
      - apiKey: []
  /workflows/{workflowId}/nodes/{nodeId}/add-branch:
    parameters:
    - name: workflowId
      in: path
      required: true
      description: The ID of the workflow.
      schema:
        type: string
    - name: nodeId
      in: path
      required: true
      description: The ID of the BranchNode or ExperimentBranchNode that should receive one new child.
      schema:
        type: string
    post:
      tags:
      - Workflow nodes
      summary: Add a branch
      operationId: addWorkflowBranch
      description: 'Add a branch and a child node under an existing Branch or Experiment node. Returns the created child node plus the latest workflow.


        - Adding a branch to a `BranchNode` creates one `AudienceFilter` child node.

        - Adding a branch to an `ExperimentBranchNode` creates one `VariantNode` child node.


        This endpoint does not accept node configuration fields; update the child node with `POST /v1/workflows/{workflowId}/nodes/{nodeId}` after creation. Public workflows are limited to 300 nodes, and this endpoint adds 1 node.'
      x-mint:
        href: /api-reference/add-workflow-branch
        content: 'Adding a branch to a `BranchNode` creates one `AudienceFilter` child node.

          Adding a branch to an `ExperimentBranchNode` creates one `VariantNode` child node.


          This endpoint does not accept node configuration fields; [update the child node](/api-reference/update-workflow-node) after creation. Public workflows are limited to 300 nodes, and this endpoint adds 1 node.'
        metadata:
          sidebarTitle: Add a branch
          description: Add a branch and a child node under an existing Branch or Experiment node.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddWorkflowBranchRequest'
      responses:
        '200':
          description: Branch added.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AddWorkflowBranchResponse'
        '400':
          description: Invalid `workflowId`, `nodeId`, request body, branch target, workflow state, or workflow node cap.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '401':
          description: Invalid API key.
        '404':
          description: Workflow or workflow node not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '405':
          description: Wrong HTTP request method.
        '409':
          description: '`expectedRevisionId` is stale.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
      security:
      - apiKey: []
  /workflows/{workflowId}/nodes/{nodeId}:
    parameters:
    - name: workflowId
      in: path
      required: true
      description: The ID of the workflow.
      schema:
        type: string
        examples:
        - clw1a3b5c7d9e1f3g5h7i9j1
    - name: nodeId
      in: path
      required: true
      description: The ID of the workflow node.
      schema:
        type: string
        examples:
        - cln8p0q2r4s6t8u0v2w4x6z8
    get:
      tags:
      - Workflow nodes
      summary: Get a workflow node
      operationId: getWorkflowNode
      description: Retrieve detailed data for a single workflow node.
      x-mint:
        href: /api-reference/get-workflow-node
        metadata:
          sidebarTitle: Get a node
      responses:
        '200':
          description: Successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowNodeWithRevision'
        '400':
          description: Invalid `workflowId` or `nodeId`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '401':
          description: Invalid API key.
        '404':
          description: Workflow or workflow node not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '405':
          description: Wrong HTTP request method.
      security:
      - apiKey: []
    post:
      tags:
      - Workflow nodes
      summary: Update a workflow node
      operationId: updateWorkflowNode
      description: Update workflow-node-owned fields for a single node. Shared resources such as email messages and audience segments should be updated through their own APIs.
      x-mint:
        href: /api-reference/update-workflow-node
        content: Shared resources such as email messages and audience segments should be updated through their own APIs.
        metadata:
          sidebarTitle: Update a node
          description: Update workflow-node-owned fields for a single node.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWorkflowNodeRequest'
      responses:
        '200':
          description: Workflow node updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateWorkflowNodeResponse'
        '400':
          description: Invalid `workflowId`, `nodeId`, request body, or node update.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '401':
          description: Invalid API key.
        '404':
          description: Workflow or workflow node not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '405':
          description: Wrong HTTP request method.
        '409':
          description: '`expectedRevisionId` is stale.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '501':
          description: This node update is not implemented.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
      security:
      - apiKey: []
    delete:
      tags:
      - Workflow nodes
      summary: Delete a workflow node
      operationId: deleteWorkflowNode
      description: 'Delete a single workflow node. If contacts are queued at the node, Loops returns with `"status": "queuedContactsFound"` instead of deleting. Retry with `queuedContactPolicy: "discard"` to delete the node and discard those queued contacts. Confirmed deletion responses include the simplified workflow after the node is removed.'
      x-mint:
        href: /api-reference/delete-workflow-node
        content: 'Delete a node from a workflow.


          Make a dry run request using `dryRun: true`.


          If contacts are queued at the node, Loops returns with `"status": "queuedContactsFound"` instead of deleting. Retry with `queuedContactPolicy: "discard"` to delete the node and discard those queued contacts.


          Confirmed deletion responses include the simplified workflow after the node is removed.'
        metadata:
          sidebarTitle: Delete a node
          description: Delete a single workflow node.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeleteWorkflowNodeRequest'
      responses:
        '200':
          description: Delete dry run, queued-contact warning, or deletion result. Confirmed deletion responses include the simplified workflow after the node is removed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteWorkflowNodeResponse'
        '400':
          description: Invalid `workflowId`, `nodeId`, request body, or delete target.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '401':
          description: Invalid API key.
        '404':
          description: Workflow or workflow node not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '405':
          description: Wrong HTTP request method.
        '409':
          description: '`expectedRevisionId` is stale.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
      security:
      - apiKey: []
  /workflows/{workflowId}/nodes/{nodeId}/reroute:
    parameters:
    - name: workflowId
      in: path
      required: true
      description: The ID of the workflow.
      schema:
        type: string
        examples:
        - clw1a3b5c7d9e1f3g5h7i9j1
    - name: nodeId
      in: path
      required: true
      description: The ID of the source workflow node whose outgoing connection should be moved.
      schema:
        type: string
        examples:
        - cln1a3b5c7d9e1f3g5h7i9j1
    post:
      tags:
      - Workflow nodes
      summary: Reroute a node connection
      operationId: rerouteNodeConnection
      description: Reroute the source node's existing connection to another valid target node. Returns the updated source node and the latest workflow.
      x-mint:
        href: /api-reference/reroute-node-connection
        content: 'Use this endpoint to modify an existing node connection to another target. Send the source node in the URL path and the new target in the request body.


          The source node must have exactly one outgoing connection. Branch and experiment branch nodes cannot be rerouted with this endpoint because they have multiple branch-specific outputs. The current target must still have another incoming connection after the reroute, and the new target must be valid for the source node. The workflow cannot be edited while in a `SENDING` state.'
        metadata:
          sidebarTitle: Reroute a node
          description: Reroute one existing node connection to another valid target node.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RerouteNodeConnectionRequest'
      responses:
        '200':
          description: Node connection rerouted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RerouteNodeConnectionResponse'
        '400':
          description: Invalid `workflowId`, `nodeId`, request body, node connection selection, reroute target, or workflow state.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '401':
          description: Invalid API key.
        '404':
          description: Workflow or workflow node not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '405':
          description: Wrong HTTP request method.
        '409':
          description: '`expectedRevisionId` is stale.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
      security:
      - apiKey: []
  /workflows/{workflowId}/nodes/{nodeId}/recursive:
    parameters:
    - name: workflowId
      in: path
      required: true
      description: The ID of the workflow.
      schema:
        type: string
    - name: nodeId
      in: path
      required: true
      description: The root node ID of the subtree to delete.
      schema:
        type: string
    delete:
      tags:
      - Workflow nodes
      summary: Delete workflow nodes recursively
      operationId: deleteWorkflowNodeRecursively
      description: 'Delete a node and its downstream subtree. If contacts are queued at any node that would be deleted, Loops returns with `"status": "queuedContactsFound"` instead of deleting. Retry with `queuedContactPolicy: "discard"` to delete the nodes and discard those queued contacts. Confirmed deletion responses include the simplified workflow after the nodes are removed.'
      x-mint:
        href: /api-reference/delete-workflow-nodes
        content: 'Delete a node and its downstream subtree.


          Make a dry run request using `dryRun: true`.


          If contacts are queued at any node that would be deleted, Loops returns with `"status": "queuedContactsFound"` instead of deleting. Retry with `queuedContactPolicy: "discard"` to delete the nodes and discard those queued contacts.


          Confirmed deletion responses include the simplified workflow after the nodes are removed.'
        metadata:
          sidebarTitle: Delete nodes
          description: Delete a node and its downstream subtree.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeleteWorkflowNodeRequest'
      responses:
        '200':
          description: Delete dry run, queued-contact warning, or deletion result. Confirmed deletion responses include the simplified workflow after the nodes are removed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteWorkflowNodeResponse'
        '400':
          description: Invalid `workflowId`, `nodeId`, request body, or delete target.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '401':
          description: Invalid API key.
        '404':
          description: Workflow or workflow node not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
        '405':
          description: Wrong HTTP request method.
        '409':
          description: '`expectedRevisionId` is stale.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowFailureResponse'
      security:
      - apiKey: []
components:
  schemas:
    ActivityCondition:
      type: object
      description: Matches contacts by their activity on a campaign or workflow.
      properties:
        type:
          type: string
          enum:
          - activity
        action:
          type: string
          enum:
          - sent
          - opened
          - clicked
        negate:
          type: boolean
        target:
          type: string
          enum:
          - campaign
          - workflow
          - workflowEmail
        id:
          type: string
          description: The ID of the campaign, workflow, or workflow email.
      required:
      - type
      - action
      - negate
      - target
      - id
      examples:
      - type: activity
        action: opened
        negate: false
        target: campaign
        id: clc4m6n8p0q2r4s6t8u0v2x4
    AddToListTriggerWorkflowMutationNode:
      type: object
      properties:
        id:
          type: string
        typeName:
          type: string
          enum:
          - AddToListTrigger
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
        mailingListId:
          type:
          - string
          - 'null'
          description: The ID of the mailing list this trigger sends to, if set.
        reEligible:
          $ref: '#/components/schemas/WorkflowReEligible'
      required:
      - id
      - typeName
      - nextNodeIds
      - mailingListId
      - reEligible
    AddToListTriggerWorkflowMutationNodeWithRevision:
      allOf:
      - $ref: '#/components/schemas/AddToListTriggerWorkflowMutationNode'
      - $ref: '#/components/schemas/WorkflowMutationNodeRevision'
    AddToListTriggerWorkflowNode:
      type: object
      properties:
        id:
          type: string
          examples:
          - cln8p0q2r4s6t8u0v2w4x6z8
        workflowId:
          type: string
          examples:
          - clw1a3b5c7d9e1f3g5h7i9j1
        typeName:
          type: string
          enum:
          - AddToListTrigger
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
        mailingListId:
          type:
          - string
          - 'null'
          examples:
          - clm2k8j4h6g0f8d6s4a2b0z8
          - null
          description: The ID of the mailing list that triggers the workflow.
        reEligible:
          $ref: '#/components/schemas/WorkflowReEligible'
      required:
      - id
      - workflowId
      - typeName
      - nextNodeIds
      - mailingListId
      - reEligible
      additionalProperties: false
    AddWorkflowBranchRequest:
      type: object
      properties:
        expectedRevisionId:
          $ref: '#/components/schemas/WorkflowExpectedRevisionId'
      required:
      - expectedRevisionId
      additionalProperties: false
    AddWorkflowBranchResponse:
      type: object
      properties:
        node:
          $ref: '#/components/schemas/WorkflowMutationNodeWithRevision'
        workflow:
          $ref: '#/components/schemas/SimplifiedWorkflow'
      required:
      - node
      - workflow
      additionalProperties: false
    AudienceFilter:
      type:
      - object
      - 'null'
      description: A tree of audience conditions combined with `match`.
      properties:
        match:
          type: string
          enum:
          - all
          - any
        conditions:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/AudienceFilterCondition'
      required:
      - match
      - conditions
      additionalProperties: false
    AudienceFilterCondition:
      oneOf:
      - $ref: '#/components/schemas/PropertyCondition'
      - $ref: '#/components/schemas/OptInCondition'
      - $ref: '#/components/schemas/ActivityCondition'
      discriminator:
        propertyName: type
    AudienceFilterInRequest:
      type:
      - object
      - 'null'
      description: A tree of audience conditions combined with `match`. Setting this without also providing `audienceSegmentId` clears any existing `audienceSegmentId`. When both are provided, this filter is applied on top of the segment's filter.
      properties:
        match:
          type: string
          enum:
          - all
          - any
        conditions:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/AudienceFilterCondition'
      required:
      - match
      - conditions
      additionalProperties: false
    AudienceFilterWorkflowMutationNode:
      type: object
      properties:
        id:
          type: string
        typeName:
          type: string
          enum:
          - AudienceFilter
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
        audienceFilter:
          $ref: '#/components/schemas/AudienceFilter'
        audienceSegmentId:
          type: string
          description: The ID of the audience segment this trigger targets.
        appliesDownstream:
          description: If `true`, the audience filter will apply to all downstream nodes. If `false`, the audience filter will only apply to the current node. Matches the "Filter scope" option in the UI.
          type: boolean
      required:
      - id
      - typeName
      - nextNodeIds
      - appliesDownstream
    AudienceFilterWorkflowMutationNodeWithRevision:
      allOf:
      - $ref: '#/components/schemas/AudienceFilterWorkflowMutationNode'
      - $ref: '#/components/schemas/WorkflowMutationNodeRevision'
    AudienceFilterWorkflowNode:
      type: object
      properties:
        id:
          type: string
          examples:
          - cln8p0q2r4s6t8u0v2w4x6z8
        workflowId:
          type: string
          examples:
          - clw1a3b5c7d9e1f3g5h7i9j1
        typeName:
          type: string
          enum:
          - AudienceFilter
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
        audienceFilter:
          $ref: '#/components/schemas/AudienceFilter'
        audienceSegmentId:
          type: string
        appliesDownstream:
          description: If `true`, the audience filter will apply to all downstream nodes. If `false`, the audience filter will only apply to the current node. Matches the "Filter scope" option in the UI.
          type: boolean
      required:
      - id
      - workflowId
      - typeName
      - nextNodeIds
      - appliesDownstream
      additionalProperties: false
    BlankTriggerWorkflowMutationNode:
      type: object
      properties:
        id:
          type: string
        typeName:
          type: string
          enum:
          - BlankTrigger
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
      required:
      - id
      - typeName
      - nextNodeIds
    BlankTriggerWorkflowMutationNodeWithRevision:
      allOf:
      - $ref: '#/components/schemas/BlankTriggerWorkflowMutationNode'
      - $ref: '#/components/schemas/WorkflowMutationNodeRevision'
    BlankTriggerWorkflowNode:
      type: object
      properties:
        id:
          type: string
          examples:
          - cln8p0q2r4s6t8u0v2w4x6z8
        workflowId:
          type: string
          examples:
          - clw1a3b5c7d9e1f3g5h7i9j1
        typeName:
          type: string
          enum:
          - BlankTrigger
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
      required:
      - id
      - workflowId
      - typeName
      - nextNodeIds
      additionalProperties: false
    BranchWorkflowMutationNode:
      type: object
      properties:
        id:
          type: string
        typeName:
          type: string
          enum:
          - BranchNode
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
      required:
      - id
      - typeName
      - nextNodeIds
    BranchWorkflowMutationNodeWithRevision:
      allOf:
      - $ref: '#/components/schemas/BranchWorkflowMutationNode'
      - $ref: '#/components/schemas/WorkflowMutationNodeRevision'
    BranchWorkflowNode:
      type: object
      properties:
        id:
          type: string
          examples:
          - cln8p0q2r4s6t8u0v2w4x6z8
        workflowId:
          type: string
          examples:
          - clw1a3b5c7d9e1f3g5h7i9j1
        typeName:
          type: string
          enum:
          - BranchNode
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
      required:
      - id
      - workflowId
      - typeName
      - nextNodeIds
      additionalProperties: false
    ContactPropertyTriggerWorkflowMutationNode:
      type: object
      properties:
        id:
          type: string
        typeName:
          type: string
          enum:
          - ContactPropertyTrigger
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
        contactPropertyQuery:
          oneOf:
          - $ref: '#/components/schemas/WorkflowContactPropertyQuery'
          - type: 'null'
        reEligible:
          $ref: '#/components/schemas/WorkflowReEligible'
      required:
      - id
      - typeName
      - nextNodeIds
      - contactPropertyQuery
      - reEligible
    ContactPropertyTriggerWorkflowMutationNodeWithRevision:
      allOf:
      - $ref: '#/components/schemas/ContactPropertyTriggerWorkflowMutationNode'
      - $ref: '#/components/schemas/WorkflowMutationNodeRevision'
    ContactPropertyTriggerWorkflowNode:
      type: object
      properties:
        id:
          type: string
          examples:
          - cln8p0q2r4s6t8u0v2w4x6z8
        workflowId:
          type: string
          examples:
          - clw1a3b5c7d9e1f3g5h7i9j1
        typeName:
          type: string
          enum:
          - ContactPropertyTrigger
        nextNodeIds:
          $ref: '#/components/schemas/WorkflowNextNodeIds'
        contactPropertyQuery:
          oneOf:
          - $ref: '#/components/schemas/WorkflowContactPropertyQuery'
          - type: 'null'
        reEligible:
          $ref: '#/components/schemas/WorkflowReEligible'
      required:
      - id
      - workflowId
      - typeName
      - nextNodeIds
      - contactPropertyQuery
      - reEligible
      additionalProperties: false
    CreateWorkflowNodeAfterRequest:
      type: object
      description: Insert a new node after `fromNodeId`. This is valid only when `fromNodeId` has exactly one outgoing node. It is invalid when `fromNodeId` has no outgoing nodes, multiple outgoing nodes, or is an exit node. When the source has multiple outgoing nodes, use `between` with the exact `toNodeId` instead.
      properties:
        expectedRevisionId:
          $ref: '#/components/schemas/WorkflowExpectedRevisionId'
        insertMode:
          type: string
          enum:
          - after
        nodeTypeName:
          $ref: '#/components/schemas/CreateWorkflowNodeTypeName'
        fromNodeId:
          type: string
          description: The node to insert after. This node must currently have exactly one outgoing node.
      required:
      - expectedRevisionId
      - insertMode
      - nodeTypeName
      - fromNodeId
      additionalProperties: false
    CreateWorkflowNodeBeforeRequest:
      type: object
      description: 'Insert a new node before `toNodeId`. `VariantNode` cannot use `insertMode: "before"`; to restore a missing variant path, use `insertMode: "between"` with the experiment branch as `fromNodeId`.'
      properties:
        expectedRevisionId:
          $ref: '#/components/schemas/WorkflowExpectedRevisionId'
        insertMode:
          type: string
          enum:
          - before
        nodeTypeName:
          $ref: '#/components/schemas/CreateWorkflowNodeTypeName'
        toNodeId:
          type: string
          description: The node to insert before. The target must have at least one incoming parent and cannot be a trigger node.
        beforeNodeId:
          type: string
          description: Deprecated. Use `toNodeId` instead.
          deprecated: true
      required:
      - expectedRevisionId
      - insertMode
      - nodeTypeName
      oneOf:
      - properties:
          toNodeId:
            type: string
        required:
        - toNodeId
      - properties:
          beforeNodeId:
            type: string
            deprecated: true
        required:
        - beforeNodeId
      additionalProperties: false
    CreateWorkflowNodeBetweenRequest:
      type: object
      description: Insert a new node between two existing nodes, `fromNodeId` and `toNodeId`. When `fromNodeId` is an `ExperimentBranchNode`, `nodeTypeName` must be `VariantNode`, and `toNodeId` cannot already be a `VariantNode`; use add-branch to add sibling variants. Branch

# --- truncated at 32 KB (75 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/loops/refs/heads/main/openapi/loops-workflow-nodes-api-openapi.yml