# Extract, split and classify
Source: https://docs.file.ai/extract/split-classify

> Send one document, get back extracted values, split boundaries or a document type as an async job.

fileScout

# Extract, split and classify

Copy pageCopy page

Send one document, get back extracted values, split boundaries or a document type as an async job.

Copy pageCopy page

## 

[​

](#what-it-does)

What it does

`POST /v1/extract`, `/v1/split` and `/v1/classify` each take a single document in the request and process it asynchronously. Each returns `202 Accepted` with a `job_id` straight away; you read the result from `GET /v1/jobs/{job_id}` or receive it by webhook.

## 

[​

](#when-to-use-it)

When to use it

*   You need to pull fields out of one document, with or without your own schema, without setting up schemas or folders in a project: `POST /v1/extract`.
*   You receive one PDF that holds several documents and need to find where each one starts and ends: `POST /v1/split`.
*   You need to identify what kind of document a file is, optionally against your own list of candidate types: `POST /v1/classify`.

To store files, classify them into your file types and keep the values, use [Uploads](/ingest/uploads) and [AI Schemas](/extract/ai-schemas) instead.

## 

[​

](#how-it-works)

How it works

1

Submit

Send the document as `multipart/form-data` in the `file` field, with any options as form fields. You get `202` with `job_id`, `status: "queued"` and `poll_url`.

2

Poll or wait

Poll `poll_url` (`GET /v1/jobs/{job_id}`) until `status` is `succeeded` or `failed`. Or pass `callback_url` to receive the `extraction.job.settled` webhook. Keep polling as a fallback: the job is durable, a webhook delivery may not be. [Async jobs](/api/async-jobs) covers both.

3

Read the result

On `succeeded`, read `result`. On `failed`, read `error.code` and `error.detail`. `usage` shows the `pages` and `credits` the job used.

## 

[​

](#try-it)

Try it

Split a shipment PDF into two documents:

cURL

Python

Node.js

```
curl -X POST "$FILEAI_BASE_URL/split" \
  -H "x-api-key: $FILEAI_API_KEY" \
  -F "file=@shipment.pdf" \
  -F 'ranges=[[1,3],[4,6]]' \
  -F "client_ref=shipment-8812"
```

```
import os, requests

BASE = "https://api.orion.file.ai/prod/v1"
HEADERS = {"x-api-key": os.environ["FILEAI_API_KEY"]}

with open("shipment.pdf", "rb") as f:
    job = requests.post(
        f"{BASE}/split",
        headers=HEADERS,
        files={"file": ("shipment.pdf", f, "application/pdf")},
        data={"ranges": "[[1,3],[4,6]]", "client_ref": "shipment-8812"},
    ).json()
```

```
import { readFile } from "node:fs/promises";

const BASE = "https://api.orion.file.ai/prod/v1";
const form = new FormData();
form.append("file", new Blob([await readFile("shipment.pdf")], { type: "application/pdf" }), "shipment.pdf");
form.append("ranges", "[[1,3],[4,6]]");
form.append("client_ref", "shipment-8812");

const job = await fetch(`${BASE}/split`, {
  method: "POST",
  headers: { "x-api-key": process.env.FILEAI_API_KEY },
  body: form,
}).then((r) => r.json());
```

## 

[​

](#understand-the-result)

Understand the result

The submit call returns straight away:

202 Accepted

```
{
  "job_id": "job_4b7e8d4c1fa0b39f2c1a",
  "status": "queued",
  "created_at": "2026-09-25T02:14:00.000Z",
  "poll_url": "https://api.orion.file.ai/prod/v1/jobs/job_4b7e8d4c1fa0b39f2c1a"
}
```

*   `job_id`: the job to poll. Document jobs have a `job_` prefix.
*   `poll_url`: the `GET /v1/jobs/{job_id}` URL. It is a URI reference: if it comes back without a scheme and host, resolve it against the host you called.

Then poll:

```
curl "$FILEAI_BASE_URL/jobs/job_4b7e8d4c1fa0b39f2c1a" \
  -H "x-api-key: $FILEAI_API_KEY"
```

Illustrative: shape from the API reference

```
{
  "job_id": "job_4b7e8d4c1fa0b39f2c1a",
  "kind": "extraction",
  "status": "succeeded",
  "created_at": "2026-09-25T02:14:00.000Z",
  "updated_at": "2026-09-25T02:14:20.000Z",
  "client_ref": "shipment-8812",
  "result": { "documents": [ … ] },
  "usage": { "pages": 6, "credits": … }
}
```

Field

Meaning

`kind`

`extraction` for a document job. Branch on it first: the same route also returns agent jobs.

`status`

`queued` (poll again), `succeeded` or `failed` (both final). See [Async jobs](/api/async-jobs).

`result`

When `succeeded`. For a split, `result.documents` holds the page range of each document.

`error`

When `failed`: `error.code` and `error.detail`.

`usage`

Once settled: the `pages` and `credits` the job used.

`client_ref`

Your reference, echoed back when you sent one.

## 

[​

](#next-steps)

Next steps

## Async jobs

Polling and webhooks across fileAI’s async APIs.

## fileForensics

Check a stored file for editing and AI generation.

## Errors

Problem responses, including 413, 415 and 422.

## Extract with AI Schemas

Keep values in a project instead of one-shot jobs.

## 

[​

](#reference)

Reference

### 

[​

](#choose-an-endpoint)

Choose an endpoint

You want to…

Use

Pull fields out of one document, with or without your own schema

`POST /v1/extract`

Find where one PDF holds several documents

`POST /v1/split`

Identify what kind of document a file is

`POST /v1/classify`

Store files, classify them into your file types and keep the values

[Uploads](/ingest/uploads) and [AI Schemas](/extract/ai-schemas)

Check a stored file for signs of manipulation

[fileForensics](/forensics/overview)

### 

[​

](#modes)

Modes

Every option is a form field, so structured options (`schema`, `ranges`, `schemas`) are sent as **JSON strings**. A blank field counts as omitted. The fields you send select the mode:

Operation

Fields sent

Mode

Extract

none

fileAI generates a schema and returns it under `result.schema` with `generated: true`.

Extract

`schema`

Extracts against your schema.

Split

none

Automatic split: fileAI finds the document boundaries.

Split

`custom_instruction`

Guided split, e.g. `"group the invoice and packing list as one document"`.

Split

`ranges`

Deterministic split on 1-indexed, inclusive page ranges, e.g. `[[1,3],[4,6]]`.

Classify

none

Open classification: fileAI proposes document types.

Classify

`schemas`

Closed-set classification against your candidate types.

Sending both `custom_instruction` and `ranges` is a `422`. Classify has no free-text instruction field. Classify against two candidate types:

```
curl -X POST "$FILEAI_BASE_URL/classify" \
  -H "x-api-key: $FILEAI_API_KEY" \
  -F "file=@scan.pdf" \
  -F 'schemas=[{"document_type":"invoice"},{"document_type":"packing_list"}]'
```

### 

[​

](#request)

Request

Constraint

Value

Content type

`multipart/form-data`, document in `file`

Accepted MIME types

`application/pdf`, `image/png`, `image/jpeg`, `image/tiff`

Type check

The file’s leading bytes must match its declared type. A mismatch is a `415`.

Max size

50 MB per document. Larger is a `413`.

Missing `file`

`400`

Fields every operation accepts:

Field

Rules

`callback_url`

An HTTPS URL that receives the `extraction.job.settled` webhook. Any other scheme is a `422`.

`client_ref`

Your own reference, up to 256 characters, echoed on the job and the webhook.

Operation-specific fields:

Operation

Field

Rules

Extract

`schema`

JSON object, up to 100,000 characters. Needs `document_type`; optional `form_fields` and `tables`. Each form field needs `field_name`, `field_type` and 1-indexed `page_index`.

Extract

`pipeline`

Reserved for contracted pipelines. Leave it out unless fileAI has given you a value; an unknown value is a `422`.

Extract

`include_ocr`

`true` adds per-page OCR output under `result.pages`. Default `false`.

Extract

`provider`

Optional model hint. Only `gemini` is accepted.

Split

`custom_instruction`

Up to 4,000 characters.

Split

`ranges`

Up to 1,000 `[start, end]` integer pairs, 1-indexed, `start` ≤ `end`, non-overlapping, and within the document’s page count.

Classify

`schemas`

Non-empty JSON array of up to 200 candidates, up to 100,000 characters. Each needs `document_type`; `summary` (string) and `tags` (string array) are optional. Any other key is a `422`.

An extraction `schema` that is valid JSON but does not match the expected shape is accepted at submit time. The job then settles as `failed`, with the validation errors in `error.detail`.

These endpoints ignore the `Idempotency-Key` header. See [Idempotency](/api/idempotency).

### 

[​

](#job)

Job

`GET /v1/jobs/{job_id}` returns a document job with `kind: "extraction"` and a `job_` id prefix. Its statuses and fields are listed in [Understand the result](#understand-the-result); [Async jobs](/api/async-jobs) has the full status table. Where to read the result:

Operation

Result

Extract

Extracted values. `result.schema` is the schema used (`generated: true` when fileAI made it). `result.pages` holds OCR output if you sent `include_ocr=true`.

Split

`result.documents`, with the page range of each document.

Classify

`result.document_class`, the primary classification.

`poll_url` is a URI reference. If it comes back without a scheme and host, resolve it against the host you called. The same route also returns agent jobs (`kind: "agent"`, `sajob_` prefix), which use different statuses. Branch on `kind` first. See [Agent sessions](/ask/agent-sessions).

[Previous](/extract/ai-schemas)[

Get results

The payload fileAI POSTs to your callback URL as each processing step of an upload finishes.

Next

](/deliver/callbacks)

⌘I

## On this page

*   [What it does](#what-it-does)
*   [When to use it](#when-to-use-it)
*   [How it works](#how-it-works)
*   [Try it](#try-it)
*   [Understand the result](#understand-the-result)
*   [Next steps](#next-steps)
*   [Reference](#reference)
    *   [Choose an endpoint](#choose-an-endpoint)
    *   [Modes](#modes)
    *   [Request](#request)
    *   [Job](#job)
