openapi: 3.1.0 info: title: Loops OpenAPI Spec Workflows 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: Workflows description: View and mutate workflow graphs paths: /workflows: get: tags: - Workflows summary: List workflows operationId: listWorkflows description: Retrieve a paginated list of workflows. x-mint: href: /api-reference/list-workflows parameters: - name: perPage in: query required: false description: How many results to return in each request. Must be between 10 and 50. Default is 20. schema: type: string - name: cursor in: query required: false description: A cursor to return a specific page of results. Cursors can be found from the `pagination.nextCursor` value in each response. schema: type: string responses: '200': description: Successful. content: application/json: schema: $ref: '#/components/schemas/ListWorkflowsResponse' '400': description: Invalid `perPage` or `cursor` value. content: application/json: schema: $ref: '#/components/schemas/WorkflowFailureResponse' '401': description: Invalid API key. '405': description: Wrong HTTP request method. security: - apiKey: [] post: tags: - Workflows summary: Create a workflow operationId: createWorkflow description: Create a draft workflow with a blank trigger and exit node. x-mint: href: /api-reference/create-workflow requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateWorkflowRequest' responses: '200': description: Workflow created. content: application/json: schema: $ref: '#/components/schemas/SimplifiedWorkflow' '400': description: Invalid request body. content: application/json: schema: $ref: '#/components/schemas/WorkflowFailureResponse' '401': description: Invalid API key. '405': description: Wrong HTTP request method. '500': description: Workflow creation is unavailable for this team. content: application/json: schema: $ref: '#/components/schemas/WorkflowFailureResponse' security: - apiKey: [] /workflows/{workflowId}: parameters: - name: workflowId in: path required: true description: The ID of the workflow. schema: type: string examples: - clw1a3b5c7d9e1f3g5h7i9j1 get: tags: - Workflows summary: Get a workflow operationId: getWorkflow description: Retrieve a workflow graph with node type names, connections, and selected display fields. x-mint: content: Returns a simplified view of the workflow graph. Each node includes its `typeName`, outgoing connections in `nextNodeIds`, and selected display fields. Use [Get a workflow node](/api-reference/get-workflow-node) to retrieve full details for a single node. href: /api-reference/get-workflow responses: '200': description: Successful. content: application/json: schema: $ref: '#/components/schemas/SimplifiedWorkflow' '400': description: Invalid `workflowId`. content: application/json: schema: $ref: '#/components/schemas/WorkflowFailureResponse' '401': description: Invalid API key. '404': description: Workflow not found. content: application/json: schema: $ref: '#/components/schemas/WorkflowFailureResponse' '405': description: Wrong HTTP request method. security: - apiKey: [] post: tags: - Workflows summary: Update a workflow operationId: updateWorkflowProperties description: Update a workflow's display properties. At least one property must be provided. To change the workflow's mailing list, use the `POST /v1/workflows/{workflowId}/mailing-list` endpoint instead. x-mint: href: /api-reference/update-workflow content: To change a workflow's mailing list, use the [Change workflow mailing list](/api-reference/change-workflow-mailing-list) endpoint instead. This is because changing mailing lists may remove queued contacts from the workflow. metadata: description: Update a workflow's display properties. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateWorkflowPropertiesRequest' responses: '200': description: Workflow properties updated. content: application/json: schema: $ref: '#/components/schemas/SimplifiedWorkflow' '400': description: Invalid `workflowId` or request body. content: application/json: schema: $ref: '#/components/schemas/WorkflowFailureResponse' '401': description: Invalid API key. '404': description: Workflow 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}/mailing-list: parameters: - name: workflowId in: path required: true description: The ID of the workflow. schema: type: string post: tags: - Workflows summary: Change workflow mailing list operationId: changeWorkflowMailingList description: 'Dry run or apply a workflow mailing list change. If queued contacts would be removed from the workflow due to the change of mailing list, Loops returns with `"status": "queuedContactsFound"` instead of applying the change. Retry with `queuedContactPolicy: "discard"` to apply the change and discard those contacts. Confirmed update responses include the simplified workflow after the mailing list changes.' x-mint: href: /api-reference/change-workflow-mailing-list content: 'Use this endpoint to change a workflow''s mailing list. Make a dry run request using `dryRun: true`. If queued contacts would be removed from the workflow due to the change of mailing list, Loops returns with `"status": "queuedContactsFound"` instead of applying the change. Retry with `queuedContactPolicy: "discard"` to apply the change and discard those contacts. Confirmed update responses include the simplified workflow after the mailing list changes.' metadata: sidebarTitle: Change mailing list description: Change a workflow's mailing list. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ChangeWorkflowMailingListRequest' responses: '200': description: Mailing-list dry run, queued-contact warning, or update result. Confirmed update responses include the simplified workflow after the mailing list changes. content: application/json: schema: $ref: '#/components/schemas/ChangeWorkflowMailingListResponse' '400': description: Invalid `workflowId`, request body, mailing list, or workflow state. content: application/json: schema: $ref: '#/components/schemas/WorkflowFailureResponse' '401': description: Invalid API key. '404': description: Workflow 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: ChangeWorkflowMailingListRequest: type: object properties: expectedRevisionId: $ref: '#/components/schemas/WorkflowExpectedRevisionId' mailingListId: type: - string - 'null' description: 'The mailing list to use for the workflow. When assigning a mailing list, queued contacts excluded by the new list can return `queuedContactsFound`; retry with `queuedContactPolicy: "discard"` to apply the change and discard those contacts. Use `null` to clear the workflow mailing list; clearing does not discard queued contacts.' dryRun: type: boolean description: If `true`, the request will be validated but the workflow will not be modified. queuedContactPolicy: $ref: '#/components/schemas/WorkflowQueuedContactPolicy' required: - expectedRevisionId - mailingListId additionalProperties: false ChangeWorkflowMailingListResponse: oneOf: - $ref: '#/components/schemas/WorkflowMailingListPreview' - $ref: '#/components/schemas/WorkflowMailingListUpdatedResponse' CreateWorkflowRequest: type: object properties: name: type: string description: The name of the workflow. description: type: string description: The description of the workflow. mailingListId: type: - string - 'null' description: The ID of a mailing list the workflow sends to. After creation, the mailing list can be changed with the `/v1/workflows/{workflowId}/mailing-list` endpoint. required: - name additionalProperties: false ListWorkflowsResponse: type: object properties: pagination: $ref: '#/components/schemas/Pagination' data: type: array items: $ref: '#/components/schemas/WorkflowSummary' required: - pagination - data examples: - pagination: totalResults: 45 returnedResults: 20 perPage: 20 totalPages: 3 nextCursor: clp9k2m4n6p8q0r2s4t6u8v0 nextPage: https://app.loops.so/api/v1/campaign-groups?cursor=clp9k2m4n6p8q0r2s4t6u8v0&perPage=20 data: - id: clw1a3b5c7d9e1f3g5h7i9j1 name: Welcome series createdAt: 2025-06-29 07:47:39.370000+00:00 updatedAt: 2025-06-29 07:47:39.370000+00:00 NullableWorkflowRevisionId: type: - string - 'null' description: The current workflow revision token. Pass the latest value as `expectedRevisionId` on the next workflow mutation. Will be `null` for workflows without a revision token yet. Pagination: type: object properties: totalResults: type: number examples: - 2 returnedResults: type: number examples: - 2 perPage: type: number examples: - 20 totalPages: type: number examples: - 1 nextCursor: type: - string - 'null' examples: - null nextPage: type: - string - 'null' examples: - null required: - totalResults - returnedResults - perPage - totalPages - nextCursor - nextPage examples: - totalResults: 2 returnedResults: 2 perPage: 20 totalPages: 1 nextCursor: null nextPage: null SimplifiedAddToListTriggerWorkflowNode: type: object properties: typeName: type: string enum: - AddToListTrigger nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' mailingListId: type: - string - 'null' description: The ID of the mailing list that triggers the workflow. reEligible: $ref: '#/components/schemas/WorkflowReEligible' required: - typeName - nextNodeIds - mailingListId - reEligible additionalProperties: false SimplifiedAudienceFilterWorkflowNode: type: object properties: typeName: type: string enum: - AudienceFilter nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' required: - typeName - nextNodeIds additionalProperties: false SimplifiedBlankTriggerWorkflowNode: type: object properties: typeName: type: string enum: - BlankTrigger nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' required: - typeName - nextNodeIds additionalProperties: false SimplifiedBranchWorkflowNode: type: object properties: typeName: type: string enum: - BranchNode nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' required: - typeName - nextNodeIds additionalProperties: false SimplifiedContactPropertyTriggerWorkflowNode: type: object properties: typeName: type: string enum: - ContactPropertyTrigger nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' contactPropertyQuery: oneOf: - $ref: '#/components/schemas/WorkflowContactPropertyQuery' - type: 'null' reEligible: $ref: '#/components/schemas/WorkflowReEligible' required: - typeName - nextNodeIds - contactPropertyQuery - reEligible additionalProperties: false SimplifiedEventTriggerWorkflowNode: type: object properties: typeName: type: string enum: - EventTrigger nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' eventName: type: - string - 'null' description: The name of the event that triggers the workflow. reEligible: $ref: '#/components/schemas/WorkflowReEligible' required: - typeName - nextNodeIds - eventName - reEligible additionalProperties: false examples: - typeName: EventTrigger nextNodeIds: - cln1a3b5c7d9e1f3g5h7i9j1 eventName: signup reEligible: false SimplifiedExitActionWorkflowNode: type: object properties: typeName: type: string enum: - ExitAction nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' required: - typeName - nextNodeIds additionalProperties: false SimplifiedExperimentBranchWorkflowNode: type: object properties: typeName: type: string enum: - ExperimentBranchNode nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' samplingRate: type: number description: The percentage of contacts that will be sent to variant branches, between `0` and `100`. The remaining percentage will be sent to the control branch. required: - typeName - nextNodeIds - samplingRate additionalProperties: false SimplifiedSendEmailActionWorkflowNode: type: object properties: typeName: type: string enum: - SendEmailAction nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' emailMessageId: type: - string - 'null' description: The ID of the email message to send. To edit this email, use the `POST /v1/email-messages/{emailMessageId}` endpoint. subject: type: string description: The subject of the email message (reference only). required: - typeName - nextNodeIds - emailMessageId - subject additionalProperties: false examples: - typeName: SendEmailAction nextNodeIds: [] emailMessageId: cle5f7g9h1i3j5k7l9m1n3p5 subject: Welcome to Acme! SimplifiedSignupTriggerWorkflowNode: type: object properties: typeName: type: string enum: - SignupTrigger nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' required: - typeName - nextNodeIds additionalProperties: false SimplifiedTimerActionWorkflowNode: type: object properties: typeName: type: string enum: - TimerAction nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' amount: $ref: '#/components/schemas/WorkflowTimerAmount' unit: $ref: '#/components/schemas/WorkflowTimerUnit' required: - typeName - nextNodeIds - amount - unit additionalProperties: false examples: - typeName: TimerAction nextNodeIds: - cln1a3b5c7d9e1f3g5h7i9j1 amount: 2 unit: d SimplifiedVariantWorkflowNode: type: object properties: typeName: type: string enum: - VariantNode nextNodeIds: $ref: '#/components/schemas/WorkflowNextNodeIds' isControl: type: boolean description: Whether this is the control variant of an experiment. required: - typeName - nextNodeIds - isControl additionalProperties: false SimplifiedWorkflow: type: object properties: id: type: string description: The ID of the workflow. workflowRevisionId: $ref: '#/components/schemas/NullableWorkflowRevisionId' status: type: string enum: - Draft - Sending - Paused - PausedAndQueueing name: type: string description: The name of the workflow. description: type: string description: The description of the workflow. mailingListId: type: - string - 'null' description: The ID of the mailing list the workflow sends to. rootNodeId: type: string description: The ID of the root node in the workflow graph. nodes: type: object description: A map of node IDs to simplified node objects. Each node includes `typeName` and `nextNodeIds`, plus type-specific fields when present. To get the full node object, use the `GET /v1/workflows/{workflowId}/nodes/{nodeId}` endpoint. additionalProperties: $ref: '#/components/schemas/SimplifiedWorkflowNode' example: cf16k73gq014h3mmj5b6jdi9r: typeName: SignupTrigger nextNodeIds: - cf16k73gq014h3mmj5b4jdifg - cf16k73gq014h3mmj5b4jdifh required: - id - workflowRevisionId - status - mailingListId - rootNodeId - nodes examples: - id: clw1a3b5c7d9e1f3g5h7i9j1 status: Draft name: Welcome series description: Onboarding emails for new signups mailingListId: clm2k8j4h6g0f8d6s4a2b0z8 rootNodeId: cln8p0q2r4s6t8u0v2w4x6z8 nodes: cln8p0q2r4s6t8u0v2w4x6z8: typeName: SignupTrigger nextNodeIds: - cln1a3b5c7d9e1f3g5h7i9j1 cln1a3b5c7d9e1f3g5h7i9j1: typeName: SendEmailAction nextNodeIds: [] emailMessageId: cle5f7g9h1i3j5k7l9m1n3p5 subject: Welcome to Acme! SimplifiedWorkflowNode: oneOf: - $ref: '#/components/schemas/SimplifiedSignupTriggerWorkflowNode' - $ref: '#/components/schemas/SimplifiedEventTriggerWorkflowNode' - $ref: '#/components/schemas/SimplifiedContactPropertyTriggerWorkflowNode' - $ref: '#/components/schemas/SimplifiedAddToListTriggerWorkflowNode' - $ref: '#/components/schemas/SimplifiedBlankTriggerWorkflowNode' - $ref: '#/components/schemas/SimplifiedAudienceFilterWorkflowNode' - $ref: '#/components/schemas/SimplifiedTimerActionWorkflowNode' - $ref: '#/components/schemas/SimplifiedSendEmailActionWorkflowNode' - $ref: '#/components/schemas/SimplifiedExitActionWorkflowNode' - $ref: '#/components/schemas/SimplifiedBranchWorkflowNode' - $ref: '#/components/schemas/SimplifiedExperimentBranchWorkflowNode' - $ref: '#/components/schemas/SimplifiedVariantWorkflowNode' discriminator: propertyName: typeName UpdateWorkflowPropertiesRequest: type: object description: At least one property must be provided. properties: expectedRevisionId: $ref: '#/components/schemas/WorkflowExpectedRevisionId' name: type: string description: The updated workflow name. description: type: string description: The updated workflow description. required: - expectedRevisionId anyOf: - required: - name - required: - description additionalProperties: false WorkflowContactPropertyComparison: type: object description: For Contact Updated triggers, the API validates `operator` against the selected contact property's type and the side of the comparison. The `was` comparison can use any operator supported by the selected property type. The `is` comparison uses the same operators, except number and boolean properties cannot use `empty`. String properties support `any`, `equal`, `not_equal`, `contains`, `not_contains`, `empty`, and `not_empty`. Number properties support `any`, `greater_than`, `less_than`, `numeric_equal`, `numeric_not_equal`, `empty`, and `not_empty`. Boolean properties support `any`, `true`, `false`, `empty`, and `not_empty`. Date properties support `any`, `empty`, `not_empty`, `after`, `before`, and `between`. properties: value: oneOf: - type: string - type: number - type: boolean operator: type: string description: The comparison operator. It must be valid for the selected contact property's type and for the `is` or `was` side of the comparison. Number and boolean properties allow `empty` on `was`, but not on `is`. enum: - any - contains - not_contains - empty - not_empty - equal - not_equal - greater_than - less_than - 'true' - 'false' - numeric_equal - numeric_not_equal - after - before - between required: - value - operator WorkflowContactPropertyQuery: type: object description: Define the contact property change that triggers the workflow. In update requests, `key` must resolve to an existing contact property that is available for Contact Updated triggers. Hidden or unsupported fields, such as `createdAt`, `notes`, and computed contact properties, are rejected. properties: key: type: string description: The camel-cased `key` of the contact property to query. The property must exist for the team and must be available for Contact Updated triggers. examples: - firstName - email - planName is: description: Comparison for the new contact property value after the update. $ref: '#/components/schemas/WorkflowContactPropertyComparison' was: description: Comparison for the previous contact property value before the update. $ref: '#/components/schemas/WorkflowContactPropertyComparison' required: - key - is - was WorkflowExpectedRevisionId: type: - string - 'null' description: The workflow revision token returned by the latest workflow read or mutation. Older workflows may return `null` before their first revision-aware mutation; pass `null` back as `expectedRevisionId` in that case. If the token is stale, the API returns a `409 Conflict` error. WorkflowFailureResponse: type: object properties: message: type: string required: - message examples: - message: Workflow not found. WorkflowMailingListPreview: type: object properties: status: type: string enum: - dryRun - queuedContactsFound mailingListId: type: - string - 'null' queuedContactCount: type: number description: The number of queued contacts that would be removed from the workflow due to the mailing list changing. required: - status - mailingListId - queuedContactCount WorkflowMailingListUpdatedResponse: type: object properties: status: type: string enum: - updated mailingListId: type: - string - 'null' workflowRevisionId: $ref: '#/components/schemas/WorkflowRevisionId' queuedContactCount: type: number description: The number of queued contacts that were removed from the workflow due to the mailing list changing. workflow: $ref: '#/components/schemas/SimplifiedWorkflow' required: - status - mailingListId - workflowRevisionId - queuedContactCount - workflow WorkflowNextNodeIds: type: array items: type: string description: The IDs of the nodes that are downstream of this node. WorkflowQueuedContactPolicy: type: string enum: - fail - discard default: fail description: '`fail` returns queued-contact impact instead of mutating. `discard` confirms that matching queued contacts should be discarded. Defaults to `fail` when omitted.' WorkflowReEligible: type: boolean description: If `true`, the contacts will be able to enter this workflow every time the trigger is matched. If `false`, contacts will only ever enter this workflow once. Matches the "Trigger frequency" option in the UI. WorkflowRevisionId: type: - string description: The current workflow revision token. Pass the latest value as `expectedRevisionId` on the next workflow mutation. WorkflowSummary: type: object properties: id: type: string description: The ID of the workflow. examples: - clw1a3b5c7d9e1f3g5h7i9j1 name: type: string description: The name of the workflow. examples: - Welcome series createdAt: type: string format: date-time examples: - 2025-06-29 07:47:39.370000+00:00 description: ISO 8601 timestamp for when the workflow was created. updatedAt: type: string format: date-time examples: - 2025-06-29 07:47:39.370000+00:00 description: ISO 8601 timestamp for when the workflow was last updated. required: - id - name - createdAt - updatedAt examples: - id: clw1a3b5c7d9e1f3g5h7i9j1 name: Welcome series createdAt: 2025-06-29 07:47:39.370000+00:00 updatedAt: 2025-06-29 07:47:39.370000+00:00 WorkflowTimerAmount: type: number description: The amount of time to wait before triggering the next node. Set to `0` to move to the next node immediately. WorkflowTimerUnit: type: string enum: - m - h - d description: The unit of time for the timer action node. m = minutes, h = hours, d = days. securitySchemes: apiKey: type: http scheme: bearer