> This page is for version v2026-02-09 (default).
> For other versions, use one of these documentation indexes:
> - v2026-02-09 (default): https://docs.extend.ai/2026-02-09/llms.txt
> - v2025-04-21: https://docs.extend.ai/2025-04-21/llms.txt
> - v2024-12-23: https://docs.extend.ai/2024-12-23/llms.txt

> ## 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.

# Splitting Overview

> Split breaks a multi-document file into separate, typed sub-documents with page ranges and standalone file IDs. Learn how it works, then run it in minutes.

**Splitting** takes a single file that bundles many documents and breaks it into separate, typed sub-documents. You describe the document types you expect with `splitClassifications`, and Extend returns one entry per detected sub-document with its type, page range, and a standalone `fileId` you can feed into parse, extract, or a workflow. Use it for loan packages, claim files, closing binders, and any multi-document upload that needs to be separated before processing.

Split runs [Parse](/parsing/overview) under the hood, parsing the file first if it hasn't been parsed already and reusing the existing parsed output if it has.

## Quick start

We'll split a Uniform Residential Loan Application (Form 1003) into its sections — Section 1 spans two pages, and the rest are single pages. For this quick-start we've uploaded the file [here.](https://extend-public-files.s3.us-east-2.amazonaws.com/loan_application.pdf)

![First page of a loan application packet](/_fern-img/9d1103b44a655ffb796d63c6a646de16ecc14b7618c7dd2b2519a2cc08bea2ee.webp)

Grab a key from the [Developers](https://dashboard.extend.ai/developers) page and store it as the `EXTEND_API_KEY` environment variable. If you're using an SDK, see the [installation instructions](/sdks).

```bash
export EXTEND_API_KEY="your_api_key_here"
```

The `/split` endpoint takes a `file` and a `config` with the `splitClassifications` you expect.

#### Python

```python
from extend_ai import Extend

client = Extend()

result = client.split(
    file={
        "url": "https://extend-public-files.s3.us-east-2.amazonaws.com/loan_application.pdf",
    },
    config={
        "baseProcessor": "splitting_performance",
        "splitClassifications": [
            {
                "id": "section_1",
                "type": "section_1",
                "description": "Section 1, Borrower Information: personal details, current and previous employment, and income.",
            },
            {
                "id": "section_2",
                "type": "section_2",
                "description": "Section 2, Financial Information — Assets and Liabilities: bank and retirement accounts, other assets, liabilities, and expenses.",
            },
            {
                "id": "section_3",
                "type": "section_3",
                "description": "Section 3, Financial Information — Real Estate: properties owned and the mortgage loans on them.",
            },
            {
                "id": "other",
                "type": "other",
                "description": "Any other section of the loan application (loan and property information, declarations, acknowledgments, military service, demographic information, or loan originator details).",
            },
        ],
    },
)

print(result)
```

#### TypeScript

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

const client = new ExtendClient();

const result = await client.split({
  file: {
    url: "https://extend-public-files.s3.us-east-2.amazonaws.com/loan_application.pdf",
  },
  config: {
    baseProcessor: "splitting_performance",
    splitClassifications: [
      {
        id: "section_1",
        type: "section_1",
        description:
          "Section 1, Borrower Information: personal details, current and previous employment, and income.",
      },
      {
        id: "section_2",
        type: "section_2",
        description:
          "Section 2, Financial Information — Assets and Liabilities: bank and retirement accounts, other assets, liabilities, and expenses.",
      },
      {
        id: "section_3",
        type: "section_3",
        description:
          "Section 3, Financial Information — Real Estate: properties owned and the mortgage loans on them.",
      },
      {
        id: "other",
        type: "other",
        description:
          "Any other section of the loan application (loan and property information, declarations, acknowledgments, military service, demographic information, or loan originator details).",
      },
    ],
  },
});

console.log(result);
```

#### Java

```java
import ai.extend.ExtendClient;
import ai.extend.requests.SplitRequest;
import ai.extend.types.FileFromUrl;
import ai.extend.types.SplitBaseProcessor;
import ai.extend.types.SplitClassification;
import ai.extend.types.SplitConfig;
import ai.extend.types.SplitRequestFile;
import ai.extend.types.SplitRun;
import java.util.List;

ExtendClient client = ExtendClient.builder().build();

SplitRun result = client.split(SplitRequest.builder()
    .file(SplitRequestFile.of(FileFromUrl.builder()
        .url("https://extend-public-files.s3.us-east-2.amazonaws.com/loan_application.pdf")
        .build()))
    .config(SplitConfig.builder()
        .baseProcessor(SplitBaseProcessor.SPLITTING_PERFORMANCE)
        .splitClassifications(List.of(
            SplitClassification.builder()
                .id("section_1")
                .type("section_1")
                .description("Section 1, Borrower Information: personal details, current and previous employment, and income.")
                .build(),
            SplitClassification.builder()
                .id("section_2")
                .type("section_2")
                .description("Section 2, Financial Information — Assets and Liabilities: bank and retirement accounts, other assets, liabilities, and expenses.")
                .build(),
            SplitClassification.builder()
                .id("section_3")
                .type("section_3")
                .description("Section 3, Financial Information — Real Estate: properties owned and the mortgage loans on them.")
                .build(),
            SplitClassification.builder()
                .id("other")
                .type("other")
                .description("Any other section of the loan application (loan and property information, declarations, acknowledgments, military service, demographic information, or loan originator details).")
                .build()))
        .build())
    .build());

System.out.println(result);
```

#### Go

```go
package main

import (
	"context"
	"fmt"
	"log"

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

func main() {
	c := client.NewClient()

	result, err := c.Split(context.TODO(), &extend.SplitRequest{
		File: &extend.SplitRequestFile{
			FileFromURL: &extend.FileFromURL{
				URL: "https://extend-public-files.s3.us-east-2.amazonaws.com/loan_application.pdf",
			},
		},
		Config: &extend.SplitConfig{
			SplitClassifications: []*extend.SplitClassification{
				{
					ID:          "section_1",
					Type:        "section_1",
					Description: "Section 1, Borrower Information: personal details, current and previous employment, and income.",
				},
				{
					ID:          "section_2",
					Type:        "section_2",
					Description: "Section 2, Financial Information — Assets and Liabilities: bank and retirement accounts, other assets, liabilities, and expenses.",
				},
				{
					ID:          "section_3",
					Type:        "section_3",
					Description: "Section 3, Financial Information — Real Estate: properties owned and the mortgage loans on them.",
				},
				{
					ID:          "other",
					Type:        "other",
					Description: "Any other section of the loan application (loan and property information, declarations, acknowledgments, military service, demographic information, or loan originator details).",
				},
			},
		},
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(result)
}
```

#### cURL

```bash
curl -X POST https://api.extend.ai/split \
  -H "x-extend-api-version: 2026-02-09" \
  -H "Authorization: Bearer $EXTEND_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "file": {
      "url": "https://extend-public-files.s3.us-east-2.amazonaws.com/loan_application.pdf"
    },
    "config": {
      "baseProcessor": "splitting_performance",
      "splitClassifications": [
        { "id": "section_1", "type": "section_1", "description": "Section 1, Borrower Information: personal details, current and previous employment, and income." },
        { "id": "section_2", "type": "section_2", "description": "Section 2, Financial Information — Assets and Liabilities: bank and retirement accounts, other assets, liabilities, and expenses." },
        { "id": "section_3", "type": "section_3", "description": "Section 3, Financial Information — Real Estate: properties owned and the mortgage loans on them." },
        { "id": "other", "type": "other", "description": "Any other section of the loan application (loan and property information, declarations, acknowledgments, military service, demographic information, or loan originator details)." }
      ]
    }
  }'
```

> **Tip**
>
> Want to split your own document? [Upload it](/api-reference/endpoints/file/upload-file) first, then pass the returned file `id` instead of a `url` (reusing the same `config`).
>
> #### Python
>
> ```python
> with open("loan_application.pdf", "rb") as f:
>     uploaded = client.files.upload(file=f)
>
> result = client.split(file={"id": uploaded.id}, config=config)
> ```
>
> #### TypeScript
>
> ```typescript
> import { createReadStream } from "fs";
>
> const uploaded = await client.files.upload(createReadStream("loan_application.pdf"), {});
>
> const result = await client.split({ file: { id: uploaded.id }, config });
> ```
>
> #### Java
>
> ```java
> import ai.extend.requests.FilesUploadRequest;
> import ai.extend.types.File;
> import ai.extend.types.FileFromId;
>
> File uploaded = client.files().upload(
>     new java.io.File("loan_application.pdf"),
>     FilesUploadRequest.builder().build());
>
> SplitRun result = client.split(SplitRequest.builder()
>     .file(SplitRequestFile.of(FileFromId.builder().id(uploaded.getId()).build()))
>     .config(config) // the SplitConfig from above
>     .build());
> ```
>
> #### Go
>
> ```go
> f, err := os.Open("loan_application.pdf")
> if err != nil {
> 	log.Fatal(err)
> }
> defer f.Close()
>
> uploaded, err := c.Files.Upload(context.TODO(), f, &extend.FilesUploadRequest{})
> if err != nil {
> 	log.Fatal(err)
> }
>
> result, err := c.Split(context.TODO(), &extend.SplitRequest{
> 	File:   &extend.SplitRequestFile{FileFromID: &extend.FileFromID{ID: uploaded.ID}},
> 	Config: config, // the *extend.SplitConfig from above
> })
> ```
>
> #### cURL
>
> ```bash
> # Upload the file to get an id
> curl -X POST https://api.extend.ai/files/upload \
>   -H "Authorization: Bearer $EXTEND_API_KEY" \
>   -H "x-extend-api-version: 2026-02-09" \
>   -F "file=@loan_application.pdf"
>
> # Then split using the returned id
> curl -X POST https://api.extend.ai/split \
>   -H "Authorization: Bearer $EXTEND_API_KEY" \
>   -H "x-extend-api-version: 2026-02-09" \
>   -H "Content-Type: application/json" \
>   -d '{ "file": { "id": "file_xK9mLPqRtN3vS8wF5hB2cQ" }, "config": { "splitClassifications": [{ "id": "other", "type": "other", "description": "Any other document type." }] } }'
> ```

### Example response

After you run the code snippet above, you'll see a response like this. Extend parses the document, finds each section, and returns an `output.splits` array — one entry per detected sub-document with its `type`, page range, and a `fileId` you can process further. (Truncated to the first two splits.)

```json
{
  "object": "split_run",
  "id": "splr_Xj8mK2pL9nR4vT7qY5wZ",
  "status": "PROCESSED",
  "file": {
    "object": "file",
    "id": "file_GzKUy0VDhHscv7tweODYb",
    "name": "loan_application.pdf"
  },
  "output": {
    "splits": [
      {
        "id": "splt_xK9mLPqRtN3vS8wF5hB2cQ",
        "classificationId": "section_1",
        "type": "section_1",
        "startPage": 1,
        "endPage": 2,
        "identifier": "",
        "observation": "Pages 1-2 contain Section 1: Borrower Information.",
        "fileId": "file_8sLPqRtN3vS2wF5hB2cQ"
      },
      {
        "id": "splt_2pL9nR4vT7qY5wZj8mK2",
        "classificationId": "section_2",
        "type": "section_2",
        "startPage": 3,
        "endPage": 3,
        "identifier": "",
        "observation": "Page 3 contains Section 2: Financial Information — Assets and Liabilities.",
        "fileId": "file_R4vT7qY5wZj8mK2pL9nR"
      }
    ]
  }
}
```

### Key fields

| Field                            | What it contains                                                                      |
| -------------------------------- | ------------------------------------------------------------------------------------- |
| `output.splits`                  | One entry per detected sub-document.                                                  |
| `splits[].classificationId`      | The `id` of the classification that matched. Branch your logic on this — it's stable. |
| `splits[].type`                  | The document type, matching a classification you defined.                             |
| `splits[].startPage` / `endPage` | The 1-based page range of the sub-document.                                           |
| `splits[].identifier`            | The extracted identifier, when the classification set an `identifierKey`.             |
| `splits[].fileId`                | A standalone file for the sub-document, usable as input to other endpoints.           |

For full request/response details, see the [Create Split Run API reference](/api-reference/endpoints/split/create-split-run).

### Use the output

Walk `output.splits` to read each sub-document's type and page range, and use its `fileId` to process the piece — for example, sending a specific section to Extract. Branch your logic on `classificationId` rather than `type`: the `classificationId` is the stable `id` you defined, while `type` and `description` are part of the prompt that steers the split and may change as you tune accuracy.

#### Python

```python
for split in result.output.splits:
    print(f"{split.type}: pages {split.start_page}-{split.end_page}")

# Each split is a standalone file you can process further
for split in result.output.splits:
    if split.classification_id == "section_2":
        client.extract(file={"id": split.file_id}, config={"schema": {...}})
```

#### TypeScript

```typescript
for (const split of result.output?.splits ?? []) {
  console.log(`${split.type}: pages ${split.startPage}-${split.endPage}`);
}

// Each split is a standalone file you can process further
for (const split of result.output?.splits ?? []) {
  if (split.classificationId === "section_2") {
    await client.extract({ file: { id: split.fileId }, config: { schema: {} } });
  }
}
```

#### Java

```java
for (var split : result.getOutput().get().getSplits()) {
    System.out.println(split.getType() + ": pages "
        + split.getStartPage() + "-" + split.getEndPage());
}
```

#### Go

```go
for _, split := range result.Output.Splits {
	fmt.Printf("%s: pages %d-%d\n", split.Type, split.StartPage, split.EndPage)
}
```

For the full shape, including every field on each split, see [Response Format](/splitting/response-format).

## Sync vs async

The example above calls the synchronous `/split` endpoint. We also have an asynchronous `/split_runs` endpoint that should be used for large files and high volume use cases.

See [Async Processing](/general/async-processing) for the full comparison, polling options, and webhook setup.

## Save it as a processor

The quick start runs with an inline `config`, which is perfect for getting started. To reuse a configuration across runs — and to version it, measure its accuracy, and optimize it — save it as a **splitter**, a kind of [processor](/evaluation/processors). Processors are the saved entities you iterate on in the dashboard, run [evaluation sets](/evaluation/overview) against, and improve with [Composer](/optimization/composer).

## Configuration

The quick start sends `file` and `config.splitClassifications`. To control how splitting runs, pass more options inside `config`. Here are the most commonly used ones; for the full reference, see [Configuration](/splitting/configuration).

### Split classifications

The `splitClassifications` define the document types the splitter can assign. Provide at least one, and at least one must have the type `"other"` as a catch-all. The `description` on each is your biggest lever on accuracy.

```json
{
  "config": {
    "splitClassifications": [
      { "id": "invoice", "type": "invoice", "description": "An invoice or bill for goods or services." },
      { "id": "other", "type": "other", "description": "Any other document type." }
    ]
  }
}
```

### Identifier keys

Add an `identifierKey` to a classification to extract a unique identifier (like an invoice number or borrower name) from each sub-document of that type. The value is returned in each split's `identifier`, and the splitter uses it to decide when adjacent pages belong to the same document.

```json
{
  "config": {
    "splitClassifications": [
      { "id": "invoice", "type": "invoice", "description": "An invoice.", "identifierKey": "The invoice number from the header." }
    ]
  }
}
```

Turn on [`advancedOptions.strictIdentifierModeEnabled`](/splitting/configuration) to go further and merge every adjacent sub-document that shares an identifier into a single split — one split per invoice number, however many page groups it was drafted as.

### Split rules

Steer how the document is divided with plain-language `splitRules` — for example, keeping multi-page contracts together.

```json
{ "config": { "splitRules": "Keep all pages of a signed contract together in a single split." } }
```

### Base processor

Choose the splitting model based on your accuracy and latency needs.

```json
{ "config": { "baseProcessor": "splitting_performance" } }
```

| Processor               | When to use                 |
| ----------------------- | --------------------------- |
| `splitting_performance` | Highest accuracy (default). |
| `splitting_light`       | Faster and cheaper.         |

> **Note**
>
> For every option, including advanced options and parse configuration, see the [Configuration](/splitting/configuration) reference.

---

## Next steps

#### [Configuration](/splitting/configuration)

Split classifications, identifier keys, rules, and the base processor.

#### [Response Format](/splitting/response-format)

The full shape of the split run and the splits array.

#### [Workflows](/workflows/overview)

Route each split sub-document to the right processor automatically.

#### [API Reference](/api-reference/endpoints/split/create-split-run)

Full request and response schema for the split endpoint.