# Understand parse output

[Get started](/api/getting-started.html) · [API reference](/api/docs) · [Operations and limits](/api/operations.html) · [Webhooks](/api/webhooks.html) · [Versions and changelog](/api/versioning.html)

## Choose slices

`GET /documents/{id}/parse` returns the slices you name in `include`. The default is `include=tree,key_values` (`tree,kvps` before version `2026-11-05`).

| Slice        | Use it for                                                                                 |
| ------------ | ------------------------------------------------------------------------------------------ |
| `tree`       | Page layout as a tree of typed nodes, with classes, attributes and coordinates.            |
| `text`       | Plain page text in reading order.                                                          |
| `paragraphs` | Logical paragraphs with their source node IDs and governing heading.                       |
| `clauses`    | A document-wide outline of numbered clauses and headings.                                  |
| `tables`     | Tables as headers and rows of cell text.                                                   |
| `blocks`     | A flat list of layout blocks with their source node IDs.                                   |
| `key_values` | Form fields detected on any document, as key-value pairs (version `2026-11-05` and later). |
| `kvps`       | Fields from an extraction workflow configured for your account.                            |

## Pages and numbering

The `pages` parameter on `/parse` and `/render` uses one-based page numbers: `pages=1-3` returns the first three pages. Page indexes in responses are zero-based, including `page_index`, sub-document `page_from`/`page_to` and source references, so page 1 is `page_index: 0`.

`pages` selects which pages are returned. The whole document is always processed and billed.

While a document is processing, `/parse` returns the pages completed so far, and `pages` returns the requested pages that have completed. `total_pages` counts completed pages and grows until processing finishes. Use `status` from `/processing/latest` to know when a document is complete.

## Email and attachments

An EML or MSG upload is a container. The message body and each attachment in a supported format (PDF, DOC, DOCX, ODT, RTF or HTML) become child documents, processed in one processing run, and their pages count toward usage like any other pages. The container itself has no pages: `/parse` on the uploaded `id` returns an empty `pages` list.

- Attachments in other formats, such as images and spreadsheets, are skipped, and so are emails attached to an email; upload an attached email separately to process it.
- An email with more than 10 attachments in supported formats fails with `PROCESSING_FAILED`.

1. Wait until the upload's `/processing/latest` status is `completed`, or for its `document.processing.completed` event. The event carries the uploaded document's `id`.
2. List the children with `GET /documents?parent_id=<uploaded id>`. They can take a few seconds to appear in the listing, so retry briefly if the list is empty.
3. Call `/parse` on each child. A child's `/processing/latest` reports the container's `processing_id` and the child's own page counts.

Because the children share the container's `processing_id`, key anything you store from them by the child's document `id`. Deleting the uploaded email also deletes its children.

## Identifiers

- The document `id` identifies a stored document until it's deleted.
- A `processing_id` identifies one processing run. The children of an uploaded email share the email's run, so pair any run-scoped ID with a document `id`.
- Every other ID belongs to one document's run: tree node IDs, paragraph and block source IDs, sub-document IDs and table IDs. A new run assigns new IDs.
- Node IDs such as `line_0` belong to one page, and an ID isn't guaranteed to be unique on its page. For example, the rows and cells of two tables both start at `table_row_0`, header and footer nodes can share IDs, and nodes named after a printed clause or paragraph number repeat when the number is printed twice. `paragraphs[].ids`, `blocks[].id`, `tables[].id` and `clauses[].node_id` use these node IDs.
- To cite a source safely, store the document `id`, the `processing_id`, the `page_index` and the slice entry itself: its IDs together with its position in that page's list. For a unique reference to a tree node, store `(document id, processing_id, page_index, path)`, where `path` lists the node's zero-based position at each level from the page tree's `root` array down: `[0, 2, 1]` is `root[0].content[2].content[1]`.
- `paragraphs[].ids` can list several blocks merged into one logical paragraph.

To map text to positions on the page, use tree node IDs and coordinates. The `text` slice has no character offsets into the tree.

## Highlight words

Request `include=tree&tokens=true&strip_geometry=false`. Each word is a `token` node with its text in `value.text` and its rectangle in `coordinates`. Without `tokens=true`, the tree stops at lines, which carry the line text.

Coordinates use the units of the page's `width` and `height`: points, at 72 per inch, for every input format, because DOC, DOCX, ODT, RTF and email bodies are converted to PDF pages before processing. The origin is the top-left corner; x increases to the right and y increases downward. Word rectangles list their corners in this order:

