Prerequisites
An API key is minted in the NDI console and shown exactly once. Export it, and the SDKs andcurl examples below pick it up with no extra wiring:
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:- Claude Code
- Cursor
- Codex
- opencode
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
- Python
- TypeScript
- curl
Install the SDK. It requires Python 3.11+ and pulls in only Stage the document. Parse it. Parse is asynchronous and returns a Read the result.
httpx and
pydantic:create_upload sends the bytes and returns a
single-use handle. The bytes are deleted as soon as the job that reads them
finishes:Job. wait_seconds holds
the submission request open so short documents finish inline; jobs.wait
covers everything longer: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:- Python
- TypeScript
- curl
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,mediumroutes to the best parser for the document,highadds page-level verification and correction for more latency.output.formats—markdownandblocksby default. Addtextfor a flattened rendering.table_formatswitches tables betweenhtml(default) andmarkdown.chunking.strategy—noneby default. Usepageorsectionwhen the output feeds retrieval.
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. SendX-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.