> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ndi.nace.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Parse

> Turn a file into markdown, text, blocks, and optional chunks

```python theme={"dark"}
from ndi_sdk import NdiClient

with NdiClient() as client:
    upload = client.documents.create_upload("report.pdf")
    job = client.jobs.wait(
        client.documents.parse(upload, wait_seconds=30).job_id,
        timeout=600,
    )
    print(job.result.markdown)
```

`ocr_applied` on the result says whether OCR ran.

## Method signature

```text theme={"dark"}
def parse(
    source: DocumentSource | UploadResponse,
    *,
    page_ranges: list[PageRange] | None = None,
    quality: Literal["auto"] = "auto",
    ocr: ParseOcrOptions | None = None,
    output: ParseOutputOptions | None = None,
    figures: ParseFiguresOptions | None = None,
    diagrams: ParseDiagramsOptions | None = None,
    chunking: ParseChunkingOptions | None = None,
    spreadsheet: ParseSpreadsheetOptions | None = None,
    password: str | None = None,
    wait_seconds: int = 0,
    idempotency_key: str | None = None,
) -> Job
```

### Parameters

| Parameter         | Type                                 | Required | Description                                        |
| ----------------- | ------------------------------------ | -------- | -------------------------------------------------- |
| `source`          | `DocumentSource` or `UploadResponse` | Yes      | Upload handle, URL, workspace file, or prior parse |
| `page_ranges`     | `list[PageRange]`                    | No       | Inclusive 1-indexed ranges                         |
| `quality`         | `"auto"`                             | No       | Only accepted value                                |
| `ocr`             | `ParseOcrOptions`                    | No       | `mode`: `auto` / `force` / `disabled`              |
| `output`          | `ParseOutputOptions`                 | No       | `formats`, `table_format`, `include_images`        |
| `figures`         | `ParseFiguresOptions`                | No       | Default `describe`; also `omit` / `include`        |
| `diagrams`        | `ParseDiagramsOptions`               | No       | `omit` or `mermaid`                                |
| `chunking`        | `ParseChunkingOptions`               | No       | `none` / `page` / `section`                        |
| `spreadsheet`     | `ParseSpreadsheetOptions`            | No       | Sheet, row, and column filters                     |
| `password`        | `str`                                | No       | Encrypted PDF; write-only                          |
| `wait_seconds`    | `int`                                | No       | Hold the HTTP response open (max 300)              |
| `idempotency_key` | `str`                                | No       | Override the minted header                         |

### Returns

A `Job`. On success, `result.result_type == "parse"`. `result.markdown` is a
convenience alias for `result.document.markdown`.

## Options

```python theme={"dark"}
from ndi_sdk import NdiClient

with NdiClient() as client:
    upload = client.documents.create_upload("report.pdf")
    job = client.jobs.wait(
        client.documents.parse(
            upload,
            page_ranges=[{"start": 1, "end": 1}],
            output={"formats": ["markdown", "blocks"], "table_format": "html"},
            chunking={"strategy": "page"},
            wait_seconds=30,
        ).job_id
    )
    print(len(job.result.document.chunks))
```

Reuse a parse with `ParseResultSource(job_id=job.job_id)` so extract/ground do
not pay for it twice. Page selection and `include_images` are not available on
that source.

## Async

```python theme={"dark"}
import asyncio

from ndi_sdk import AsyncNdiClient


async def parse_one(client: AsyncNdiClient, name: str) -> str:
    upload = await client.documents.create_upload(name)
    job = await client.documents.parse(upload, wait_seconds=30)
    job = await client.jobs.wait(job.job_id, timeout=600)
    return job.result.markdown


async def main() -> None:
    async with AsyncNdiClient() as client:
        pages = await asyncio.gather(
            parse_one(client, "invoice.pdf"),
            parse_one(client, "report.pdf"),
            return_exceptions=True,
        )
    print(pages)


asyncio.run(main())
```

See [Parse guide](/guides/parse) and [Parse response](/guides/parse-response).