```text
[[x_min,y_max], [x_max,y_max], [x_max,y_min], [x_min,y_min]]
```

That is bottom-left, bottom-right, top-right, top-left. Use the minimum and maximum values to draw a box. Reading order is the order of the tree's `content` arrays, including on right-to-left pages.

To draw at a displayed size, scale each point: `screenX = x * displayWidth / page.width` and `screenY = y * displayHeight / page.height`. Don't flip y. `strip_geometry=true` removes coordinates and page dimensions, so leave it `false` for overlays.

## Tables

The `tables` slice returns each table as `{id, headers, rows}`. Each row lists its cell text. `headers` lists detected header nodes; a header node containing several cells becomes one joined string. To read a header cell by cell, request `include=tree` and inspect the `table_column_header` node's `table_cell` children.

A table that continues across pages appears as one fragment per page. Only the tree links the fragments: each `table` node's `meta.table` carries the logical table's ID.

- Fragments of the same logical table share `meta.table.id`.
- The first fragment has `is_table_start: true`.
- Continuing fragments have `continues_from_previous: true` and a `continuation_table_id` equal to the logical table's ID.

To join a table across pages:

1. Request `include=tables,tree` for every page the table spans.
2. For each `tables[]` entry, find the `table` node with the same `id` in that page's tree and read its `meta.table.id`.
3. Group the entries by `meta.table.id` within one document, order them by page, and append their rows. Decide whether to keep a header row that repeats on each page.

The `table` node on page 0 and the one on page 1 (abridged):

```json
[
  {
    "id": "table_0",
    "class": "table",
    "class_id": 19,
    "meta": {
      "table": {
        "id": "example-table",
        "is_table_start": true,
        "continues_from_previous": false,
        "continuation_table_id": null
      }
    }
  },
  {
    "id": "table_0",
    "class": "table",
    "class_id": 19,
    "meta": {
      "table": {
        "id": "example-table",
        "is_table_start": false,
        "continues_from_previous": true,
        "continuation_table_id": "example-table"
      }
    }
  }
]
```

A first fragment can omit `continues_from_previous` and `continuation_table_id`; treat them as `false` and `null`.

## Get clean body text

- Use `exclude_node_types=header,footer,page_number,header_image,footer_image` to drop running headers, footers and page numbers. Excluded classes are removed from every slice. Unknown class names return `400`.
- Use `tokens`, not `exclude_node_types`, to control word nodes. The tree ignores `token` in `exclude_node_types`, and the other slices are built from words, so excluding `token` leaves their text empty.
- `key_values` ignores `token`, `kv_key` and `kv_value` in `exclude_node_types`, because every pair is built from them. Excluding `key_value` removes the pairs held as `key_value` nodes.
- Stamps, running case captions and footer text that repeat on every page are marked with `meta.page_chrome=true` and `ignore_selection=true` on their `token` nodes. `text`, `paragraphs`, `blocks` and `/render` keep those words; to drop them, request `tokens=true` and rebuild the text without the marked words.
- `ignore_selection` also marks other non-body words, such as printed transcript line numbers and some structural markers.
- From version `2026-09-12`, printed transcript line numbers are removed from body text and given once per line in `value.transcript_line_number`; see [Versions and changelog](/api/versioning.html).

## Blocks

The `blocks` slice lists `header`, `footer`, `section`, `line`, `table` and `sub_document` blocks in reading order. A `section` block carries the text of everything inside it, and the lines, tables and sections inside it are listed again as their own blocks; to get each piece of text once, skip `section` blocks or use `paragraphs`. `header`, `footer`, `table` and `sub_document` blocks carry their own text and aren't followed by their lines. Paragraph, heading and list-item text appears in `blocks` as `line` blocks.

## Paragraphs, clauses and attributes

