> ## Documentation Index
> Fetch the complete documentation index at: https://docs.extend.ai/llms.txt
> Use this file to discover all available pages before exploring further.
>
> ## API version
> The current API version is `2026-02-09`, served at the site root (no version prefix in URLs).
> If this page URL contains `/2025-04-21/` or `/2024-12-23/`, you are reading an older API version.
> Prefer the current docs at https://docs.extend.ai/llms.txt unless the user explicitly needs that older version.
> Do not treat older-version pages as the source of truth for new integrations.

# Batch Processing

> Process hundreds or thousands of files asynchronously using the batch endpoints for parsing, extraction, classification, and splitting.

Batch endpoints let you submit up to one thousand files in a single API call. Each file is enqueued as an independent run and processed asynchronously — use webhooks to know when the batch completes, then fetch results via the List endpoints.

Batch endpoints are available for parsing and all three document processor types:

| Operation | Create batch                | Get batch status       |
| --------- | --------------------------- | ---------------------- |
| Parse     | `POST /parse_runs/batch`    | `GET /batch_runs/{id}` |
| Extract   | `POST /extract_runs/batch`  | `GET /batch_runs/{id}` |
| Classify  | `POST /classify_runs/batch` | `GET /batch_runs/{id}` |
| Split     | `POST /split_runs/batch`    | `GET /batch_runs/{id}` |

## When to use batch endpoints

Use batch endpoints when you have **many** files to process — for example, end-of-day ingestion pipelines, bulk backfills, or any high-volume async workload.

Batch submissions are placed into a delayed queue and given a **lower default priority** than single runs. This ensures that batch workloads do not interfere with interactive use from the dashboard or single-file API calls.

For low-volume or low-latency use cases, the single-file [async endpoints](/api-reference/endpoints/extract/create-extract-run) with polling or webhooks are the right choice.

