openapi: 3.0.0
info:
    version: '0.0'
    title: 'Qomon Workflows API'
    description: "This is Qomon's Workflows API definition.\n\nTo get an authorization go to [Qomon's setting page](https://qomon.app/settings/extensions/connect) and create an API key."
servers:
    -
        description: 'Qomon production'
        url: 'https://qomon.app/api'
    -
        description: 'Qomon integration'
        url: 'https://test.quorumapps.com/api'
    -
        description: 'Qomon local'
        url: 'http://localhost:8080'
security:
    -
        bearerAuth: []
tags:
    -
        name: Workflows
        description: 'Workflow management operations'
    -
        name: 'Workflow Runs'
        description: 'Workflow run tracking and analytics'
paths:
    /workflows:
        get:
            tags: [Workflows]
            summary: 'List all workflows'
            description: "Retrieve all workflows for the group (no pagination). Returns workflow information with:\n- Message summary (name, locale, category, image_url) but WITHOUT content_html/content_json\n- Last run information (last_run, last_run_id, last_run_status)\n\nUse GET /workflows/{id} to retrieve full workflow details with complete message content.\n"
            operationId: listWorkflows
            responses: {'200': {description: 'List of all workflows', content: {application/json: {schema: {type: array, items: {type: object, description: 'Workflow summary without message content (used in list responses)', properties: {id: {type: integer, format: int64, description: 'Workflow ID'}, name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action', example: group_id}, action_value: {type: string, description: 'Value for the action', example: '1352'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, group_id_trigger: {type: integer, description: 'Group ID that owns this workflow'}, user_id: {type: integer, format: int64, description: 'ID of the user who created this workflow', nullable: true}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts'}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert'}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, workflow_email_template: {type: array, items: {$ref: '#/components/schemas/WorkflowEmailTemplateSummary'}}, workflow_sms_template: {type: array, items: {$ref: '#/components/schemas/WorkflowSmsTemplate'}, description: 'SMS template(s) — present when action_to_activate is ''SendSms'''}, created_at: {type: string, format: date-time, description: 'Creation timestamp'}, updated_at: {type: string, format: date-time, description: 'Last update timestamp'}, created_by: {type: integer, format: int64, description: 'User ID of the user who created the workflow'}, updated_by: {type: integer, format: int64, description: 'User ID of the user who updated the workflow'}, mode: {type: string, enum: [exclusive, multiple], default: multiple, description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, last_run: {type: string, format: date-time, nullable: true, description: 'Timestamp of the last execution of this workflow'}, last_run_id: {type: string, format: uuid, nullable: true, description: 'ID of the last run that included this workflow'}, last_run_status: {type: string, enum: [pending, running, completed, failed], nullable: true, description: 'Status of the last run that included this workflow'}}}}}}}, '400': {description: 'Bad request', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '500': {description: 'Internal server error', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}}
        post:
            tags: [Workflows]
            summary: 'Create a new workflow'
            description: "Create a new workflow. Supported action types:\n\n**SendEmail** — provide `workflow_email_template[0]` with either:\n1. `email_beefree_template_id` — a new template with category=`workflow_message` is created by duplicating the source\n2. `message` with `content_html`, `content_json`, and `name` — a new template is created from the provided content\n\n**SendSms** — provide `workflow_sms_template[0]` with a `message` (required). Optionally set\n`consent_data_ids` to enforce per-contact consent checking against the contact's form data, and\n`file_ids` for MMS attachments. `url_for_consent` is auto-populated from the request origin.\n"
            operationId: createWorkflow
            requestBody: {required: true, content: {application/json: {schema: {type: object, required: [trigger_field, trigger_operator, trigger_value, name, action_to_activate], properties: {name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action'}, action_value: {type: string, description: 'Value for the action'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts', default: false}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert', default: false}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, mode: {type: string, enum: [exclusive, multiple], default: multiple, description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, workflow_email_template: {type: array, description: 'Required when action_to_activate is ''SendEmail''', items: {$ref: '#/components/schemas/CreateWorkflowEmailTemplate'}}, workflow_sms_template: {type: array, description: 'Required when action_to_activate is ''SendSms''. Exactly one entry expected.', items: {$ref: '#/components/schemas/CreateWorkflowSmsTemplate'}}}}}}}
            responses: {'200': {description: 'Workflow created successfully', content: {application/json: {schema: {type: object, description: 'Full workflow details with complete message content (used in GET by ID response)', properties: {id: {type: integer, format: int64, description: 'Workflow ID'}, name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action', example: group_id}, action_value: {type: string, description: 'Value for the action', example: '1352'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, group_id_trigger: {type: integer, description: 'Group ID that owns this workflow'}, user_id: {type: integer, format: int64, description: 'ID of the user who created this workflow', nullable: true}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts'}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert'}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, workflow_email_template: {type: array, items: {$ref: '#/components/schemas/WorkflowEmailTemplate'}}, workflow_sms_template: {type: array, items: {$ref: '#/components/schemas/WorkflowSmsTemplate'}, description: 'SMS template(s) — present when action_to_activate is ''SendSms'''}, created_at: {type: string, format: date-time, description: 'Creation timestamp'}, updated_at: {type: string, format: date-time, description: 'Last update timestamp'}, created_by: {type: integer, format: int64, description: 'User ID of the user who created the workflow'}, updated_by: {type: integer, format: int64, description: 'User ID of the user who updated the workflow'}, mode: {type: string, enum: [exclusive, multiple], default: multiple, description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, last_run: {type: string, format: date-time, nullable: true, description: 'Timestamp of the last execution of this workflow'}, last_run_id: {type: string, format: uuid, nullable: true, description: 'ID of the last run that included this workflow'}, last_run_status: {type: string, enum: [pending, running, completed, failed], nullable: true, description: 'Status of the last run that included this workflow'}}}}}}, '400': {description: 'Bad request', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {missingWorkflowData: {value: {status: error, message: missing_workflow_data}}, missingUserId: {value: {status: error, message: missing_user_id}}, missingSourceTemplateIdOrMessageContent: {value: {status: error, message: missing_source_template_id_or_message_content}}}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '403': {description: 'Source template not found or not accessible', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {sourceTemplateNotFound: {value: {status: error, message: source_template_not_found_or_not_accessible}}}}}}, '406': {description: 'Validation error', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {missingWorkflowEmailTemplate: {value: {status: error, message: missing_workflow_email_template}}, missingMessageContent: {value: {status: error, message: missing_message_content}}, missingWorkflowName: {value: {status: error, message: missing_workflow_name}}, workflowNameTooLong: {value: {status: error, message: workflow_name_too_long}}, missingWorkflowSmsTemplate: {value: {status: error, message: missing_workflow_sms_template}}, missingSmsMessage: {value: {status: error, message: missing_sms_message}}}}}}, '500': {description: 'Internal server error', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {failedToDuplicateTemplate: {value: {status: error, message: failed_to_duplicate_template}}, failedToUpdateTemplateCategory: {value: {status: error, message: failed_to_update_template_category}}, failedToCreateWorkflow: {value: {status: error, message: failed_to_create_workflow}}, failedToCreateTemplate: {value: {status: error, message: failed_to_create_template}}, failedToUpdateTemplateName: {value: {status: error, message: failed_to_update_template_name}}, failedToCommitTransaction: {value: {status: error, message: failed_to_commit_transaction}}, duplicatedTemplateIsNil: {value: {status: error, message: duplicated_template_is_nil}}, createdTemplateIsNil: {value: {status: error, message: created_template_is_nil}}}}}}}
    /workflows/search:
        post:
            tags: [Workflows]
            summary: 'Search workflows with pagination'
            description: "Search workflows with optional user filtering and pagination. Returns workflow information with:\n- Message summary (name, locale, category, image_url) but WITHOUT content_html/content_json\n- Last run information (last_run, last_run_id, last_run_status)\n\nUse GET /workflows/{id} to retrieve full workflow details with complete message content.\n"
            operationId: searchWorkflows
            requestBody: {required: true, content: {application/json: {schema: {type: object, properties: {user_id: {type: integer, format: int64, description: 'Filter workflows by user ID (optional)', nullable: true}, page: {type: integer, description: 'Page number, default -> 1', minimum: 1, default: 1, example: 1}, per_page: {type: integer, description: 'Items per page, default -> 20, max -> 100', minimum: 1, maximum: 100, default: 20, example: 20}}}}}}
            responses: {'200': {description: 'Paginated search results', content: {application/json: {schema: {type: object, properties: {workflows: {type: array, items: {$ref: '#/components/schemas/WorkflowSummary'}}, page: {type: integer, description: 'Current page number'}, per_page: {type: integer, description: 'Items per page'}, total: {type: integer, description: 'Total number of workflows'}, total_pages: {type: integer, description: 'Total number of pages'}}}}}}, '400': {description: 'Bad request', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '406': {description: 'Invalid per_page parameter'}, '500': {description: 'Internal server error', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}}
    '/workflows/{id}':
        get:
            tags: [Workflows]
            summary: 'Get workflow by ID'
            description: "Retrieve a specific workflow by its ID with full details including:\n- Complete message content (HTML and JSON) for SendEmail workflows\n- SMS template with message, consent_data_ids, and files for SendSms workflows\n- Last run information (last_run, last_run_id, last_run_status)\n\nIf the template is a global binding (not from the current group), the message.id will be 0 to hide the template ID.\n"
            operationId: getWorkflow
            parameters: [{name: id, in: path, required: true, description: 'Workflow ID', schema: {type: integer, format: int64}}]
            responses: {'200': {description: 'Workflow details', content: {application/json: {schema: {type: object, description: 'Full workflow details with complete message content (used in GET by ID response)', properties: {id: {type: integer, format: int64, description: 'Workflow ID'}, name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action', example: group_id}, action_value: {type: string, description: 'Value for the action', example: '1352'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, group_id_trigger: {type: integer, description: 'Group ID that owns this workflow'}, user_id: {type: integer, format: int64, description: 'ID of the user who created this workflow', nullable: true}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts'}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert'}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, workflow_email_template: {type: array, items: {$ref: '#/components/schemas/WorkflowEmailTemplate'}}, workflow_sms_template: {type: array, items: {$ref: '#/components/schemas/WorkflowSmsTemplate'}, description: 'SMS template(s) — present when action_to_activate is ''SendSms'''}, created_at: {type: string, format: date-time, description: 'Creation timestamp'}, updated_at: {type: string, format: date-time, description: 'Last update timestamp'}, created_by: {type: integer, format: int64, description: 'User ID of the user who created the workflow'}, updated_by: {type: integer, format: int64, description: 'User ID of the user who updated the workflow'}, mode: {type: string, enum: [exclusive, multiple], default: multiple, description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, last_run: {type: string, format: date-time, nullable: true, description: 'Timestamp of the last execution of this workflow'}, last_run_id: {type: string, format: uuid, nullable: true, description: 'ID of the last run that included this workflow'}, last_run_status: {type: string, enum: [pending, running, completed, failed], nullable: true, description: 'Status of the last run that included this workflow'}}}}}}, '400': {description: 'Bad request', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '404': {description: 'Workflow not found', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {workflowNotFound: {value: {status: error, message: workflow_not_found}}}}}}, '500': {description: 'Internal server error', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {failedToRetrieveWorkflow: {value: {status: error, message: failed_to_retrieve_workflow}}, failedToEnrichWorkflowWithMessage: {value: {status: error, message: failed_to_enrich_workflow_with_message}}}}}}}
        patch:
            tags: [Workflows]
            summary: 'Update workflow'
            description: "Update an existing workflow.\n\n**SendEmail** — update the message by providing `workflow_email_template[0]` with either:\n1. `message` with `content_html` and `content_json` — a new `workflow_message` template is created; the old one is soft-deleted (unless bound)\n2. `email_beefree_template_id` — the specified template is used (duplicated if not already a `workflow_message`)\n\nIf neither is provided, only workflow metadata is updated.\n\n**SendSms** — update the SMS template by providing `workflow_sms_template[0]` with a `message`.\n`consent_data_ids` and MMS `file_ids` can also be updated.\n"
            operationId: updateWorkflow
            parameters: [{name: id, in: path, required: true, description: 'Workflow ID', schema: {type: integer, format: int64}}]
            requestBody: {required: true, content: {application/json: {schema: {type: object, required: [trigger_field, trigger_operator, action_to_activate], properties: {name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action'}, action_value: {type: string, description: 'Value for the action'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts'}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert'}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, mode: {type: string, enum: [exclusive, multiple], description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, workflow_email_template: {type: array, description: 'Required when action_to_activate is ''SendEmail''', items: {$ref: '#/components/schemas/UpdateWorkflowEmailTemplate'}}, workflow_sms_template: {type: array, description: 'Required when action_to_activate is ''SendSms''. Exactly one entry expected.', items: {$ref: '#/components/schemas/UpdateWorkflowSmsTemplate'}}}}}}}
            responses: {'200': {description: 'Workflow updated successfully', content: {application/json: {schema: {type: object, description: 'Full workflow details with complete message content (used in GET by ID response)', properties: {id: {type: integer, format: int64, description: 'Workflow ID'}, name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action', example: group_id}, action_value: {type: string, description: 'Value for the action', example: '1352'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, group_id_trigger: {type: integer, description: 'Group ID that owns this workflow'}, user_id: {type: integer, format: int64, description: 'ID of the user who created this workflow', nullable: true}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts'}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert'}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, workflow_email_template: {type: array, items: {$ref: '#/components/schemas/WorkflowEmailTemplate'}}, workflow_sms_template: {type: array, items: {$ref: '#/components/schemas/WorkflowSmsTemplate'}, description: 'SMS template(s) — present when action_to_activate is ''SendSms'''}, created_at: {type: string, format: date-time, description: 'Creation timestamp'}, updated_at: {type: string, format: date-time, description: 'Last update timestamp'}, created_by: {type: integer, format: int64, description: 'User ID of the user who created the workflow'}, updated_by: {type: integer, format: int64, description: 'User ID of the user who updated the workflow'}, mode: {type: string, enum: [exclusive, multiple], default: multiple, description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, last_run: {type: string, format: date-time, nullable: true, description: 'Timestamp of the last execution of this workflow'}, last_run_id: {type: string, format: uuid, nullable: true, description: 'ID of the last run that included this workflow'}, last_run_status: {type: string, enum: [pending, running, completed, failed], nullable: true, description: 'Status of the last run that included this workflow'}}}}}}, '400': {description: 'Bad request', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {missingWorkflowData: {value: {status: error, message: missing_workflow_data}}}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '404': {description: 'Workflow not found', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {workflowNotFound: {value: {status: error, message: workflow_not_found}}, failedToRetrieveWorkflow: {value: {status: error, message: failed_to_retrieve_workflow}}}}}}, '406': {description: 'Validation error', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {missingWorkflowId: {value: {status: error, message: missing_workflow_id}}, missingWorkflowName: {value: {status: error, message: missing_workflow_name}}, workflowNameTooLong: {value: {status: error, message: workflow_name_too_long}}, missingWorkflowSmsTemplate: {value: {status: error, message: missing_workflow_sms_template}}, missingSmsMessage: {value: {status: error, message: missing_sms_message}}}}}}, '500': {description: 'Internal server error', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {failedToGetOldTemplateIds: {value: {status: error, message: failed_to_get_old_template_ids}}, failedToCreateTemplate: {value: {status: error, message: failed_to_create_template}}, createdTemplateIsNil: {value: {status: error, message: created_template_is_nil}}, missingMessageContent: {value: {status: error, message: missing_message_content}}, failedToGetTemplate: {value: {status: error, message: failed_to_get_template}}, failedToDuplicateTemplate: {value: {status: error, message: failed_to_duplicate_template}}, failedToUpdateTemplateCategory: {value: {status: error, message: failed_to_update_template_category}}, failedToUpdateWorkflow: {value: {status: error, message: failed_to_update_workflow}}, failedToCommitTransaction: {value: {status: error, message: failed_to_commit_transaction}}}}}}}
        delete:
            tags: [Workflows]
            summary: 'Delete workflow'
            description: "Delete a workflow by its ID. The associated message template will also be deleted (soft delete) \nunless it is a bound template (globally or locally bound). Bound templates are never deleted.\n"
            operationId: deleteWorkflow
            parameters: [{name: id, in: path, required: true, description: 'Workflow ID', schema: {type: integer, format: int64}}]
            responses: {'200': {description: 'Workflow deleted successfully', content: {application/json: {schema: {type: object, properties: {message: {type: string, example: 'Workflow deleted successfully'}}}}}}, '400': {description: 'Bad request', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {missingWorkflowId: {value: {status: error, message: missing_workflow_id}}}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '404': {description: 'Workflow not found', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {workflowNotFound: {value: {status: error, message: workflow_not_found}}, failedToFetchWorkflow: {value: {status: error, message: failed_to_fetch_workflow}}}}}}, '500': {description: 'Internal server error', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {failedToDeleteWorkflow: {value: {status: error, message: failed_to_delete_workflow}}}}}}}
    '/workflows/{id}/runs':
        get:
            tags: ['Workflow Runs']
            summary: 'Get runs for a specific workflow'
            description: "Retrieve paginated runs that include steps for a specific workflow. Returns runs with \nonly the steps that belong to the specified workflow.\n"
            operationId: getWorkflowRuns
            parameters: [{name: id, in: path, required: true, description: 'Workflow ID', schema: {type: integer, format: int64}}, {name: page, in: query, description: 'Page number (default 1)', schema: {type: integer, minimum: 1, default: 1}}, {name: per_page, in: query, description: 'Items per page (default 20, max 100)', schema: {type: integer, minimum: 1, maximum: 100, default: 20}}]
            responses: {'200': {description: 'Paginated list of workflow runs', content: {application/json: {schema: {type: object, properties: {runs: {type: array, items: {$ref: '#/components/schemas/WorkflowRun'}}, page: {type: integer, description: 'Current page number'}, per_page: {type: integer, description: 'Items per page'}, total: {type: integer, description: 'Total number of runs'}, total_pages: {type: integer, description: 'Total number of pages'}}}}}}, '400': {description: 'Bad request', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '500': {description: 'Internal server error', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}}
    /workflow-runs/search:
        post:
            tags: ['Workflow Runs']
            summary: 'Search workflow runs with filters'
            description: "Search all workflow runs with advanced filtering options. Supports filtering by workflow, \nstatus, source, and date range. Returns runs without steps for list view (use GET /workflow-runs/{id} \nto get full details with steps).\n"
            operationId: searchWorkflowRuns
            requestBody: {required: true, content: {application/json: {schema: {type: object, properties: {workflow_id: {type: integer, description: 'Filter by specific workflow ID (optional)', nullable: true}, status: {type: string, enum: [pending, running, completed, failed], description: 'Filter by run status (optional)', nullable: true}, source: {type: string, description: 'Filter by source (e.g., "upsert.form", "upsert.import")', nullable: true}, from_date: {type: string, format: date-time, description: 'Filter runs created after this date (optional)', nullable: true}, to_date: {type: string, format: date-time, description: 'Filter runs created before this date (optional)', nullable: true}, page: {type: integer, description: 'Page number (default 1)', minimum: 1, default: 1}, per_page: {type: integer, description: 'Items per page (default 20, max 100)', minimum: 1, maximum: 100, default: 20}}}}}}
            responses: {'200': {description: 'Paginated search results', content: {application/json: {schema: {type: object, properties: {runs: {type: array, items: {$ref: '#/components/schemas/WorkflowRun'}}, page: {type: integer, description: 'Current page number'}, per_page: {type: integer, description: 'Items per page'}, total: {type: integer, description: 'Total number of runs'}, total_pages: {type: integer, description: 'Total number of pages'}}}}}}, '400': {description: 'Bad request', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '406': {description: 'Invalid per_page parameter'}, '500': {description: 'Internal server error', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}}
    '/workflow-runs/{id}':
        get:
            tags: ['Workflow Runs']
            summary: 'Get a specific run with all steps'
            description: "Retrieve a specific workflow run by its ID with all execution steps. Steps are ordered \nby phase (pre_upsert, post_upsert) and then by execution order.\n"
            operationId: getWorkflowRun
            parameters: [{name: id, in: path, required: true, description: 'Run ID (UUID)', schema: {type: string, format: uuid}}]
            responses: {'200': {description: 'Run details with all steps', content: {application/json: {schema: {type: object, description: 'A single execution run triggered by a message (maps to DAG Run concept)', properties: {id: {type: string, format: uuid, description: 'Unique run identifier'}, created_at: {type: string, format: date-time, description: 'When the run was created'}, updated_at: {type: string, format: date-time, description: 'When the run was last updated'}, group_id: {type: integer, description: 'Group ID that owns this run'}, status: {type: string, enum: [pending, running, completed, failed], description: 'Current status of the run'}, source: {type: string, description: 'Source that triggered this run', example: upsert.form}, contact_ids: {type: string, description: 'JSON array of contact IDs processed in this run'}, input_hash: {type: string, description: 'Hash of input payload for deduplication'}, input_payload: {type: object, nullable: true, description: 'Full input payload for replay/debugging (JSONB)'}, started_at: {type: string, format: date-time, nullable: true, description: 'When the run started executing'}, completed_at: {type: string, format: date-time, nullable: true, description: 'When the run completed'}, duration_ms: {type: integer, format: int64, nullable: true, description: 'Execution duration in milliseconds'}, total_workflows: {type: integer, description: 'Total number of workflows evaluated in this run'}, triggered_count: {type: integer, description: 'Number of workflows that were triggered'}, skipped_count: {type: integer, description: 'Number of workflows that were skipped'}, failed_count: {type: integer, description: 'Number of workflows that failed'}, error_message: {type: string, description: 'Error message if the run failed'}, metadata: {type: object, nullable: true, description: 'Additional metadata for DAG engine (extensible)'}, steps: {type: array, items: {$ref: '#/components/schemas/WorkflowRunStep'}, description: 'All execution steps in this run'}}}}}}, '400': {description: 'Invalid UUID format', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}}}}, '401': {description: Unauthorized, content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}, '404': {description: 'Run not found', content: {application/json: {schema: {type: object, properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}}, examples: {runNotFound: {value: {status: error, message: run_not_found}}}}}}, '500': {description: 'Internal server error', content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}}}
