> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ndi.nace.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Parse

> Convert a document into high-fidelity markdown

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 /parse`       | Starts the job and waits for the result (bounded by `timeout_seconds`). |
| `POST /parse_async` | Starts the job and returns `202 {"job_id": …}` immediately.             |

Both take the same body. See [Jobs](/concepts/jobs) for the sync/async mechanics.

## Request

<ParamField query="timeout_seconds" type="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.
</ParamField>

<ParamField body="file" type="object" required>
  The document to parse.

  <Expandable title="file properties">
    <ParamField body="source_url" type="string" required>
      One of `ndi://file/<uuid>` (from [`POST /upload`](/api-reference/upload)),
      `https://…` (public or presigned), or `s3://bucket/key`.
      See [Files & sources](/concepts/files).
    </ParamField>

    <ParamField body="file_name" type="string">
      Original filename; its extension determines the format. **Required** for
      `s3://` and `https://` sources; optional for `ndi://file/…` (defaults to
      the name captured at upload).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="idempotency_key" type="string">
  Up to 128 characters. Repeating the POST with the same key returns the
  existing job instead of starting a new one. See
  [Idempotency](/concepts/jobs#idempotency).
</ParamField>

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`:

<ResponseField name="result_type" type="&#x22;parse&#x22;">
  Discriminator — always `"parse"` for this method.
</ResponseField>

<ResponseField name="status" type="&#x22;success&#x22; | &#x22;failed&#x22;">
  Outcome of the extraction itself.
</ResponseField>

<ResponseField name="error" type="string | null">
  Extraction failure detail when `status` is `"failed"`.
</ResponseField>

<ResponseField name="item" type="object">
  The parsed output — one of two shapes, discriminated by `item_type`.

  <Expandable title="item_type: &#x22;file&#x22; — documents">
    <ResponseField name="markdown_url" type="string">
      Download URL of the full markdown (time-limited, 1 h; re-fetch the job
      for a fresh one).
    </ResponseField>

    <ResponseField name="page_count" type="integer">Pages processed.</ResponseField>
    <ResponseField name="char_count" type="integer">Characters in the markdown.</ResponseField>
    <ResponseField name="extraction_duration_ms" type="integer">Processing time.</ResponseField>
  </Expandable>

  <Expandable title="item_type: &#x22;table&#x22; — spreadsheets">
    <ResponseField name="sheets" type="array">
      One entry per sheet, each with `sheet_name`, `markdown_url`,
      `max_row`, `max_col`, and `char_count`.
    </ResponseField>
  </Expandable>
</ResponseField>

## Examples

<CodeGroup>
  ```bash Document (sync) theme={"dark"}
  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"
    }'
  ```

  ```bash Spreadsheet (async) theme={"dark"}
  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"
      }
    }'
  ```

  ```python Python (async + poll) theme={"dark"}
  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
  ```
</CodeGroup>

<CodeGroup>
  ```json Document result theme={"dark"}
  {
    "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"
  }
  ```

  ```json Spreadsheet result theme={"dark"}
  {
    "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"
  }
  ```
</CodeGroup>
