Parse converts any supported document into markdown. Documents (PDF, Word, images, email, …) produce a single markdown file preserving layout, tables, and reading order. Spreadsheets (.xlsx, .xls, .xlsm, .csv) produce one markdown table per sheet.
Endpoint Behavior POST /parseStarts the job and waits for the result (bounded by timeout_seconds). POST /parse_asyncStarts the job and returns 202 {"job_id": …} immediately.
Both take the same body. See Jobs for the sync/async mechanics.
Request
Sync endpoint only. Max seconds to wait, between 1 and 300. On expiry
the call returns 408 and the job keeps running.
The document to parse. Original filename; its extension determines the format. Required for
s3:// and https:// sources; optional for ndi://file/… (defaults to
the name captured at upload).
Up to 128 characters. Repeating the POST with the same key returns the
existing job instead of starting a new one. See
Idempotency .
Supported extensions: .csv .doc .docm .docx .eml .htm .html .jpeg .jpg .log .msg .pdf .png .ppt .pptx .tif .tiff .txt .vsd .vsdx .webp .xls .xlsm .xlsx .xml
Result
When the job succeeds, result is a ParseResult:
Discriminator — always "parse" for this method.
Outcome of the extraction itself.
Extraction failure detail when status is "failed".
The parsed output — one of two shapes, discriminated by item_type. Show item_type: "file" — documents
Download URL of the full markdown (time-limited, 1 h; re-fetch the job
for a fresh one).
Characters in the markdown.
Show item_type: "table" — spreadsheets
One entry per sheet, each with sheet_name, markdown_url,
max_row, max_col, and char_count.
Examples
Document (sync)
Spreadsheet (async)
Python (async + poll)
curl -s " $NDI_BASE /parse" \
-H "X-API-Key: $NDI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"file": {
"source_url": "ndi://file/7f4d2a10-3b7e-4c25-9f61-8f0f4f0a1b2c"
},
"idempotency_key": "parse-annual-report-v1"
}'
curl -s " $NDI_BASE /parse_async" \
-H "X-API-Key: $NDI_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"file": {
"source_url": "https://example.com/trial-balance.xlsx",
"file_name": "trial-balance.xlsx"
}
}'
import time, httpx
client = httpx.Client(
base_url = "https://ndi-api.nace.ai/api/v1" ,
headers ={ "X-API-Key" : NDI_API_KEY},
)
job = client.post( "/parse_async" , json ={
"file" : { "source_url" : f "ndi://file/ { file_id } " },
"idempotency_key" : "parse-annual-report-v1" ,
}).json()
while True :
status = client.get( f "/jobs/ { job[ 'job_id' ] } " ).json()
if status[ "status" ] in ( "succeeded" , "failed" ):
break
time.sleep( 2 )
markdown = httpx.get(status[ "result" ][ "item" ][ "markdown_url" ]).text
Document result
Spreadsheet result
{
"job_id" : "0c9b2c1e-8f4a-4a91-b7a5-3f2d1e0a9c8b" ,
"action" : "parse" ,
"status" : "succeeded" ,
"result" : {
"result_type" : "parse" ,
"status" : "success" ,
"error" : null ,
"item" : {
"item_type" : "file" ,
"markdown_url" : "https://…(time-limited)…/parse/output.md" ,
"page_count" : 96 ,
"char_count" : 184223 ,
"extraction_duration_ms" : 41250
}
},
"error" : null ,
"created_at" : "2026-07-12T21:04:11Z" ,
"started_at" : "2026-07-12T21:04:12Z" ,
"completed_at" : "2026-07-12T21:04:53Z"
}
{
"job_id" : "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d" ,
"action" : "parse" ,
"status" : "succeeded" ,
"result" : {
"result_type" : "parse" ,
"status" : "success" ,
"error" : null ,
"item" : {
"item_type" : "table" ,
"sheets" : [
{
"sheet_name" : "TB Dec 2025" ,
"markdown_url" : "https://…(time-limited)…/sheet-0.md" ,
"max_row" : 412 ,
"max_col" : 8 ,
"char_count" : 30215
},
{
"sheet_name" : "Adjustments" ,
"markdown_url" : "https://…(time-limited)…/sheet-1.md" ,
"max_row" : 36 ,
"max_col" : 6 ,
"char_count" : 2144
}
]
}
},
"error" : null ,
"created_at" : "2026-07-12T21:10:02Z" ,
"started_at" : "2026-07-12T21:10:02Z" ,
"completed_at" : "2026-07-12T21:10:09Z"
}