- `paragraphs[].heading` is the text of the most recent heading or title before the paragraph in reading order, carried across pages. Headings are listed as their own entries, so this text isn't part of the paragraph's `text`.
- `paragraphs[].class` names the source, such as `paragraph`, `list_item`, `heading`, `footnote` or `key_value`. Use the node-class reference below to decide what counts as body text.
- A paragraph that continues onto the next page appears as two entries: the last entry on the first page has `continues_next: true`, and the first entry on the next page has `continues_prev: true`. Concatenate their `text` to rebuild it.
- The `clauses` outline contains clause entries (`kind` is `clause` or `list_item`, with `number`, `level`, `parent`, `scheme`, `text` and `children`) and heading entries (`kind` is `heading`, with `level`, `style`, `text` and `children`). A heading's `style` is an object with `size_ratio`, `bold_ratio`, `caps` and `keyword_rank`, the same measurements as the tree's `meta.heading`. Every entry points back to its `page_index` and `node_id`. Use the document's own numbering from `number` rather than parsing it out of `text`.
- `meta.section.is_marker` marks the line that carries a section's printed number.
- Handwriting is reported in `meta.styling.text_type`, and mixed lines list their handwritten words in `handwritten_tokens`.
- From version `2026-10-20`, word nodes report detected `meta.styling.strikethrough` and `underline` with `tokens=true`. Nodes with word children list their `struck_tokens` and `underlined_tokens` as `{index, text}`, even with `tokens=false`; `index` is zero-based in the line's word sequence. Struck-through words stay in `value.text`, so use the styling fields to decide which words to display or exclude.
- From version `2026-11-04`, word nodes carry `meta.ocr_confidence` with `tokens=true`: how confident OCR is in the word's text, from 0 to 1. Low scores often mark text that is damaged, faint or garbled on the page, so use them to warn readers about words or pages that may be misread. A word without the key has no score, which is not the same as a low one. Documents processed before this version's release carry no scores.

## Key-value pairs

There are two different things, and most callers only need the first.

**Detected pairs (`key_values`).** Every document is scanned for labelled fields, such as `EIN: 81-3829306` on a form or a signature block's `Date:` line, with no setup. From version `2026-11-05`, `key_values` is in the default `include` and lists every pair on the page in reading order:

```json
{"key": "EIN", "value": "81-3829306", "unvalued": false, "score": 0.9731,
 "key_box": [[...]], "value_box": [[...]], "node_id": "table_2", "source": "table"}
```

- `unvalued: true` is a blank field: a label with nothing filled in. Its `value` is empty and its `score` is `null`.
- `score`, from 0 to 1, is how confident the model is that the value belongs to the key.
- `source` says where the pair sits in the tree, and `node_id` names the node:
  - `field`: a `key_value` node, with its `kv_key` and `kv_value` halves as children. `paragraphs` lists it as a `key_value` entry.
  - `table`: inside a table. When the key and the value share a cell, the cell holds a `key_value` node. When they are in different cells, as on most ruled forms, the cells keep their words and the table lists the pair in `meta.key_values`.
  - `inline`: inside a sentence, such as `Filed on Date: 1/2/20 by the clerk`. The words stay in the paragraph's text, so it still reads, and the paragraph lists the pair in `meta.key_values`.
- In the tree, a `key_value` node carries the same pair in `meta.key_value`.

Detection finds labelled fields in English. It doesn't extract terms written in running prose, such as an effective date stated in a contract's opening sentence. For those, run your own extraction step over `paragraphs` or `/render?format=markdown`, as described in the next section.

**Configured extraction (`kvps`).** `kvps` is `{field name: value}` per page from an extraction workflow that LexSelect sets up for an account: a fixed list of fields, read from the page image and named the way you need them, for the document types you choose. It can't be set up or changed through the API or a CLI. Email [support@lexselect.io](mailto:support@lexselect.io) with sample documents and the fields you need. Without such a workflow, `kvps` is `null` on every page. From version `2026-11-05`, `kvps` is returned only when `include` names it, and the response then carries `kvps_status`: `not_configured`, or `configured` when the run's workflow extracts `kvps` (a page it skipped is still `null`). `kvps_status` is left out when the run's workflow can't be read at the time of the request.

## Use output with your own models or agents

Start with `include=text,paragraphs,clauses` for a compact input, and keep `page_index` and source IDs next to each chunk so answers can cite their source. Add `tree` to `include`, with `tokens=true`, only when you need word coordinates. For your own fields, run a separate extraction step over these results and validate its output against your schema.

`/render?format=markdown` and `format=html` return a readable rendering of the tree as a raw Markdown or HTML body. The rendering is experimental and can change; use `/parse` for structured processing. Markdown output can contain raw HTML from the source document, so sanitize it before you render it as HTML, for example with DOMPurify.

## Node-class reference

`class_id` and `class` name the same class. Match on these classes rather than on text. For ordinary body text, keep paragraphs, headings and list items, and drop header, footer and page-number classes when you don't need them.

