Skip to main content
Parse turns a document into markdown and layout blocks you can hand to an LLM, an extraction schema, or your own pipeline. This guide does that with one file and no workspace, then points at the operations that build on the same call.

Prerequisites

An API key is minted in the NDI console and shown exactly once. Export it, and the SDKs and curl examples below pick it up with no extra wiring:
This guide parses report.pdf in the current directory. Any PDF, Office file, image, spreadsheet, audio, or video file works — substitute your own path or an HTTPS URL. NDI hosts no sample document, so bring your own. See Authentication for key scope and rotation, and Format support for what each lane accepts.

Working in a coding agent

NDI speaks MCP, so Claude Code, Cursor, Codex, and opencode can call parse as a tool instead of you writing client code. Authenticate once:
Then add the local server to your agent:
Ask the agent to run upload_document on the local file, then parse_document with the handle it gets back. The hosted server at https://ndi-api.nace.ai/v1/mcp runs in our cloud and cannot see your filesystem, so local files need the local server. The hosted variant and full tool catalog are on the MCP page. Prefer the shell with no agent? pip install ndi-cli, then ndi parse ./report.pdf. Full command reference: NDI CLI.

Parse a document

Install the SDK. It requires Python 3.11+ and pulls in only httpx and pydantic:
Stage the document. create_upload sends the bytes and returns a single-use handle. The bytes are deleted as soon as the job that reads them finishes:
Parse it. Parse is asynchronous and returns a Job. wait_seconds holds the submission request open so short documents finish inline; jobs.wait covers everything longer:
Read the result. job.result is a ParseResult. Markdown is produced by default, and result.markdown is a shortcut for result.document.markdown:

Understanding the response

A succeeded parse job looks like this:
Renderings you did not request are null, not missing. Block locations vary by source — pages use normalized polygons, workbooks use sheet ranges, structured text uses spans or JSON pointers. Parse response format covers every variant, including audio and video transcripts.

Customizing the parse

The defaults suit most documents. These four options cover most of what people change first:
  • page_ranges — one-based inclusive ranges. Cheaper and faster on long documents when you only need a section.
  • parse_mode — low (default) uses the native path, medium routes to the best parser for the document, high adds page-level verification and correction for more latency.
  • output.formats — markdown and blocks by default. Add text for a flattened rendering. table_format switches tables between html (default) and markdown.
  • chunking.strategy — none by default. Use page or section when the output feeds retrieval.
Figure descriptions, diagram-to-Mermaid, image crops, OCR geometry, spreadsheet sheet selection, and encrypted-PDF passwords are all available too. See the Python or TypeScript parse reference.

What’s next

Extract fields

Define a JSON schema and get typed fields back with citations into the source document.

Split a packet

Cut a multi-document PDF into labeled sections with page ranges.

Classify a document

Assign your own classes to a whole document or to each page.

Ground a claim

Locate a value or phrase on the page so a reviewer can see where it came from.

Build a workspace

Store a corpus, ingest it once, then run search and file tools across it.

Reuse one parse

Pass a succeeded parse job to extract, split, or ground instead of paying for the parse twice.

Troubleshooting

401 unauthorized. Send X-API-Key, and check $NDI_API_KEY is exported in the same shell as the client. Authorization: Bearer works on hosted MCP only. 422 invalid_request on parse. wait_seconds is a query parameter and Idempotency-Key is a header. Neither belongs in the JSON body. Status is failed. Read job.error. Common causes are an unsupported format, a corrupt file, page ranges past the end of the document, and a missing or wrong password on an encrypted PDF. upload_expired. Upload handles expire after 24 hours by default. Stage the file again. Tables came back as HTML. That is the default. Pass output.table_format: "markdown" for markdown tables. result is gone on a job that succeeded. Retention passed payload_expires_at. Re-run the operation. Symptom-based fixes for ingestion, search, and workspaces are in Troubleshooting.