> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eachlabs.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Bulk trigger workflow

> Start multiple executions of the same workflow with different inputs in parallel.

This endpoint is useful for batch processing scenarios where you need to run the same
workflow multiple times with different input parameters.

**Key Features:**
- Maximum 10 executions per request
- All executions share the same `bulk_id` for tracking
- Executions run in parallel
- Partial failures are allowed - some executions may succeed while others fail
- Optional webhook notification when all executions complete

**Bulk ID:**
All executions from a bulk trigger share a unique `bulk_id` that can be used to:
- Query all executions from a single bulk operation
- Track batch progress
- Correlate webhook notifications

**Webhook Behavior:**
When a `webhook_url` is provided, the notification payload includes the `bulk_id`
field to help you identify and correlate executions from the same bulk operation.




## OpenAPI

````yaml /openapi_specs/workflows.json post /{workflowID}/bulk-trigger
openapi: 3.0.3
info:
  title: Workflows Engine API
  description: >
    # Workflows Engine API


    Execute and monitor AI workflows with a simple, consistent API.


    ## Quick Start


    1. **Trigger a workflow** - POST to `/{workflowID}/trigger` with your inputs

    2. **Monitor execution** - GET `/executions/{executionID}` to check status

    3. **Optional**: Provide a `webhook_url` to receive automatic notifications
    when complete


    ---


    ## Webhook Notifications


    When you provide a `webhook_url` when triggering a workflow, the Workflows
    Engine will automatically 

    **POST** to your endpoint with the execution results when the workflow
    completes (successfully or with an error).


    ### Key Features


    - ✅ **Consistent Payload**: The webhook payload has the same structure as
    the response from `GET /executions/{executionID}`

    - ✅ **Automatic Retries**: Failed webhook deliveries are automatically
    retried with exponential backoff

    - ✅ **Simple Integration**: No authentication required - your endpoint just
    needs to accept POST requests


    ### Webhook Request


    The engine will POST to your `webhook_url` with:


    - **Method**: `POST`

    - **Content-Type**: `application/json`

    - **Body**: Execution details (see payload structure below)


    ### Example Webhook Payload


    ```json

    {
      "execution_id": "69ae8c7b-7500-4a45-b7c0-348b8cc2665b",
      "workflow_id": "50741f40-8621-4d46-8a91-dff4d873be98",
      "status": "completed",
      "started_at": "2025-12-04T11:48:10Z",
      "inputs": {
        "story": "tell an epic story of a rat graduating from law"
      },
      "step_outputs": {
        "step1": {
          "step_id": "step1",
          "status": "completed",
          "output": "Once upon a time in Ratropolis...",
          "primary": "Once upon a time in Ratropolis...",
          "metadata": {
            "model": "openai-chatgpt-5",
            "version": "0.0.1",
            "params": {
              "system_prompt": "You are a helpful assistant",
              "max_output_tokens": 512
            }
          }
        },
        "step2": {
          "step_id": "step2",
          "status": "completed",
          "output": [
            "https://storage.googleapis.com/uploads/image1.png",
            "https://storage.googleapis.com/uploads/image2.png"
          ],
          "primary": "https://storage.googleapis.com/uploads/image1.png",
          "metadata": {
            "model": "nano-banana-pro",
            "params": {
              "num_images": 2,
              "aspect_ratio": "16:9"
            }
          }
        }
      },
      "output": [
        "https://storage.googleapis.com/uploads/image1.png",
        "https://storage.googleapis.com/uploads/image2.png"
      ]
    }

    ```


    ### Example Webhook Handler


    ```python

    @app.post("/webhooks/workflow-completed")

    async def handle_workflow_webhook(request: Request):
        execution = await request.json()
        
        if execution["status"] == "completed":
            # Process successful execution
            final_output = execution["output"]
            step_details = execution["step_outputs"]
            print(f"Workflow completed: {final_output}")
            
        elif execution["status"] == "failed":
            # Handle failure
            error = execution.get("error_cause", "Unknown error")
            print(f"Workflow failed: {error}")
        
        return {"received": True}
    ```


    Your webhook endpoint should return a `200 OK` status to acknowledge
    receipt.


    ---


    ## Fallback Configuration


    Model steps support an optional **fallback configuration** that
    automatically retries with an alternative 

    model if the primary model invocation fails. This provides resilience
    against temporary model outages 

    or rate limits.


    ### How Fallback Works


    When a model step has fallback configured, the workflow engine will:


    1. **Execute the primary model** with its configured parameters

    2. **If the primary attempt fails**, automatically execute the fallback
    model configuration

    3. **Mark the step as failed only if both primary and fallback attempts
    fail**


    ### Fallback Configuration


    Add a `fallback` object to any model step in your workflow definition:


    ```json

    {
      "step_id": "generate_image",
      "type": "model",
      "model": "flux-dev",
      "params": {
        "prompt": "{{inputs.prompt}}",
        "num_images": 1
      },
      "fallback": {
        "enabled": true,
        "model": "flux-1-1-pro",
        "params": {
          "prompt": "{{inputs.prompt}}",
          "guidance_scale": 7.5
        }
      }
    }

    ```


    ### Fallback Properties


    | Property | Type | Description |

    |----------|------|-------------|

    | `enabled` | boolean | Enable or disable fallback for this step (default:
    `true`) |

    | `model` | string | Alternative AI model identifier to use on failure |

    | `version` | string | Fallback model version (defaults to primary version
    when omitted) |

    | `params` | object | Model-specific parameters for the fallback (supports
    template variables) |


    ### Detecting Fallback Usage


    When a fallback is used, the step's metadata in execution results will
    include:


    - `fallback_used: true` - Indicates the step completed using the fallback
    configuration

    - `primary_error` - Human-readable description of why the primary attempt
    failed


    ### Example Execution Response with Fallback


    ```json

    {
      "step_id": "generate_image",
      "status": "completed",
      "output": "https://storage.googleapis.com/uploads/image.png",
      "metadata": {
        "model": "flux-1-1-pro",
        "fallback_used": true,
        "primary_error": "Primary model flux-dev failed: rate limit exceeded"
      }
    }

    ```


    ---


    ## Unlisted Workflows


    Versions can be "unlisted" - accessible via direct link but hidden from
    public listings.


    **Visibility states:**

    - **Private** (default): Organization only

    - **Unlisted**: Accessible via link, hidden from public listings

    - **Public**: Visible in listings and accessible to everyone


    **Setting unlisted:** Use `allowed_to_share: true` when creating or updating
    a version.


    ```bash

    # Create unlisted version

    PUT /workflows/{workflowID}/versions/v1 { "allowed_to_share": true, ... }

    ```


    **Behavior:**

    - `allowed_to_share: true` → Creates/updates as unlisted

    - `allowed_to_share: false` → Creates/updates as private

    - No effect on public versions (never downgraded)
  version: 1.0.0
  x-logo:
    url: ./logo-white.svg
    altText: Eachlabs Logo
