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

# Batch Run Workflow

> Submit a batch of files to run through a specified workflow.

This endpoint allows you to efficiently initiate large batches of workflow runs in a single request (up to 1,000 in a single request, but you can queue up multiple batches in rapid succession). It accepts an array of inputs, each containing a file and metadata pair. The primary use case for this endpoint is for doing large bulk runs of >1000 files at a time that can process over the course of a few hours without needing to manage rate limits that would likely occur using the primary run endpoint.

Unlike the single [Run Workflow](/api-reference/endpoint/run_workflow) endpoint which returns the details of the created workflow runs immediately, this batch endpoint returns a `batchId`.

Our recommended usage pattern is to integrate with [Webhooks](/api-reference/webhooks/events) for consuming results, using the `metadata` and `batchId` to match up results to the original inputs in your downstream systems. However, you can integrate in a polling mechanism by using a combination of the [List Workflow Runs](/api-reference/endpoint/list_workflow_runs) endpoint to fetch all runs via a batch, and then [Get Workflow Run](/api-reference/endpoint/get_workflow_run) to fetch the full outputs each run.

### Body

<ParamField body="workflowId" type="string" required>
  The ID of the workflow that the inputs will be run through. This ID can be found
  by viewing the workflow on the Extend platform.
</ParamField>

<ParamField body="version" type="string" optional>
  An optional version of the workflow to use. This can be a specific version number (e.g., `"1"`, `"2"`) found on the Extend platform, or `"draft"` to use the current unpublished draft version.
  When a version is not supplied, the latest *deployed* version of the workflow will be used.
</ParamField>

<ParamField body="inputs" type="Input[]" required>
  An array of input objects to be processed by the workflow. Each object represents a single workflow run to be created.
  The array must contain at least 1 input and at most 1000 inputs.

  <Expandable title="Properties">
    <ParamField body="file" type="object" optional>
      Specifies a file to be processed. Either `file` or `rawText` must be provided for each input.

      <Expandable title="File Object Properties">
        <ParamField body="fileUrl" type="string" optional>
          A presigned URL for the file. For the batch endpoint, we suggest a slightly longer expiration time, ideally 30 minutes for a worst case scenario.
        </ParamField>

        <ParamField body="fileId" type="string" optional>
          An existing Extend file ID (e.g., from a previous workflow run or file upload). If provided, Extend will reuse the existing file data. Either `fileUrl` or `fileId` must be provided if the `file` object is used.
        </ParamField>

        <ParamField body="fileName" type="string" optional>
          The name to associate with the file. If not provided when using `fileUrl`, the name may be inferred from the URL. This param is only for your reference, and will be rendered in our dashboard, it is not used by the workflow.
        </ParamField>
      </Expandable>
    </ParamField>

    <ParamField body="rawText" type="string" optional>
      A string containing raw text data to be processed. This will be treated as a `.txt` file by the workflow. Use the `file` parameter for structured data or specific file types. Either `file` or `rawText` must be provided for each input.
    </ParamField>

    <ParamField body="metadata" type="object" optional>
      An optional object containing arbitrary key-value pairs to associate with this specific workflow run. This metadata will be included in webhook payloads and responses when fetching the workflow run details.
    </ParamField>

    <ParamField body="secrets" type="object" optional>
      An optional object containing secrets to be used by processors within the workflow for this specific run. Secrets provided here override any globally configured secrets for the workflow.
    </ParamField>
  </Expandable>
</ParamField>

### Response

<ResponseField name="success" type="boolean">
  Indicates whether the batch request was successfully accepted and queued. `true` signifies success.
</ResponseField>

<ResponseField name="batchId" type="string">
  A unique identifier for the submitted batch. This ID can be used to correlate the workflow runs created by this request. You can find this `batchId` associated with individual runs when listing workflow runs or in webhook payloads.
</ResponseField>

### Processing and Monitoring

Upon successful submission, the endpoint returns a `batchId`. The individual workflow runs are then queued for processing.

* **Monitoring:** Track the progress and consume results of individual runs using [Webhooks](/api-reference/webhooks/events). Subscribe to events like `workflow_run.completed`, `workflow_run.failed`, etc. The webhook payload for these events will include the corresponding `batchId` and the `metadata` you provided for each input.
* **Fetching Results:** You can also use the [List Workflow Runs](/api-reference/endpoint/list_workflow_runs) endpoint and filter using the `batchId` query param.

