Skip to main content
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.
EndpointBehavior
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

timeout_seconds
number
default:"120"
Sync endpoint only. Max seconds to wait, between 1 and 300. On expiry the call returns 408 and the job keeps running.
file
object
required
The document to parse.
idempotency_key
string
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:
result_type
"parse"
Discriminator — always "parse" for this method.
status
"success" | "failed"
Outcome of the extraction itself.
error
string | null
Extraction failure detail when status is "failed".
item
object
The parsed output — one of two shapes, discriminated by item_type.

Examples

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
{
  "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"
}