> For a complete page index of the Captain API documentation, fetch https://docs.captain.dev/llms.txt?excludeSpec=true

# Documents

> How Captain indexes PDF and Word files. Basic, advanced or automatic processing, layout-labelled chunks with page ranges, tables and figures kept as searchable text, and block-level citations.

## Agent Quick Reference - Documents

* Extensions: `.pdf`, `.docx`, `.doc`. Word files are converted to PDF first, then parsed the same way. Extensionless files from connectors are sniffed by content type and magic bytes.
* `processing_type` is required per job: `basic` (layout-aware parse with OCR on scanned regions, 1 credit per page), `advanced` (adds a vision pass over the text for handwriting and faded print, table reconstruction with merged cells and nested headers, figure descriptions and verified chart values, 2.5 credits per page) or `auto` (Captain inspects each PDF or DOCX and parses it with `advanced` when it has a photo or drawing covering at least 4% of a page, a ruled or bordered table, or a scanned page, otherwise with `basic`; each file is billed at the tier it used). Logos, signatures, letterheads and borderless layout tables do not count. In PDFs, charts drawn without an image are not detected. Legacy `.doc` files use `advanced`.
* Every chunk carries `chunk_type`, one of `body`, `table`, `heading`, `page_header`, `page_footer`, `footnote`, `figure`, and a page range `metadata.pageStart` / `metadata.pageEnd`. Drop roles at query time with `exclude_chunk_types`.
* Structure: sections of up to 40,000 tokens, each with a generated `summary` (2 to 3 sentences) and 8 to 15 `tags`; sections are tiled into passages of about 250 tokens that are embedded. Passages never mix a heading or footer into body text.
* Tables are kept as text inside the chunk (HTML tables in `advanced`), so cell values are searchable. Figures are described; chart numbers are stored only when they can be verified, otherwise the block is marked `extraction: "unavailable"`.
* Citations: `include.regions` returns each block's `page`, `bbox` (`top`, `left`, `width`, `height`, 0 to 1), `type` and `confidence`. `GET /v2/collections/{c}/documents/{id}/pages/{n}` returns one page's text.
* Documents of 75 pages or more are parsed in parallel 75-page ranges. No page cap; the upload route's size limit is the only ceiling. A file that fails is a per-file error on the job record; the rest of the batch continues.
* `mask_pii` masks chunk text, block regions and figure crops, and fails closed. The report at `GET /v2/jobs/{id}/pii` gives block-level boxes.

Captain indexes PDF and Word files as chunks that keep their layout role and page range.
This page covers the processing tiers, how a document is chunked, what a result
contains, and the limits.

## This is useful for

* Contracts and policies, where a clause needs a page number and a highlight box to cite
* Scanned invoices, forms and correspondence at volume, where OCR text has to be searchable
* Reports and decks, where headings, tables and charts should be returned as separate blocks
* Any file a reader will open at the right page rather than read in a snippet

## Processing tiers

Every document job sets `processing_type` to `basic`, `advanced` or `auto`.

| Tier       | What it does                                                                                                                                                                                                                                                            | Credits                                       |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
| `basic`    | Layout-aware parse of the text layer, with OCR on scanned or image regions. Use for clean, born-digital files and high volume.                                                                                                                                          | 1 per page                                    |
| `advanced` | Everything in `basic`, plus a vision pass over the text (handwriting, faded print, unusual characters), table reconstruction that keeps merged cells and nested headers, and figure handling that describes images and extracts chart values when they can be verified. | 2.5 per page                                  |
| `auto`     | Captain inspects each file before parsing and uses `advanced` for files that need it and `basic` for the rest. Use for mixed collections where only some files have pictures, tables or scans.                                                                          | 1 or 2.5 per page, by the tier each file used |

### How `auto` picks a tier

Captain reads the structure of each PDF without parsing it. A file is parsed with
`advanced` when any page has one of these:

* A photo or drawing that covers at least 4% of the page. Logos, signatures and icons are
  smaller than that and do not count. An image that repeats on most pages, such as a
  letterhead, does not count either.
* A table drawn with ruled lines, with at least two columns and two rows of content. Empty
  form grids do not count.
* A scanned page: an image covering most of the page with almost no text layer.

Every other file is parsed with `basic`. A file that cannot be inspected, such as a
password-protected PDF, is parsed with `advanced`. In a PDF, charts drawn as shapes rather
than an image are not detected, so index those files with `advanced` if you need their
values.

Word files (`.docx`) are inspected the same way, from the document itself. A picture,
chart or diagram that covers at least 4% of the page, or a table with visible borders,
sends the file to `advanced`. Pictures in headers and footers, such as logos, do not
count, and neither do tables without borders, such as signature blocks. Legacy `.doc` files
are parsed with `advanced`.

Each file is billed at the tier it used. The job's `billing.credits` reports
`used_basic` and `used_advanced` separately.