<RequestExample>
  ```bash Bash theme={null}
  curl --location --request POST 'https://api-prod.extend.app/workflow_runs/batch' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer <API_TOKEN>' \
  --data '{
      "workflowId": "workflow_abc789",
      "version": "2",
      "inputs": [
        {
          "file": {
            "fileName": "invoice_1.pdf",
            "fileUrl": "https://your-presigned-url.s3.amazonaws.com/invoice_1.pdf?..."
          },
          "metadata": {
            "customer_id": "cust_123",
            "source": "batch_upload"
          }
        },
        {
          "file": {
            "fileId": "file_def456"
          },
          "metadata": {
            "customer_id": "cust_456",
            "source": "batch_upload"
          }
        },
        {
          "rawText": "This is the raw text content for the third run.",
          "metadata": {
            "internal_ref": "ref_789"
          }
        }
      ]
  }'
  ```

  ```javascript Node.js theme={null}
  async function runWorkflowBatch() {
    const apiToken = "<API_TOKEN>";
    const url = "https://api-prod.extend.app/workflow_runs/batch";

    const payload = {
      workflowId: "workflow_abc789",
      version: "2",
      inputs: [
        {
          file: {
            fileName: "invoice_1.pdf",
            fileUrl: "https://your-presigned-url.s3.amazonaws.com/invoice_1.pdf?..."
          },
          name: "Run for Invoice 1",
          metadata: {
            customer_id: "cust_123",
            source": "batch_upload"
          }
        },
        {
          file: {
            fileId: "file_def456"
          },
          name: "Run for Existing File DEF456",
          metadata: {
            customer_id": "cust_456",
            source": "batch_upload"
          }
        },
        {
          rawText: "This is the raw text content for the third run.",
          name: "Run for Raw Text Input",
          metadata: {
            internal_ref": "ref_789"
          }
        }
      ]
    };

    try {
      const response = await fetch(url, {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${apiToken}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(payload),
      });

      const data = await response.json();

      if (!response.ok) {
        console.error(`Error: ${response.status}`, data);
        // Log the response text for more detailed debugging if needed
        // console.error("Response text:", await response.text());
        return;
      }

      console.log("Success:", data);

    } catch (error) {
      console.error("Request failed:", error);
    }
  }

  runWorkflowBatch();
  ```

  ```python Python theme={null}
  import requests
  import json

  api_token = "<API_TOKEN>"
  url = "https://api-prod.extend.app/workflow_runs/batch"

  payload = {
      "workflowId": "workflow_abc789",
      "version": "2",
      "inputs": [
          {
              "file": {
                  "fileName": "invoice_1.pdf",
                  "fileUrl": "https://your-presigned-url.s3.amazonaws.com/invoice_1.pdf?..."
              },
              "metadata": {
                  "customer_id": "cust_123",
                  "source": "batch_upload"
              }
          },
          {
              "file": {
                  "fileId": "file_def456"
              },
              "metadata": {
                  "customer_id": "cust_456",
                  "source": "batch_upload"
              }
          },
          {
              "rawText": "This is the raw text content for the third run.",
              "metadata": {
                  "internal_ref": "ref_789"
              }
          }
      ]
  }

  headers = {
      "Authorization": f"Bearer {api_token}",
      "Content-Type": "application/json"
  }

  response = requests.post(url, headers=headers, data=json.dumps(payload))

  print(response.status_code)
  print(response.json())
  ```
</RequestExample>

<ResponseExample>
  ```json Example Success Response (200 OK) theme={null}
  {
    "success": true,
    "batchId": "batch_zyx987"
  }
  ```
</ResponseExample>

### Error Responses

Common errors include:

* **400 Bad Request**: Invalid request body (e.g., missing required fields, array size limits exceeded, issues with `fileUrl` or `fileId`). The response body will contain an `error` message detailing the specific validation issues. Can also indicate issues accessing a provided `fileUrl`.
* **401 Unauthorized**: Missing or invalid API token.
* **403 Forbidden**: The API token does not have permission to access the specified workflow.
* **404 Not Found**: The specified `workflowId` or `version` does not exist.
* **429 Too Many Requests**: The request was rate limited. Please try again later.
* **500 Internal Server Error**: An unexpected error occurred on the server.

<ResponseExample>
  ```json Example Error Response (400 Bad Request) theme={null}
  {
    "success": false,
    "error": "Validation Error: Array must contain at most 1000 element(s): param: inputs"
  }
  ```
</ResponseExample>

<ResponseExample>
  ```json Example Error Response (404 Not Found) theme={null}
  {
    "success": false,
    "error": "Resource not found."
  }
  ```
</ResponseExample>