|  ID | Class                 | Category          | Meaning                                                                                                                                               |
| --: | --------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
|   0 | `root`                | Structural        | The root of a page tree; one per page                                                                                                                 |
|   1 | `main_page`           | Structural        | The page container directly under the root                                                                                                            |
|   2 | `subpage`             | Structural        | The content region inside the page margins                                                                                                            |
|   3 | `header`              | Header and footer | Running page header                                                                                                                                   |
|   4 | `footer`              | Header and footer | Running page footer                                                                                                                                   |
|   5 | `content`             | Structural        | Generic body-content container                                                                                                                        |
|   6 | `column`              | Structural        | One vertical reading column                                                                                                                           |
|   7 | `section`             | Structural        | Logical section, such as a numbered paragraph in a legal filing; carries `value.paragraph_number`; sections can nest                                  |
|   8 | `transcript_line`     | Transcript / Q&A  | One numbered transcript line                                                                                                                          |
|   9 | `question`            | Transcript / Q&A  | A question in a transcript or deposition                                                                                                              |
|  10 | `answer`              | Transcript / Q&A  | An answer in a transcript or deposition                                                                                                               |
|  11 | `question_mark_token` | Transcript / Q&A  | The `Q.` or `Q:` marker that opens a question                                                                                                         |
|  12 | `answer_mark_token`   | Transcript / Q&A  | The `A.` or `A:` marker that opens an answer                                                                                                          |
|  13 | `speaker_turn`        | Transcript / Q&A  | A named speaker's or examiner's turn (`value.speaker`, `value.turn_number`, `value.role`; `meta.transcript.turn`); children are transcript paragraphs |
|  14 | `vision_object`       | Content block     | A content block with no more specific class                                                                                                           |
|  15 | `token`               | Text              | One word; can carry `meta.styling`                                                                                                                    |
|  16 | `line`                | Text              | One text line; the `text` slice is these lines in reading order                                                                                       |
|  17 | `sub_document`        | Structural        | A detected sub-document boundary, such as an exhibit inside a combined PDF                                                                            |
|  18 | `horizontal_band`     | Structural        | A full-width horizontal band; columns sit inside bands                                                                                                |
|  19 | `table`               | Table             | A table; the `tables` slice is built from these                                                                                                       |
|  20 | `table_row`           | Table             | One table row; children are table cells                                                                                                               |
|  21 | `table_column_header` | Table             | A header row containing its column cells                                                                                                              |
|  22 | `table_cell`          | Table             | One table cell                                                                                                                                        |
|  23 | `title`               | Content block     | Document title                                                                                                                                        |
|  24 | `heading`             | Content block     | Section heading                                                                                                                                       |
|  25 | `paragraph`           | Content block     | Body paragraph                                                                                                                                        |
|  26 | `list_item`           | Content block     | One item of a bulleted or numbered list                                                                                                               |
|  27 | `chart`               | Content block     | Chart or graph                                                                                                                                        |
|  28 | `image`               | Content block     | Image or figure in the body                                                                                                                           |
|  29 | `formula`             | Content block     | Display formula                                                                                                                                       |
|  30 | `inline_formula`      | Content block     | Formula inside a text line                                                                                                                            |
|  31 | `formula_number`      | Content block     | Equation number next to a formula                                                                                                                     |
|  32 | `caption`             | Content block     | Figure or table caption                                                                                                                               |
|  33 | `aside`               | Content block     | Side or marginal text                                                                                                                                 |
|  34 | `footnote`            | Content block     | Footnote                                                                                                                                              |
|  35 | `reference`           | Content block     | Bibliography or reference entry                                                                                                                       |
|  36 | `seal`                | Content block     | Stamp or seal                                                                                                                                         |
|  37 | `page_number`         | Header and footer | Page number                                                                                                                                           |
|  38 | `code_block`          | Content block     | Monospaced code block                                                                                                                                 |
|  39 | `abstract`            | Content block     | Abstract                                                                                                                                              |
|  40 | `header_image`        | Header and footer | Image in the header, such as a letterhead logo                                                                                                        |
|  41 | `footer_image`        | Header and footer | Image in the footer                                                                                                                                   |
|  42 | `key_value`           | Form field        | A form field: a key and its value, or a blank field with no value                                                                                     |
|  43 | `kv_key`              | Form field        | The key (label) half of a `key_value`                                                                                                                 |
|  44 | `kv_value`            | Form field        | The value half of a `key_value`                                                                                                                       |
