Batch Processing

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:

OperationCreate batchGet batch status
ParsePOST /parse_runs/batchGET /batch_runs/{id}
ExtractPOST /extract_runs/batchGET /batch_runs/{id}
ClassifyPOST /classify_runs/batchGET /batch_runs/{id}
SplitPOST /split_runs/batchGET /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 with polling or webhooks are the right choice.

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

1import { ExtendClient } from "extend-ai";
2
3const client = new ExtendClient({ token: "YOUR_API_KEY" });
4
5const batch = await client.parseRuns.createBatch({
6 // config is optional — omit to use default parse settings
7 inputs: [
8 {
9 file: { url: "https://example.com/document1.pdf" },
10 metadata: { customerId: "cust_abc123" },
11 },
12 {
13 file: { url: "https://example.com/document2.pdf" },
14 metadata: { customerId: "cust_def456" },
15 },
16 {
17 file: { id: "file_ghi789" }, // previously uploaded Extend file ID
18 },
19 {
20 file: { text: "Raw text content to parse." }, // raw text also supported
21 },
22 ],
23});
24
25console.log(batch.id); // "bpar_Xj8mK2pL9nR4vT7qY5wZ"
26console.log(batch.status); // "PENDING"
27
28// Poll the batch status
29const status = await client.batchRuns.get(batch.id);
30console.log(status.status); // "PENDING" | "PROCESSING" | "PROCESSED" | "FAILED" | "CANCELLED"
31console.log(status.runCount); // number of individual runs created

Batch extraction

1import { ExtendClient } from "extend-ai";
2
3const client = new ExtendClient({ token: "YOUR_API_KEY" });
4
5const batch = await client.extractRuns.createBatch({
6 extractor: {
7 id: "ex_xK9mLPqRtN3vS8wF5hB2cQ",
8 // version: "1.0", // optional — defaults to "latest"
9 // overrideConfig: { ... }, // optional — partial config override
10 },
11 inputs: [
12 {
13 file: { url: "https://example.com/invoice1.pdf" },
14 metadata: { customerId: "cust_abc123" },
15 },
16 {
17 file: { url: "https://example.com/invoice2.pdf" },
18 metadata: { customerId: "cust_def456" },
19 },
20 {
21 file: { id: "file_ghi789" }, // previously uploaded Extend file ID
22 },
23 ],
24});
25
26console.log(batch.id); // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
27console.log(batch.status); // "PENDING"
28
29// Poll the batch status
30const status = await client.batchRuns.get(batch.id);
31console.log(status.status); // "PENDING" | "PROCESSING" | "PROCESSED" | "FAILED" | "CANCELLED"
32console.log(status.runCount); // number of individual runs created

Batch classification

1import { ExtendClient } from "extend-ai";
2
3const client = new ExtendClient({ token: "YOUR_API_KEY" });
4
5const batch = await client.classifyRuns.createBatch({
6 classifier: {
7 id: "cl_xK9mLPqRtN3vS8wF5hB2cQ",
8 // version: "2.0", // optional — defaults to "latest"
9 // overrideConfig: { ... }, // optional — partial config override
10 },
11 inputs: [
12 {
13 file: { url: "https://example.com/document1.pdf" },
14 metadata: { source: "email-inbox" },
15 },
16 {
17 file: { url: "https://example.com/document2.pdf" },
18 metadata: { source: "upload-portal" },
19 },
20 ],
21});
22
23console.log(batch.id); // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
24console.log(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: "..." }).

1import { ExtendClient } from "extend-ai";
2
3const client = new ExtendClient({ token: "YOUR_API_KEY" });
4
5const batch = await client.splitRuns.createBatch({
6 splitter: {
7 id: "spl_xK9mLPqRtN3vS8wF5hB2cQ",
8 // version: "1.0", // optional — defaults to "latest"
9 // overrideConfig: { ... }, // optional — partial config override
10 },
11 inputs: [
12 {
13 file: { url: "https://example.com/multi-doc1.pdf" },
14 metadata: { batchRef: "daily-run-2026-04-07" },
15 },
16 {
17 file: { url: "https://example.com/multi-doc2.pdf" },
18 metadata: { batchRef: "daily-run-2026-04-07" },
19 },
20 ],
21});
22
23console.log(batch.id); // "bpr_Xj8mK2pL9nR4vT7qY5wZ"
24console.log(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):

EventDescription
batch_parse_run.processedTriggered when a batch parse run has finished processing
batch_parse_run.failedTriggered when a batch parse run has failed

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

EventDescription
batch_processor_run.processedTriggered when a batch has finished processing
batch_processor_run.failedTriggered when a batch has failed

See Webhook 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):

$GET /batch_runs/{batchId}

The batch status field reflects the aggregate state:

StatusMeaning
PENDINGQueued, not yet started
PROCESSINGRuns are actively being processed
PROCESSEDAll runs have completed
FAILEDThe batch encountered a fatal error
CANCELLEDThe batch was cancelled

Fetching individual results

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

$GET /parse_runs?batchId={batchId}
$GET /extract_runs?batchId={batchId}
$GET /classify_runs?batchId={batchId}
$GET /split_runs?batchId={batchId}