Batch processes each file **independently** and returns one result per file. If several files should be read together as one document (a contract plus its amendments, or multiple photos of one receipt), you want [Multifile Extraction](/extraction/multifile) with a `package`, not a batch. See [Multifile vs batch](/extraction/multifile#multifile-vs-batch).

## How it works

1. **Submit** — Send a `POST` request with an `inputs` array (1–1,000 items). For processor batches (extract, classify, split) a processor ID is required; for parse batches, config is optional. The endpoint returns immediately with a batch object in `PENDING` status.
2. **Process** — Each item in `inputs` is enqueued as an independent run. The batch transitions through `PENDING → PROCESSING → PROCESSED` (or `FAILED` / `CANCELLED`).
3. **Consume results** — Subscribe to webhooks to be notified when the batch completes, then fetch individual run results via the List endpoints filtered by `batchId`.

Inline configuration (`config`) is not supported for batch processor requests (extract, classify, split). You must reference an existing processor by `id`.

---

## Batch parsing

**`Python SDK`**

```python Python SDK
from extend_ai import Extend

client = Extend(token="YOUR_API_KEY")

batch = client.parse_runs.create_batch(
    # config is optional — omit to use default parse settings
    inputs=[
        {
            "file": {"url": "https://example.com/document1.pdf"},
            "metadata": {"customerId": "cust_abc123"},
        },
        {
            "file": {"url": "https://example.com/document2.pdf"},
            "metadata": {"customerId": "cust_def456"},
        },
        {
            "file": {"id": "file_ghi789"},  # previously uploaded Extend file ID
        },
        {
            "file": {"text": "Raw text content to parse."},  # raw text also supported
        },
    ],
)

print(batch.id)      # "bpar_Xj8mK2pL9nR4vT7qY5wZ"
print(batch.status)  # "PENDING"

# Poll the batch status
status = client.batch_runs.get(batch.id)
print(status.status)    # "PENDING" | "PROCESSING" | "PROCESSED" | "FAILED" | "CANCELLED"
print(status.run_count) # number of individual runs created
```

**`TypeScript SDK`**

```typescript TypeScript SDK
import { ExtendClient } from "extend-ai";

const client = new ExtendClient({ token: "YOUR_API_KEY" });

const batch = await client.parseRuns.createBatch({
  // config is optional — omit to use default parse settings
  inputs: [
    {
      file: { url: "https://example.com/document1.pdf" },
      metadata: { customerId: "cust_abc123" },
    },
    {
      file: { url: "https://example.com/document2.pdf" },
      metadata: { customerId: "cust_def456" },
    },
    {
      file: { id: "file_ghi789" }, // previously uploaded Extend file ID
    },
    {
      file: { text: "Raw text content to parse." }, // raw text also supported
    },
  ],
});

console.log(batch.id);     // "bpar_Xj8mK2pL9nR4vT7qY5wZ"
console.log(batch.status); // "PENDING"

// Poll the batch status
const status = await client.batchRuns.get(batch.id);
console.log(status.status);   // "PENDING" | "PROCESSING" | "PROCESSED" | "FAILED" | "CANCELLED"
console.log(status.runCount); // number of individual runs created
```

**`Java SDK`**

```java Java SDK
import ai.extend.ExtendClient;
import ai.extend.resources.parseruns.requests.ParseRunsCreateBatchRequest;
import ai.extend.resources.parseruns.types.ParseRunsCreateBatchRequestInputsItem;
import ai.extend.resources.parseruns.types.ParseRunsCreateBatchRequestInputsItemFile;
import ai.extend.types.FileFromUrl;
import ai.extend.types.FileFromText;
import java.util.List;

var client = ExtendClient.builder().apiKey("YOUR_API_KEY").build();

var batch = client.parseRuns().createBatch(
    ParseRunsCreateBatchRequest.builder()
        // config is optional — omit to use default parse settings
        .inputs(List.of(
            ParseRunsCreateBatchRequestInputsItem.builder()
                .file(ParseRunsCreateBatchRequestInputsItemFile.of(
                    FileFromUrl.builder().url("https://example.com/document1.pdf").build()))
                .build(),
            ParseRunsCreateBatchRequestInputsItem.builder()
                .file(ParseRunsCreateBatchRequestInputsItemFile.of(
                    FileFromUrl.builder().url("https://example.com/document2.pdf").build()))
                .build(),
            ParseRunsCreateBatchRequestInputsItem.builder()
                .file(ParseRunsCreateBatchRequestInputsItemFile.of(
                    FileFromText.builder().text("Raw text content to parse.").build()))
                .build()))
        .build()
);

System.out.println(batch.getId());     // "bpar_Xj8mK2pL9nR4vT7qY5wZ"
System.out.println(batch.getStatus()); // "PENDING"

// Poll the batch status
var status = client.batchRuns().get(batch.getId());
System.out.println(status.getStatus());   // "PENDING" | "PROCESSING" | "PROCESSED" | "FAILED" | "CANCELLED"
System.out.println(status.getRunCount()); // number of individual runs created
```

**`Go SDK`**

```go Go SDK
import (
	"context"
	"fmt"
	"log"

	extend "github.com/extend-hq/extend-go-sdk"
	client "github.com/extend-hq/extend-go-sdk/client"
	option "github.com/extend-hq/extend-go-sdk/option"
)

c := client.NewClient(option.WithToken("YOUR_API_KEY"))

// config is optional — omit to use default parse settings
batch, err := c.ParseRuns.CreateBatch(context.TODO(), &extend.ParseRunsCreateBatchRequest{
	Inputs: []*extend.ParseRunsCreateBatchRequestInputsItem{
		{File: &extend.ParseRunsCreateBatchRequestInputsItemFile{
			FileFromURL: &extend.FileFromURL{URL: "https://example.com/document1.pdf"},
		}},
		{File: &extend.ParseRunsCreateBatchRequestInputsItemFile{
			FileFromURL: &extend.FileFromURL{URL: "https://example.com/document2.pdf"},
		}},
		{File: &extend.ParseRunsCreateBatchRequestInputsItemFile{
			FileFromID: &extend.FileFromID{ID: "file_ghi789"}, // previously uploaded Extend file ID
		}},
		{File: &extend.ParseRunsCreateBatchRequestInputsItemFile{
			FileFromText: &extend.FileFromText{Text: "Raw text content to parse."}, // raw text also supported
		}},
	},
})
if err != nil {
	log.Fatal(err)
}

fmt.Println(batch.ID)     // "bpar_Xj8mK2pL9nR4vT7qY5wZ"
fmt.Println(batch.Status) // "PENDING"

// Poll the batch status
status, err := c.BatchRuns.Get(context.TODO(), batch.ID)
if err != nil {
	log.Fatal(err)
}
fmt.Println(status.Status)   // PENDING | PROCESSING | PROCESSED | FAILED | CANCELLED
fmt.Println(status.RunCount) // number of individual runs created
```

---

## Batch extraction

**`Python SDK`**

```python Python SDK
from extend_ai import Extend

client = Extend(token="YOUR_API_KEY")

batch = client.extract_runs.create_batch(
    extractor={
        "id": "ex_xK9mLPqRtN3vS8wF5hB2cQ",
        # "version": "1.0",          # optional — defaults to "latest"
        # "override_config": { ... }, # optional — partial config override
    },
    inputs=[
        {
            "file": {"url": "https://example.com/invoice1.pdf"},
            "metadata": {"customerId": "cust_abc123"},
        },
        {
            "file": {"url": "https://example.com/invoice2.pdf"},
            "metadata": {"customerId": "cust_def456"},
        },
        {
            "file": {"id": "file_ghi789"},  # previously uploaded Extend file ID
        },
    ],
)

print(batch.id)      # "bpr_Xj8mK2pL9nR4vT7qY5wZ"
print(batch.status)  # "PENDING"

# Poll the batch status
status = client.batch_runs.get(batch.id)
print(status.status)    # "PENDING" | "PROCESSING" | "PROCESSED" | "FAILED" | "CANCELLED"
print(status.run_count) # number of individual runs created
```

**`TypeScript SDK`**

```typescript TypeScript SDK
import { ExtendClient } from "extend-ai";

const client = new ExtendClient({ token: "YOUR_API_KEY" });

const batch = await client.extractRuns.createBatch({
  extractor: {
    id: "ex_xK9mLPqRtN3vS8wF5hB2cQ",
    // version: "1.0",          // optional — defaults to "latest"
    // overrideConfig: { ... }, // optional — partial config override
  },
  inputs: [
    {
      file: { url: "https://example.com/invoice1.pdf" },
      metadata: { customerId: "cust_abc123" },
    },
    {
      file: { url: "https://example.com/invoice2.pdf" },
      metadata: { customerId: "cust_def456" },
    },
    {
      file: { id: "file_ghi789" }, // previously uploaded Extend file ID
    },
  ],
});

console.log(batch.id);     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
console.log(batch.status); // "PENDING"

// Poll the batch status
const status = await client.batchRuns.get(batch.id);
console.log(status.status);   // "PENDING" | "PROCESSING" | "PROCESSED" | "FAILED" | "CANCELLED"
console.log(status.runCount); // number of individual runs created
```

**`Java SDK`**

```java Java SDK
import ai.extend.ExtendClient;
import ai.extend.resources.extractruns.requests.ExtractRunsCreateBatchRequest;
import ai.extend.resources.extractruns.types.ExtractRunsCreateBatchRequestExtractor;
import ai.extend.resources.extractruns.types.ExtractRunsCreateBatchRequestInputsItem;
import ai.extend.resources.extractruns.types.ExtractRunsCreateBatchRequestInputsItemFile;
import ai.extend.types.FileFromUrl;
import java.util.List;

var client = ExtendClient.builder().apiKey("YOUR_API_KEY").build();

var batch = client.extractRuns().createBatch(
    ExtractRunsCreateBatchRequest.builder()
        .extractor(ExtractRunsCreateBatchRequestExtractor.builder()
            .id("ex_xK9mLPqRtN3vS8wF5hB2cQ")
            .build())
        .inputs(List.of(
            ExtractRunsCreateBatchRequestInputsItem.builder()
                .file(ExtractRunsCreateBatchRequestInputsItemFile.of(
                    FileFromUrl.builder().url("https://example.com/invoice1.pdf").build()))
                .build(),
            ExtractRunsCreateBatchRequestInputsItem.builder()
                .file(ExtractRunsCreateBatchRequestInputsItemFile.of(
                    FileFromUrl.builder().url("https://example.com/invoice2.pdf").build()))
                .build()))
        .build()
);

System.out.println(batch.getId());     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
System.out.println(batch.getStatus()); // "PENDING"

// Poll the batch status
var status = client.batchRuns().get(batch.getId());
System.out.println(status.getStatus());   // "PENDING" | "PROCESSING" | "PROCESSED" | "FAILED" | "CANCELLED"
System.out.println(status.getRunCount()); // number of individual runs created
```

**`Go SDK`**

```go Go SDK
import (
	"context"
	"fmt"
	"log"

	extend "github.com/extend-hq/extend-go-sdk"
	client "github.com/extend-hq/extend-go-sdk/client"
	option "github.com/extend-hq/extend-go-sdk/option"
)

c := client.NewClient(option.WithToken("YOUR_API_KEY"))

batch, err := c.ExtractRuns.CreateBatch(context.TODO(), &extend.ExtractRunsCreateBatchRequest{
	Extractor: &extend.ExtractRunsCreateBatchRequestExtractor{
		ID: "ex_xK9mLPqRtN3vS8wF5hB2cQ", // Version / OverrideConfig are optional (defaults to "latest")
	},
	Inputs: []*extend.ExtractRunsCreateBatchRequestInputsItem{
		{File: &extend.ExtractRunsCreateBatchRequestInputsItemFile{
			FileFromURL: &extend.FileFromURL{URL: "https://example.com/invoice1.pdf"},
		}},
		{File: &extend.ExtractRunsCreateBatchRequestInputsItemFile{
			FileFromURL: &extend.FileFromURL{URL: "https://example.com/invoice2.pdf"},
		}},
		{File: &extend.ExtractRunsCreateBatchRequestInputsItemFile{
			FileFromID: &extend.FileFromID{ID: "file_ghi789"}, // previously uploaded Extend file ID
		}},
	},
})
if err != nil {
	log.Fatal(err)
}

fmt.Println(batch.ID)     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
fmt.Println(batch.Status) // "PENDING"

// Poll the batch status
status, err := c.BatchRuns.Get(context.TODO(), batch.ID)
if err != nil {
	log.Fatal(err)
}
fmt.Println(status.Status)   // PENDING | PROCESSING | PROCESSED | FAILED | CANCELLED
fmt.Println(status.RunCount) // number of individual runs created
```

---

## Batch classification

**`Python SDK`**

```python Python SDK
from extend_ai import Extend

client = Extend(token="YOUR_API_KEY")

batch = client.classify_runs.create_batch(
    classifier={
        "id": "cl_xK9mLPqRtN3vS8wF5hB2cQ",
        # "version": "2.0",           # optional — defaults to "latest"
        # "override_config": { ... },  # optional — partial config override
    },
    inputs=[
        {
            "file": {"url": "https://example.com/document1.pdf"},
            "metadata": {"source": "email-inbox"},
        },
        {
            "file": {"url": "https://example.com/document2.pdf"},
            "metadata": {"source": "upload-portal"},
        },
    ],
)

print(batch.id)      # "bpr_Xj8mK2pL9nR4vT7qY5wZ"
print(batch.status)  # "PENDING"
```

**`TypeScript SDK`**

```typescript TypeScript SDK
import { ExtendClient } from "extend-ai";

const client = new ExtendClient({ token: "YOUR_API_KEY" });

const batch = await client.classifyRuns.createBatch({
  classifier: {
    id: "cl_xK9mLPqRtN3vS8wF5hB2cQ",
    // version: "2.0",          // optional — defaults to "latest"
    // overrideConfig: { ... }, // optional — partial config override
  },
  inputs: [
    {
      file: { url: "https://example.com/document1.pdf" },
      metadata: { source: "email-inbox" },
    },
    {
      file: { url: "https://example.com/document2.pdf" },
      metadata: { source: "upload-portal" },
    },
  ],
});

console.log(batch.id);     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
console.log(batch.status); // "PENDING"
```

**`Java SDK`**

```java Java SDK
import ai.extend.ExtendClient;
import ai.extend.resources.classifyruns.requests.ClassifyRunsCreateBatchRequest;
import ai.extend.resources.classifyruns.types.ClassifyRunsCreateBatchRequestClassifier;
import ai.extend.resources.classifyruns.types.ClassifyRunsCreateBatchRequestInputsItem;
import ai.extend.resources.classifyruns.types.ClassifyRunsCreateBatchRequestInputsItemFile;
import ai.extend.types.FileFromUrl;
import java.util.List;

var client = ExtendClient.builder().apiKey("YOUR_API_KEY").build();

var batch = client.classifyRuns().createBatch(
    ClassifyRunsCreateBatchRequest.builder()
        .classifier(ClassifyRunsCreateBatchRequestClassifier.builder()
            .id("cl_xK9mLPqRtN3vS8wF5hB2cQ")
            .build())
        .inputs(List.of(
            ClassifyRunsCreateBatchRequestInputsItem.builder()
                .file(ClassifyRunsCreateBatchRequestInputsItemFile.of(
                    FileFromUrl.builder().url("https://example.com/document1.pdf").build()))
                .build(),
            ClassifyRunsCreateBatchRequestInputsItem.builder()
                .file(ClassifyRunsCreateBatchRequestInputsItemFile.of(
                    FileFromUrl.builder().url("https://example.com/document2.pdf").build()))
                .build()))
        .build()
);

System.out.println(batch.getId());     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
System.out.println(batch.getStatus()); // "PENDING"
```

**`Go SDK`**

```go Go SDK
import (
	"context"
	"fmt"
	"log"

	extend "github.com/extend-hq/extend-go-sdk"
	client "github.com/extend-hq/extend-go-sdk/client"
	option "github.com/extend-hq/extend-go-sdk/option"
)

c := client.NewClient(option.WithToken("YOUR_API_KEY"))

batch, err := c.ClassifyRuns.CreateBatch(context.TODO(), &extend.ClassifyRunsCreateBatchRequest{
	Classifier: &extend.ClassifyRunsCreateBatchRequestClassifier{
		ID: "cl_xK9mLPqRtN3vS8wF5hB2cQ", // Version / OverrideConfig are optional (defaults to "latest")
	},
	Inputs: []*extend.ClassifyRunsCreateBatchRequestInputsItem{
		{File: &extend.ClassifyRunsCreateBatchRequestInputsItemFile{
			FileFromURL: &extend.FileFromURL{URL: "https://example.com/document1.pdf"},
		}},
		{File: &extend.ClassifyRunsCreateBatchRequestInputsItemFile{
			FileFromURL: &extend.FileFromURL{URL: "https://example.com/document2.pdf"},
		}},
	},
})
if err != nil {
	log.Fatal(err)
}

fmt.Println(batch.ID)     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
fmt.Println(batch.Status) // "PENDING"
```

---

## Batch splitting

Raw text input (`{ text: "..." }`) is **not** supported for split runs. Provide files as a URL (`{ url: "..." }`) or an Extend file ID (`{ id: "..." }`).

**`Python SDK`**

```python Python SDK
from extend_ai import Extend

client = Extend(token="YOUR_API_KEY")

batch = client.split_runs.create_batch(
    splitter={
        "id": "spl_xK9mLPqRtN3vS8wF5hB2cQ",
        # "version": "1.0",           # optional — defaults to "latest"
        # "override_config": { ... },  # optional — partial config override
    },
    inputs=[
        {
            "file": {"url": "https://example.com/multi-doc1.pdf"},
            "metadata": {"batchRef": "daily-run-2026-04-07"},
        },
        {
            "file": {"url": "https://example.com/multi-doc2.pdf"},
            "metadata": {"batchRef": "daily-run-2026-04-07"},
        },
    ],
)

print(batch.id)      # "bpr_Xj8mK2pL9nR4vT7qY5wZ"
print(batch.status)  # "PENDING"
```

**`TypeScript SDK`**

```typescript TypeScript SDK
import { ExtendClient } from "extend-ai";

const client = new ExtendClient({ token: "YOUR_API_KEY" });

const batch = await client.splitRuns.createBatch({
  splitter: {
    id: "spl_xK9mLPqRtN3vS8wF5hB2cQ",
    // version: "1.0",          // optional — defaults to "latest"
    // overrideConfig: { ... }, // optional — partial config override
  },
  inputs: [
    {
      file: { url: "https://example.com/multi-doc1.pdf" },
      metadata: { batchRef: "daily-run-2026-04-07" },
    },
    {
      file: { url: "https://example.com/multi-doc2.pdf" },
      metadata: { batchRef: "daily-run-2026-04-07" },
    },
  ],
});

console.log(batch.id);     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
console.log(batch.status); // "PENDING"
```

**`Java SDK`**

```java Java SDK
import ai.extend.ExtendClient;
import ai.extend.resources.splitruns.requests.SplitRunsCreateBatchRequest;
import ai.extend.resources.splitruns.types.SplitRunsCreateBatchRequestInputsItem;
import ai.extend.resources.splitruns.types.SplitRunsCreateBatchRequestInputsItemFile;
import ai.extend.resources.splitruns.types.SplitRunsCreateBatchRequestSplitter;
import ai.extend.types.FileFromUrl;
import java.util.List;

var client = ExtendClient.builder().apiKey("YOUR_API_KEY").build();

var batch = client.splitRuns().createBatch(
    SplitRunsCreateBatchRequest.builder()
        .splitter(SplitRunsCreateBatchRequestSplitter.builder()
            .id("spl_xK9mLPqRtN3vS8wF5hB2cQ")
            .build())
        .inputs(List.of(
            SplitRunsCreateBatchRequestInputsItem.builder()
                .file(SplitRunsCreateBatchRequestInputsItemFile.of(
                    FileFromUrl.builder().url("https://example.com/multi-doc1.pdf").build()))
                .build(),
            SplitRunsCreateBatchRequestInputsItem.builder()
                .file(SplitRunsCreateBatchRequestInputsItemFile.of(
                    FileFromUrl.builder().url("https://example.com/multi-doc2.pdf").build()))
                .build()))
        .build()
);

System.out.println(batch.getId());     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
System.out.println(batch.getStatus()); // "PENDING"
```

**`Go SDK`**

```go Go SDK
import (
	"context"
	"fmt"
	"log"

	extend "github.com/extend-hq/extend-go-sdk"
	client "github.com/extend-hq/extend-go-sdk/client"
	option "github.com/extend-hq/extend-go-sdk/option"
)

c := client.NewClient(option.WithToken("YOUR_API_KEY"))

batch, err := c.SplitRuns.CreateBatch(context.TODO(), &extend.SplitRunsCreateBatchRequest{
	Splitter: &extend.SplitRunsCreateBatchRequestSplitter{
		ID: "spl_xK9mLPqRtN3vS8wF5hB2cQ", // Version / OverrideConfig are optional (defaults to "latest")
	},
	Inputs: []*extend.SplitRunsCreateBatchRequestInputsItem{
		{File: &extend.SplitRunsCreateBatchRequestInputsItemFile{
			FileFromURL: &extend.FileFromURL{URL: "https://example.com/multi-doc1.pdf"},
		}},
		{File: &extend.SplitRunsCreateBatchRequestInputsItemFile{
			FileFromURL: &extend.FileFromURL{URL: "https://example.com/multi-doc2.pdf"},
		}},
	},
})
if err != nil {
	log.Fatal(err)
}

fmt.Println(batch.ID)     // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
fmt.Println(batch.Status) // "PENDING"
```

---

## Monitoring results

### Webhooks

Subscribe to batch completion events to be notified when a batch finishes. The webhook payload includes the batch ID but not individual run results — use the List endpoints (below) to fetch those once notified.

**Batch parse run events** (for `POST /parse_runs/batch`):

| Event                       | Description                                              |
| --------------------------- | -------------------------------------------------------- |
| `batch_parse_run.processed` | Triggered when a batch parse run has finished processing |
| `batch_parse_run.failed`    | Triggered when a batch parse run has failed              |

**Batch processor run events** (for extract, classify, and split batches — all emit the same event types):

| Event                           | Description                                    |
| ------------------------------- | ---------------------------------------------- |
| `batch_processor_run.processed` | Triggered when a batch has finished processing |
| `batch_processor_run.failed`    | Triggered when a batch has failed              |

See [Webhook Configuration](/webhooks/configuration) for setup instructions.

### Checking batch status

You can poll the GET batch endpoint at any time to check the current status of a batch. The same endpoint works for all batch types — parse, extract, classify, and split. You can identify the type from the batch ID prefix (`bpar_` for parse, `bpr_` for processor batches):

```bash
GET /batch_runs/{batchId}
```

The batch `status` field reflects the aggregate state:

| Status       | Meaning                             |
| ------------ | ----------------------------------- |
| `PENDING`    | Queued, not yet started             |
| `PROCESSING` | Runs are actively being processed   |
| `PROCESSED`  | All runs have completed             |
| `FAILED`     | The batch encountered a fatal error |
| `CANCELLED`  | The batch was cancelled             |

### Fetching individual results

Once the batch has completed, retrieve individual run results using the List endpoints with a `batchId` filter:

```bash
GET /parse_runs?batchId={batchId}
GET /extract_runs?batchId={batchId}
GET /classify_runs?batchId={batchId}
GET /split_runs?batchId={batchId}
```