components:
    schemas:
        WorkflowSummary:
            type: object
            description: 'Workflow summary without message content (used in list responses)'
            properties: {id: {type: integer, format: int64, description: 'Workflow ID'}, name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action', example: group_id}, action_value: {type: string, description: 'Value for the action', example: '1352'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, group_id_trigger: {type: integer, description: 'Group ID that owns this workflow'}, user_id: {type: integer, format: int64, description: 'ID of the user who created this workflow', nullable: true}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts'}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert'}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, workflow_email_template: {type: array, items: {$ref: '#/components/schemas/WorkflowEmailTemplateSummary'}}, workflow_sms_template: {type: array, items: {$ref: '#/components/schemas/WorkflowSmsTemplate'}, description: 'SMS template(s) — present when action_to_activate is ''SendSms'''}, created_at: {type: string, format: date-time, description: 'Creation timestamp'}, updated_at: {type: string, format: date-time, description: 'Last update timestamp'}, created_by: {type: integer, format: int64, description: 'User ID of the user who created the workflow'}, updated_by: {type: integer, format: int64, description: 'User ID of the user who updated the workflow'}, mode: {type: string, enum: [exclusive, multiple], default: multiple, description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, last_run: {type: string, format: date-time, nullable: true, description: 'Timestamp of the last execution of this workflow'}, last_run_id: {type: string, format: uuid, nullable: true, description: 'ID of the last run that included this workflow'}, last_run_status: {type: string, enum: [pending, running, completed, failed], nullable: true, description: 'Status of the last run that included this workflow'}}
        Workflow:
            type: object
            description: 'Full workflow details with complete message content (used in GET by ID response)'
            properties: {id: {type: integer, format: int64, description: 'Workflow ID'}, name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action', example: group_id}, action_value: {type: string, description: 'Value for the action', example: '1352'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, group_id_trigger: {type: integer, description: 'Group ID that owns this workflow'}, user_id: {type: integer, format: int64, description: 'ID of the user who created this workflow', nullable: true}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts'}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert'}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, workflow_email_template: {type: array, items: {$ref: '#/components/schemas/WorkflowEmailTemplate'}}, workflow_sms_template: {type: array, items: {$ref: '#/components/schemas/WorkflowSmsTemplate'}, description: 'SMS template(s) — present when action_to_activate is ''SendSms'''}, created_at: {type: string, format: date-time, description: 'Creation timestamp'}, updated_at: {type: string, format: date-time, description: 'Last update timestamp'}, created_by: {type: integer, format: int64, description: 'User ID of the user who created the workflow'}, updated_by: {type: integer, format: int64, description: 'User ID of the user who updated the workflow'}, mode: {type: string, enum: [exclusive, multiple], default: multiple, description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, last_run: {type: string, format: date-time, nullable: true, description: 'Timestamp of the last execution of this workflow'}, last_run_id: {type: string, format: uuid, nullable: true, description: 'ID of the last run that included this workflow'}, last_run_status: {type: string, enum: [pending, running, completed, failed], nullable: true, description: 'Status of the last run that included this workflow'}}
        WorkflowEmailTemplate:
            type: object
            properties: {id: {type: integer, format: int64, description: 'WorkflowEmailTemplate ID'}, email_beefree_template_id: {type: integer, description: "Template ID (hidden/0 in responses when message is present). \nUsed internally to link the workflow to its message template.\n"}, sender: {type: string, description: 'Email sender address', example: noreply@example.com}, sender_name: {type: string, description: 'Email sender name', example: 'Qomon Team'}, subject: {type: string, description: 'Email subject', example: 'Welcome to our campaign!'}, object: {type: string, description: 'Email object/title'}, workflow_id: {type: integer, description: 'Associated workflow ID'}, group_id_trigger: {type: integer, description: 'Group ID'}, created_at: {type: string, format: date-time, description: 'Creation timestamp'}, updated_at: {type: string, format: date-time, description: 'Last update timestamp'}, message: {type: object, nullable: true, description: "Message template content (only present in GET by ID response). Contains full template \ncontent. If the template is a global binding (not from current group), the id will be 0.\n", properties: {id: {type: integer, format: int64, description: "Template ID. Will be 0 if template is a global binding (not from current group).\n", nullable: true}, name: {type: string, description: 'Template name'}, content_json: {type: string, description: 'Template content in JSON format', nullable: true}, content_html: {type: string, description: 'Template content in HTML format', nullable: true}, locale: {type: string, description: 'Template locale'}, category: {type: string, description: 'Template category', enum: [email, campaign, transac, workflow, workflow_message]}, image_url: {type: string, description: 'Template image URL', nullable: true}, group_id: {type: integer, description: 'Group ID of the template'}}}}
        WorkflowEmailTemplateSummary:
            type: object
            description: 'Email template summary without content_html/content_json (used in list responses)'
            properties: {id: {type: integer, format: int64, description: 'WorkflowEmailTemplate ID'}, email_beefree_template_id: {type: integer, description: "Template ID (hidden/0 in responses when message is present). \nUsed internally to link the workflow to its message template.\n"}, sender: {type: string, description: 'Email sender address', example: noreply@example.com}, sender_name: {type: string, description: 'Email sender name', example: 'Qomon Team'}, subject: {type: string, description: 'Email subject', example: 'Welcome to our campaign!'}, object: {type: string, description: 'Email object/title'}, workflow_id: {type: integer, description: 'Associated workflow ID'}, group_id_trigger: {type: integer, description: 'Group ID'}, created_at: {type: string, format: date-time, description: 'Creation timestamp'}, updated_at: {type: string, format: date-time, description: 'Last update timestamp'}, message: {type: object, nullable: true, description: "Message template summary (WITHOUT content_html/content_json). \nIf the template is a global binding (not from current group), the id will be 0.\n", properties: {id: {type: integer, format: int64, description: "Template ID. Will be 0 if template is a global binding (not from current group).\n", nullable: true}, name: {type: string, description: 'Template name'}, locale: {type: string, description: 'Template locale'}, category: {type: string, description: 'Template category', enum: [email, campaign, transac, workflow, workflow_message]}, image_url: {type: string, description: 'Template image URL', nullable: true}, group_id: {type: integer, description: 'Group ID of the template'}}}}
        WorkflowSmsTemplate:
            type: object
            description: 'SMS template attached to a SendSms workflow'
            properties: {id: {type: integer, format: int64, description: 'WorkflowSmsTemplate ID'}, workflow_id: {type: integer, description: 'Associated workflow ID'}, group_id_trigger: {type: integer, description: 'Group ID'}, message: {type: string, description: 'Plain-text SMS message body', example: 'Hi {{firstname}}, thanks for joining our campaign!'}, consent_data_ids: {type: array, items: {type: integer}, description: "IDs of consent-data entries that the contact must have opted into before the SMS is sent.\nWhen set, the contact's form data is checked against the resolved consent filter\n(positive opt-in required, negative opt-out blocks the send).\n", nullable: true}, url_for_consent: {type: string, description: "Backend URL injected into the consent SMS link. Auto-populated by the gateway from\nthe env_webapp request header (production / usa / integration). Can be overridden\nexplicitly if needed.\n", example: 'https://production.quorumapps.com', nullable: true}, files: {type: array, items: {$ref: '#/components/schemas/File'}, description: 'Media files attached to the SMS (MMS). Optional.', nullable: true}, created_at: {type: string, format: date-time}, updated_at: {type: string, format: date-time}}
        File:
            type: object
            description: 'A media file (used for MMS attachments)'
            properties: {id: {type: integer, format: int64, description: 'File ID'}, name: {type: string, description: 'File name'}, url: {type: string, description: 'File URL'}}
        CreateWorkflowSmsTemplate:
            type: object
            description: "SMS template for a SendSms workflow. Note that `pre_upsert` is always forced to `false`\nfor SendSms workflows — consent checking requires the contact's form data to be\nfully persisted, which is only guaranteed in the post-upsert phase.\n"
            required: [message]
            properties: {message: {type: string, description: 'Plain-text SMS message body', example: 'Hi {{firstname}}, thanks for joining our campaign!'}, consent_data_ids: {type: array, items: {type: integer}, description: "IDs of consent-data entries required for the contact to receive this SMS.\nWhen set, the contact's form data is checked: positive opt-in is required,\nany negative opt-out blocks the send.\n", nullable: true}, file_ids: {type: array, items: {type: integer}, description: 'IDs of files to attach as MMS media. Optional.', nullable: true}}
        UpdateWorkflowSmsTemplate:
            type: object
            required: [message]
            properties: {id: {type: integer, description: 'WorkflowSmsTemplate ID (required for update, omit for replace)'}, message: {type: string, description: 'Plain-text SMS message body', example: 'Hi {{firstname}}, thanks for joining our campaign!'}, consent_data_ids: {type: array, items: {type: integer}, description: 'IDs of consent-data entries required for the contact to receive this SMS.', nullable: true}, file_ids: {type: array, items: {type: integer}, description: 'IDs of files to attach as MMS media. Optional.', nullable: true}}
        CreateWorkflowRequest:
            type: object
            required: [trigger_field, trigger_operator, trigger_value, name, action_to_activate]
            properties: {name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action'}, action_value: {type: string, description: 'Value for the action'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts', default: false}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert', default: false}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, mode: {type: string, enum: [exclusive, multiple], default: multiple, description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, workflow_email_template: {type: array, description: 'Required when action_to_activate is ''SendEmail''', items: {$ref: '#/components/schemas/CreateWorkflowEmailTemplate'}}, workflow_sms_template: {type: array, description: 'Required when action_to_activate is ''SendSms''. Exactly one entry expected.', items: {$ref: '#/components/schemas/CreateWorkflowSmsTemplate'}}}
        CreateWorkflowEmailTemplate:
            type: object
            required: [sender, subject]
            properties: {email_beefree_template_id: {type: integer, description: "Source template ID to duplicate. A new template with category='workflow_message' \nwill be created from this source template and linked to the workflow.\nEither this field or 'message' must be provided.\n", example: 123}, sender: {type: string, description: 'Email sender address', example: noreply@example.com}, sender_name: {type: string, description: 'Email sender name', example: 'Qomon Team'}, subject: {type: string, description: 'Email subject', example: 'Welcome to our campaign!'}, message: {type: object, description: "Message content to create. If provided, a new template with category='workflow_message' \nwill be created from this content. Either this field or 'email_beefree_template_id' must be provided.\n", required: [name, content_html, content_json], properties: {name: {type: string, description: 'Name of the template', example: 'Welcome email template'}, content_html: {type: string, description: 'HTML content of the message template', example: '<!DOCTYPE html><html><body><h1>Welcome!</h1></body></html>'}, content_json: {type: string, description: 'JSON content of the message template (BeePlugin format)', example: '{"page":{"body":{"rows":[{"columns":[{"contents":[{"html":"<h1>Welcome!</h1>"}]}]}]}}}'}}}}
        UpdateWorkflowEmailTemplate:
            type: object
            required: [id, sender, subject]
            properties: {id: {type: integer, description: 'WorkflowEmailTemplate ID (optional, used for metadata updates)', example: 1}, sender: {type: string, description: 'Email sender address', example: noreply@example.com}, sender_name: {type: string, description: 'Email sender name', example: 'Qomon Team'}, subject: {type: string, description: 'Email subject', example: 'Welcome to our campaign!'}, email_beefree_template_id: {type: integer, description: "Template ID to use for the workflow. If the template is not already a workflow_message, \nit will be duplicated and set to workflow_message category. The old template will be \nsoft deleted (if not bound). Either this field or 'message' can be provided to update the content.\n", example: 123}, message: {type: object, description: "Message content to update. If provided, a new template with category='workflow_message' \nwill be created from this content and the old template will be soft deleted (if not bound).\nEither this field or 'email_beefree_template_id' can be provided to update the content.\n", required: [name, content_html, content_json], properties: {name: {type: string, description: 'Name of the template', example: 'Updated welcome email template'}, content_html: {type: string, description: 'HTML content of the message template', example: '<!DOCTYPE html><html><body><h1>Hello</h1></body></html>'}, content_json: {type: string, description: 'JSON content of the message template (BeePlugin format)', example: '{"page":{"body":{"rows":[{"columns":[{"contents":[{"html":"<h1>Hello!</h1>"}]}]}]}}}'}}}}
        UpdateWorkflowRequest:
            type: object
            required: [trigger_field, trigger_operator, action_to_activate]
            properties: {name: {type: string, description: 'Name of the workflow', example: 'Welcome email'}, trigger_field: {type: string, description: 'Field that triggers the workflow', example: Petitions.BaseID}, trigger_operator: {type: string, description: 'Operator for trigger condition', enum: [eql, neq, gte, lte, gt, lt, contains, start_with, exists], example: eql}, trigger_value: {type: string, description: 'Value for trigger condition', example: test-petition-123}, action_to_activate: {type: string, description: 'Action to execute when triggered.', enum: [SendEmail, SendSms], example: SendEmail}, action_field: {type: string, description: 'Field for the action'}, action_value: {type: string, description: 'Value for the action'}, action_value_ref_value_id: {type: integer, description: 'Reference value ID for the action'}, applied_only_on_created_contact: {type: boolean, description: 'Whether workflow applies only to newly created contacts'}, pre_upsert: {type: boolean, description: 'Whether workflow runs before contact upsert'}, order: {type: integer, description: 'Execution order of the workflow'}, only_for_source: {type: string, description: 'Source restriction for the workflow'}, comment: {type: string, description: 'Comment or description of the workflow'}, is_active: {type: boolean, nullable: true, description: 'Whether the workflow is active (default true)'}, mode: {type: string, enum: [exclusive, multiple], description: "Workflow execution mode:\n- exclusive: Only one workflow with the same trigger_field and pre_upsert values can be applied on the same phase run\n- multiple: Multiple workflows with the same trigger_field and pre_upsert values can be applied on the same phase run\n"}, metadata: {type: object, nullable: true, description: 'Additional metadata for the workflow (extensible JSON field)'}, workflow_email_template: {type: array, description: 'Required when action_to_activate is ''SendEmail''', items: {$ref: '#/components/schemas/UpdateWorkflowEmailTemplate'}}, workflow_sms_template: {type: array, description: 'Required when action_to_activate is ''SendSms''. Exactly one entry expected.', items: {$ref: '#/components/schemas/UpdateWorkflowSmsTemplate'}}}
        SearchWorkflowsRequest:
            type: object
            properties: {user_id: {type: integer, format: int64, description: 'Filter workflows by user ID (optional)', nullable: true}, page: {type: integer, description: 'Page number, default -> 1', minimum: 1, default: 1, example: 1}, per_page: {type: integer, description: 'Items per page, default -> 20, max -> 100', minimum: 1, maximum: 100, default: 20, example: 20}}
        WorkflowSearchResponse:
            type: object
            properties: {workflows: {type: array, items: {$ref: '#/components/schemas/WorkflowSummary'}}, page: {type: integer, description: 'Current page number'}, per_page: {type: integer, description: 'Items per page'}, total: {type: integer, description: 'Total number of workflows'}, total_pages: {type: integer, description: 'Total number of pages'}}
        WorkflowRun:
            type: object
            description: 'A single execution run triggered by a message (maps to DAG Run concept)'
            properties: {id: {type: string, format: uuid, description: 'Unique run identifier'}, created_at: {type: string, format: date-time, description: 'When the run was created'}, updated_at: {type: string, format: date-time, description: 'When the run was last updated'}, group_id: {type: integer, description: 'Group ID that owns this run'}, status: {type: string, enum: [pending, running, completed, failed], description: 'Current status of the run'}, source: {type: string, description: 'Source that triggered this run', example: upsert.form}, contact_ids: {type: string, description: 'JSON array of contact IDs processed in this run'}, input_hash: {type: string, description: 'Hash of input payload for deduplication'}, input_payload: {type: object, nullable: true, description: 'Full input payload for replay/debugging (JSONB)'}, started_at: {type: string, format: date-time, nullable: true, description: 'When the run started executing'}, completed_at: {type: string, format: date-time, nullable: true, description: 'When the run completed'}, duration_ms: {type: integer, format: int64, nullable: true, description: 'Execution duration in milliseconds'}, total_workflows: {type: integer, description: 'Total number of workflows evaluated in this run'}, triggered_count: {type: integer, description: 'Number of workflows that were triggered'}, skipped_count: {type: integer, description: 'Number of workflows that were skipped'}, failed_count: {type: integer, description: 'Number of workflows that failed'}, error_message: {type: string, description: 'Error message if the run failed'}, metadata: {type: object, nullable: true, description: 'Additional metadata for DAG engine (extensible)'}, steps: {type: array, items: {$ref: '#/components/schemas/WorkflowRunStep'}, description: 'All execution steps in this run'}}
        WorkflowRunStep:
            type: object
            description: 'A single workflow evaluation/execution within a run (maps to Task Instance concept)'
            properties: {id: {type: integer, format: int64, description: 'Step ID'}, created_at: {type: string, format: date-time, description: 'When the step was created'}, run_id: {type: string, format: uuid, description: 'ID of the parent run'}, status: {type: string, enum: [pending, skipped, triggered, completed, failed], description: 'Current status of the step'}, workflow_id: {type: integer, description: 'ID of the workflow being executed'}, workflow_name: {type: string, description: 'Name of the workflow being executed'}, phase: {type: string, enum: [pre_upsert, post_upsert], description: 'Execution phase'}, order: {type: integer, description: 'Execution order within the phase'}, contact_id: {type: integer, description: 'ID of the contact that triggered this step'}, trigger_field: {type: string, description: 'Field that was evaluated for the trigger'}, trigger_operator: {type: string, description: 'Operator used for trigger evaluation'}, trigger_value: {type: string, description: 'Value used for trigger evaluation'}, trigger_matched: {type: boolean, description: 'Whether the trigger condition was matched'}, action_type: {type: string, description: 'Type of action executed'}, action_executed: {type: boolean, description: 'Whether the action was executed'}, skip_reason: {type: string, description: 'Reason why the step was skipped (e.g., "exclusive_blocked", "source_mismatch", "trigger_not_matched")'}, started_at: {type: string, format: date-time, nullable: true, description: 'When the step started executing'}, completed_at: {type: string, format: date-time, nullable: true, description: 'When the step completed'}, duration_ms: {type: integer, format: int64, nullable: true, description: 'Execution duration in milliseconds'}, error_message: {type: string, description: 'Error message if the step failed'}, input: {type: object, nullable: true, description: 'Input data for this step (JSONB)'}, output: {type: object, nullable: true, description: 'Output data from this step (JSONB)'}}
        SearchWorkflowRunsRequest:
            type: object
            properties: {workflow_id: {type: integer, description: 'Filter by specific workflow ID (optional)', nullable: true}, status: {type: string, enum: [pending, running, completed, failed], description: 'Filter by run status (optional)', nullable: true}, source: {type: string, description: 'Filter by source (e.g., "upsert.form", "upsert.import")', nullable: true}, from_date: {type: string, format: date-time, description: 'Filter runs created after this date (optional)', nullable: true}, to_date: {type: string, format: date-time, description: 'Filter runs created before this date (optional)', nullable: true}, page: {type: integer, description: 'Page number (default 1)', minimum: 1, default: 1}, per_page: {type: integer, description: 'Items per page (default 20, max 100)', minimum: 1, maximum: 100, default: 20}}
        WorkflowRunSearchResponse:
            type: object
            properties: {runs: {type: array, items: {$ref: '#/components/schemas/WorkflowRun'}}, page: {type: integer, description: 'Current page number'}, per_page: {type: integer, description: 'Items per page'}, total: {type: integer, description: 'Total number of runs'}, total_pages: {type: integer, description: 'Total number of pages'}}
        Error:
            type: object
            properties: {status: {type: string, example: error}, message: {type: string, example: 'Error description'}}
    responses:
        BadRequest:
            description: 'Bad request'
            content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}
        Unauthorized:
            description: Unauthorized
            content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}
        InternalServerError:
            description: 'Internal server error'
            content: {application/json: {schema: {$ref: '#/components/schemas/Error'}}}
    securitySchemes:
        bearerAuth:
            type: http
            scheme: bearer
            bearerFormat: JWT