servers:
  - url: https://workflows.eachlabs.run/api/v1
    description: >-
      Deprecated compatibility production host. This public URL remains
      supported for now, but will soon move under the api-service host at
      https://api.eachlabs.ai.
security:
  - ApiKeyAuth: []
tags:
  - name: Categories
    description: Workflow categories for organization
  - name: Workflows
    description: Workflow and version management
  - name: Executions
    description: Workflow execution and monitoring
  - name: Public Workflows
    description: Access public and unlisted workflows by organization nickname
paths:
  /{workflowID}/bulk-trigger:
    parameters:
      - name: workflowID
        in: path
        required: true
        description: Unique workflow identifier
        schema:
          type: string
          example: wf_abc123
    post:
      tags:
        - Executions
      summary: Bulk trigger workflow
      description: >
        Start multiple executions of the same workflow with different inputs in
        parallel.


        This endpoint is useful for batch processing scenarios where you need to
        run the same

        workflow multiple times with different input parameters.


        **Key Features:**

        - Maximum 10 executions per request

        - All executions share the same `bulk_id` for tracking

        - Executions run in parallel

        - Partial failures are allowed - some executions may succeed while
        others fail

        - Optional webhook notification when all executions complete


        **Bulk ID:**

        All executions from a bulk trigger share a unique `bulk_id` that can be
        used to:

        - Query all executions from a single bulk operation

        - Track batch progress

        - Correlate webhook notifications


        **Webhook Behavior:**

        When a `webhook_url` is provided, the notification payload includes the
        `bulk_id`

        field to help you identify and correlate executions from the same bulk
        operation.
      operationId: bulkTriggerWorkflow
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkTriggerWorkflowRequest'
      responses:
        '202':
          description: Bulk workflow executions started
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BulkTriggerWorkflowResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  schemas:
    BulkTriggerWorkflowRequest:
      type: object
      required:
        - inputs
      properties:
        version_id:
          type: string
          description: |
            **Optional**: Specific version to trigger for all executions.

            If not provided, triggers the latest version of the workflow.
          example: v1
        inputs:
          type: array
          minItems: 1
          maxItems: 10
          description: >
            Array of input parameter objects. Each item in the array will result
            in a separate workflow execution.


            **Constraints:**

            - Minimum 1 input required

            - Maximum 10 inputs per request


            All inputs must conform to the workflow's input schema.
          items:
            type: object
            additionalProperties: true
          example:
            - prompt: Generate image of a sunset
              style: photorealistic
            - prompt: Generate image of mountains
              style: artistic
            - prompt: Generate image of ocean
              style: minimalist
        webhook_url:
          type: string
          format: uri
          description: >
            **Optional webhook URL for execution completion notifications.**


            When provided, webhook notifications for all executions in this bulk
            operation

            will include a `bulk_id` field to help you correlate them.


            Each execution sends its own webhook notification when it completes.
          example: https://your-api.com/webhooks/workflow-completed
    BulkTriggerWorkflowResponse:
      type: object
      required:
        - bulk_id
        - executions
      properties:
        bulk_id:
          type: string
          format: uuid
          description: >
            Unique identifier for this bulk operation. All executions from this
            bulk trigger

            share this ID, which can be used to query and track them together.
          example: 550e8400-e29b-41d4-a716-446655440000
        executions:
          type: array
          description: >
            Array of execution responses, one per input in the request.

            The order matches the order of inputs in the request.


            **Partial Failures:**

            If some inputs fail validation, those entries will have `status:
            "failed"`

            with an error message, while successful triggers will have `status:
            "queued"`.
          items:
            $ref: '#/components/schemas/ExecutionResponse'
          example:
            - execution_id: exec-1
              status: queued
              started_at: '2025-12-20T10:00:00Z'
            - execution_id: exec-2
              status: queued
              started_at: '2025-12-20T10:00:01Z'
            - status: failed
              message: 'invalid input: missing required field ''prompt'''
    ExecutionResponse:
      type: object
      description: Response from triggering a workflow execution
      properties:
        execution_id:
          type: string
          description: Unique execution identifier (only present for successful triggers)
          example: exec_xyz789
        status:
          type: string
          enum:
            - queued
            - failed
          description: >
            Execution status immediately after triggering.

            - `queued`: Workflow execution has been queued and will start
            shortly

            - `failed`: Trigger failed due to validation or system error
          example: queued
        started_at:
          type: string
          format: date-time
          description: >-
            RFC3339 timestamp when the execution was queued (only present for
            successful triggers)
        message:
          type: string
          description: Error message (only present when status is "failed")
          example: 'invalid input: missing required field'
      example:
        execution_id: e2dba2bb-bc1d-4651-b6bf-fbbbebdee104
        status: queued
        started_at: '2025-12-03T10:21:09Z'
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Error message
  responses:
    BadRequest:
      description: Bad request - Invalid input
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Unauthorized - Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Not found - Resource does not exist
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key for authentication

````