Parse Document (`POST /v3/parse/documents`) takes the same `auto` value and reports the
pages each tier used in `usage.pages_basic` and `usage.pages_advanced`.

Word files are converted to PDF before either tier runs, so `.docx` and `.doc` are handled
exactly like PDFs from that point, page ranges included.

## How a document is chunked

#### Layout roles

Each block of the page is labelled with a role: `body`, `table`, `heading`,
`page_header`, `page_footer`, `footnote` or `figure`. Blocks with different roles are
never packed into the same passage. This keeps running headers and footers out of body
text, so a query for "confidential" does not match the stamp at the top of every page.
Use `exclude_chunk_types` on a query to drop roles you do not want in results.

#### Sections and passages

The document is split into sections of up to 40,000 tokens. Each section gets a generated
summary of two or three sentences and 8 to 15 tags. Each section is then tiled into
passages of about 250 tokens, and the passages are what the search matches. A result
contains the passage and its section's summary, so a hit on one clause also says which
part of the document it belongs to. Passages do not overlap.

#### Context across section boundaries

When a document spans several sections, the next section starts with a short summary of
the previous one. A clause that crosses the boundary is readable from either side.

#### Tables and figures

Tables are stored as text inside the chunk (HTML tables in `advanced`), so cell values are
searchable. Figures are described in words. Chart values are stored only when the
extraction can be verified against the image; otherwise the figure is kept with
`extraction: "unavailable"` and no values.

#### Page ranges and regions

Every result carries `location.page_start` and `location.page_end`. Add
`include.regions` to get the blocks behind a result, each with `page`, a normalised
`bbox` (`top`, `left`, `width`, `height` from 0 to 1), `type` and `confidence`. To show a
page, call `GET /v2/collections/{collection}/documents/{document_id}/pages/{page_number}`.

## Limits and failures

Documents of 75 pages or more are parsed in parallel, 75 pages at a time. There is no page
cap. The only size ceiling is the one on the route the file arrived by (see
[File Size Limits](/guides/file-size-limits)). A document that cannot be parsed fails on its
own: the error is recorded on that file in the job and the rest of the batch continues. Both
tiers run OCR; language detection is automatic.

With `mask_pii` on, Captain masks the chunk text, the block regions and any figure crops. If
masking fails, the document is not indexed. The report at `GET /v2/jobs/{job_id}/pii` lists
what was found, with block-level boxes. See [PII Masking](/guides/pii-masking).

## Examples

#### Find a clause and highlight it in a viewer

Goal: return the termination clause from a set of contracts indexed with `advanced`,
with the box to draw on the page.

**`request`**

```json title="request"
{
  "query": "termination for convenience notice period",
  "limit": 5,
  "include": {
    "regions": true,
    "document": true
  },
  "exclude_chunk_types": [
    "page_header",
    "page_footer"
  ]
}
```

**`result (one item)`**

```json title="result (one item)"
{
  "text": "Either party may terminate this Agreement for convenience on ninety (90) days written notice...",
  "chunk_type": "body",
  "document": {
    "id": "…",
    "name": "MSA-2026-Acme.pdf"
  },
  "location": {
    "page_start": 14,
    "page_end": 14
  },
  "regions": [
    {
      "type": "body",
      "page": 14,
      "bbox": {
        "top": 0.42,
        "left": 0.12,
        "width": 0.76,
        "height": 0.09
      },
      "confidence": 0.97
    }
  ]
}
```

The clause is one `body` passage with its own page range. `regions[0].bbox` is the
rectangle to highlight.

#### Scanned invoices at volume

Goal: make invoice numbers and totals searchable across thousands of scans at the lowest
cost. Index with `basic`; OCR runs on the scanned regions at 1 credit per page. Move a
supplier to `advanced` when its invoices have handwritten annotations or dense line-item
tables.

**`request`**

```json title="request"
{
  "query": "invoice INV-88213 total due",
  "limit": 3,
  "filter": {
    "supplier": {
      "$eq": "northwind"
    }
  }
}
```

The OCR text is chunked like any other text. `supplier` comes from the job's
`custom_metadata`, which is copied onto every passage.

#### A board deck exported to PDF

Goal: find the revenue chart on slide 9 by what it shows, and keep slide numbers out of
results.

**`request`**

```json title="request"
{
  "query": "revenue by region chart",
  "limit": 5,
  "exclude_chunk_types": [
    "page_footer"
  ]
}
```

**`result (one item)`**

```json title="result (one item)"
{
  "chunk_type": "figure",
  "text": "Bar chart of FY26 revenue by region: EMEA 41%, Americas 38%, APAC 21% ...",
  "location": {
    "page_start": 9,
    "page_end": 9
  }
}
```

The figure is described in words and labelled `figure`. Slide numbers are `page_footer`
blocks, so excluding that role removes them.

See [Supported File Types](/guides/supported-file-types#documents) for the extension table.