/v1 Platform API. It
resolves credentials, mints idempotency keys, retries transient failures, and
parses responses into TypeScript models.
Quick start
Key features
Typed end to end
Typed request options and response models. Unknown result variants load as
UnknownResult, so an additive server change does not prevent the job from
loading.One async client
Every method returns a
Promise. Share one NdiClient across requests and
use Promise.all to collect concurrent work.Jobs, not polling loops
Slow operations return a
Job. Wait with jobs.wait, follow progress with
jobs.events, or finish inline with wait_seconds.Automatic retries
Backoff with jitter for
429, 5xx, and dropped connections. Job-creating
calls mint idempotency keys so retries resolve to the original job.Typed error hierarchy
Status failures expose the status code, error code, request ID, and
retryability; job failures carry the terminal
Job.Zero runtime dependencies
Uses native
fetch, FormData, and Blob. The package ships dual ESM and
CommonJS builds and requires Node.js 20 or newer.Installation
ndi-sdk on npm.
To upgrade, see Update the SDKs, CLI, and MCP.
Authentication
Set your API key as an environment variable:Error before the first request.
base_url defaults to process.env.NDI_BASE_URL, then
https://ndi-api.nace.ai; set it only to reach another host. Browser
applications must pass credentials explicitly and should not expose a
long-lived API key in client-side code.
Client options
The option names use the SDK’s wire-style
snake_case.
Core methods
Upload
Stage bytes for a granular operation. The handle is single-use and expires.Upload documentation
Node and browser inputs, TTL, and when to use a workspace instead.
Parse
Turn a file into markdown, blocks, and optional chunks.Parse documentation
Parse modes, OCR, figures, chunking, and spreadsheet options.
Extract
Fill a JSON Schema from a document. Passjson_schema or a stored schema_id.
Extract documentation
Schema design, field status, and citations.
Split
Cut a multi-document packet into classified segments.Split documentation
Classes, unknown and overlap policy, and split rules.
Classify
Label a whole document, or each page, against classes you define.Classify documentation
Criteria, subclasses, granularity, and unknown policy.
Ground
Pin quoted text to locations in the source document.Ground documentation
Targets, match methods, and location shapes.
Workspaces
Build a durable corpus, then search it. Uploading registers a file; ingestion is a separate, billable operation.Workspaces documentation
Workspaces, files, ingestion, tools, and search.
Automatic search and QA
Ask one question withsearch.automatic, or hold a conversation with
search.qa. Both return a Job.
search.fact and search.deep are deprecated (@deprecated): they keep
working until they are retired. See
Search.
Automatic search
Routes, modes, structured answers, and catalog tables.
QA
Conversations, follow-ups, and clarifying questions.
Journal-entry testing
An audit procedure over an ingested ledger package, not a search preset. Returns aJob whose result is a JetResult. effort is the one knob;
omit it to take the deployment’s own floor.
Journal-entry testing
Effort, file scope, SQL receipts, and figures.
Ledger understanding
Measures the ingested journal package — table roles, integrity, and optional GL parsing — and stores a report on the workspace. Returns aJob whose result is a LedgerUnderstandingResult.
Ledger understanding
Policy, reuse, the report, and in-progress conflicts.
Async and concurrency
Every method returns aPromise. Use Promise.all to fan out concurrent
jobs and collect results together:
JobFailedError rejects out of Promise.all. Pass { raise_on_failure: false }
to jobs.wait and handle job.status yourself if you want partial failures
to settle rather than reject.
client.close() is a no-op because the SDK does not own the global or injected
fetch. If a custom transport holds resources, close those resources through
the transport that created them.
Async and concurrency guide
Client lifetime, bounded concurrency, and partial failures.
Result types and narrowing
Every document operation returns aJob. job.result is typed as
JobResult | null — a discriminated union. Use the exported type guards to
narrow to the concrete variant:
ParseResult, UploadFileResult, and
IngestionResult. Other known variants (split, extract, classify, ground, …)
can be narrowed on result_type:
UnknownResult catches any result_type the server returns that this SDK
version does not know. Exclude it with instanceof UnknownResult before
reading variant fields.
Errors
Typed errors exposestatus_code, code, retryable, and request_id.
Error handling guide
The full exception hierarchy, retry policy, and request IDs.
See Errors.
Pagination
iterAll walks cursor pages for workspaces, files, jobs, and domains.
Access labels use iterAccessLabels. See Pagination.
Advanced
Timeouts and retries
429 and 5xx responses on idempotent requests (GET, PUT,
DELETE, or any POST that carries an Idempotency-Key header — minted
automatically by document operations). timeout applies per attempt, not
over the full retry budget. Adjust wait_seconds when polling inline:
timeout extends by wait_seconds for those requests.
Custom fetch and default headers
default_headers are merged onto every request. The X-API-Key header is
always set by the SDK and cannot be overridden via default_headers.
SSE job events
Stream status updates as a job runs using the server-sent events endpoint:{ last_event_id: event.sequence.toString() }.
Legacy client
Theclient.legacy namespace wraps the original /api/v1 routes for callers
who have not migrated to /v1. Upload a local file with client.legacy.upload.
It returns a legacy upload handle with file_id, file_name and expires_at,
not the /v1 UploadResponse with upload_id. Pass the handle to
client.legacy.parse:
toFileInput converts a source URL string or a legacy upload handle into a
FileInput. A string is sent as source_url, so it must be an https://,
s3://, or ndi://file/<id> URL, not a local path.
Use the /v1 surface for new integrations.
Not wrapped
Call HTTP directly for these operations:effort is the knob on search.jeTesting only.
Next steps
- Quickstart — full curl walkthrough
- Parse guide — options, chunking, and spreadsheets
- Workspace guide — ingest and search a corpus
- Search guide — automatic search, QA, and journal-entry testing
- Jobs and idempotency
- MCP server — use NDI from Claude Code, Cursor, or opencode
- NDI CLI — the same operations from the terminal