---
title: "Parse a document"
method: POST
path: "/v1/documents/parse"
tags: ["Documents"]
---

# Parse a document

`POST /v1/documents/parse`

## Request

- Base URL: `https://console.nace.ai`
- URL: `https://console.nace.ai/v1/documents/parse`
- Auth: HTTP bearer
- TypeScript: <https://skmtc.dev/nace/apis/drex-api/docs/v1/documents/parse/post.ts> (a function with typed inputs; its response is checked against the schema)

Converts a document to Markdown, text or layout blocks.

- **Body:** the document service's request for this operation. [Parse](/docs/ndi/parse) lists its options and result.
- **`source`:** a `url`, a `parse_result` of one of your own jobs, or a `workspace_file` you uploaded. Upload one with `POST /v1/documents/upload-grants`.
- **Billing:** admitted only with reserved free/prepaid credit or explicitly enabled pay-as-you-go. Execution stops at its funded limit. Final credits are charged once after successful completion. A job that fails or is cancelled before completion is not charged.
- **Retries:** the same `Idempotency-Key` with the same body returns the same job. With a different body, it answers `409`.

Delivery remains job-based, with wait_seconds=0 by default. Optional retained-job page previews are available through /v1/documents/jobs/{id}/parse-progress/events; no stream request flag is needed.

## Query parameters

- `wait_seconds` integer

## Headers

- `Idempotency-Key` string

## Request body

- DocumentParseRequest: `page_ranges` selects pages: one-based and inclusive. `password` unlocks a protected file. It is write-only and never returned in any response.
  - `chunking` ParseChunkingOptions
    - `strategy` 'none' | 'page' | 'section': How result.document.chunks is built. none leaves the list empty; page and section produce RAG-sized pieces with locations.
  - `corpus_sources` WorkspaceFileSource[]: Workspace files the run can see besides `source`.
    - `file_id` string, uuid, required: File id from GET /v1/workspaces/{workspace_id}/files.
    - `type` 'workspace_file'
    - `workspace_id` string, uuid, required: Workspace that owns the file.
  - `diagrams` ParseDiagramsOptions
    - `mode` 'omit' | 'mermaid': Whether flowchart-like figures stay as images or are rewritten as Mermaid fences.
  - `figures` ParseFiguresOptions
    - `mode` 'omit' | 'include' | 'describe': Whether figure regions are dropped, kept as crops, or kept with a generated caption. Defaults to include. describe adds one vision caption call per figure.
  - `name` string, nullable: Optional display name for the run.
  - `ocr` ParseOcrOptions
    - `languages` string[]: Optional BCP-47 language hints for OCR. Empty lets the engine detect language.
    - `mode` 'auto' | 'force' | 'disabled': When to run OCR. auto runs only if the file needs it; force always runs; disabled never runs. ocr_applied on the result says whether OCR actually ran.
  - `output` ParseOutputOptions
    - `formats` string[]: Which renderings to populate on result.document. Omitted formats are null. Default is markdown plus layout blocks; text is a stripped plaintext rendering.
    - `include_images` boolean: When true, figure blocks include a crop URL for PDF and raster uploads.
    - `include_page_markers` boolean: Insert `--- Page N ---` headers between PDF pages in markdown and text. On by default.
    - `return_ocr_data` boolean: When true, attach word- and line-level OCR geometry on result.document.ocr. PDF sources only: on any other file the create is refused with `422 invalid_request`.
    - `table_format` 'html' | 'markdown': How tables are written inside markdown and in table blocks. text always flattens tables to plain text.
  - `page_ranges` PageRange[], nullable: One-based inclusive page ranges to process. Omit to use the whole document.
    - `end` integer, required: Last page of the range, 1-based and inclusive.
    - `start` integer, required: First page of the range, 1-based and inclusive.
  - `parse_mode` 'low' | 'medium' | 'high': How much parsing effort to use: Low uses native OCR, Medium routes to the best parser, and High adds page verification and correction.
  - `parser` 'native' | 'datalab' | 'nace_router', nullable: Deprecated parse implementation override. Prefer parse_mode. Omit or null for native; 'datalab' and 'nace_router' remain accepted for compatibility.
  - `password` string, nullable: Optional PDF password. Never stored in the job payload or returned in any response.
  - `project_id` string, uuid, nullable: Caller-minted grouping id; jobs submitted together share it. Not a server-side resource.
  - `quality` 'auto' | 'fast' | 'accurate': Latency versus accuracy preference for this run.
  - `source` object, required: One of three kinds: - **A URL:** `{"type":"url","url":"https://...","file_name":"a.pdf"}` - **A parse of one of your jobs:** `{"type":"parse_result","job_id":"..."}` - **A workspace file:** `{"type":"workspace_file","workspace_id":"...","file_id":"..."}`
  - `spreadsheet` ParseSpreadsheetOptions: Workbook-specific Parse controls for spreadsheet sources. Defaults preserve the pre-control behavior: every sheet/row/column is included and formula *source text* is omitted (cached values still appear).
    - `include_formulas` boolean: When true, include formula source text. Cached calculated values are always present.
    - `include_hidden_columns` boolean: When false, skip columns marked hidden.
    - `include_hidden_rows` boolean: When false, skip rows marked hidden.
    - `include_hidden_sheets` boolean: When false, skip sheets marked hidden in the workbook.
    - `sheets` string[], nullable: Optional sheet-name filter. When set, only listed sheets are parsed, in workbook order.

## Response `200`

The job finished within `wait_seconds`, or this is a replay of its Idempotency-Key.

- DocumentJob: The document service job, with artifact links rewritten for Drex and cost set to its recorded customer wallet charge. Pending or unknown cost is null. Upstream service tariffs are separate.
  - `job_id` string, uuid, required
  - `kind` 'parse' | 'split' | 'classify' | 'extract' | 'ground', required
  - `status` 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled', required
  - `result` unknown
  - `credits` integer, nullable: Credits the job used; final once `usage_final` is true. Drex charges the job's final billable usage once, at the USD price pinned when it was admitted (see Models & pricing). `credits` is the document service's usage count, not a multiplier for the per-page or per-target price. A failed job is never charged, including when it produced partial results. A job cancelled before completion is not charged, including delivered parts.
  - `usage_final` boolean
  - `timing` DocumentTiming: Original server-side Parse service timing, in milliseconds. Total includes preparation, NDI queueing/processing and active final result preparation. Upload, browser network/rendering and idle time awaiting another client read are excluded. The first usable published preview and final result use the same origin. Missing measurements remain null. Historical jobs can omit timing.
    - `received_at` string, date-time, required: When the original Parse handler received its request, before authentication and admission. Replays preserve this origin.
    - `observed_at` string, date-time, required: Server time of this timing snapshot.
    - `completed_at` string, date-time, nullable, required: First time the service prepared the terminal response, preserved across subsequent reads.
    - `elapsed_ms` integer, nullable, required: Current server elapsed estimate, or frozen total_ms once completed.
    - `total_ms` integer, nullable, required: Frozen service duration: preparation_ms + queue_ms + ndi_processing_ms + result_preparation_ms. Null until completed. delivery_wait_ms is excluded.
    - `first_response_ms` integer, nullable, required: Original request to first usable preview publication on the server. For atomic delivery, equals total_ms. Null if not measured; browser rendering and transport are excluded.
    - `breakdown` DocumentTimingBreakdown, required
      - `preparation_ms` integer, nullable, required: Original Drex request receipt to NDI job creation, including authentication, admission, source checks and internal submission.
      - `queue_ms` integer, nullable, required: NDI job creation to its processing start.
      - `ndi_processing_ms` integer, nullable, required: NDI processing start to finish, including document finalization.
      - `result_preparation_ms` integer, nullable, required: Active result-read request work after NDI finishes, including internal transfer, funding settlement and result preparation.
      - `delivery_wait_ms` integer, nullable, required: Idle interval after NDI finishes and before the request that prepares the final result begins. Excluded from total_ms; reopening a completed job does not inflate processing time.
      - `document_finalization_ms` integer, nullable, required: All requested previews being saved to NDI finishing; included inside ndi_processing_ms, not an additional summand. Null if publication milestones were not measured.
  - `cost` DocumentCost
    - `currency` 'USD', required
    - `pricing_version` string, required
    - `total_usd` string, required: Exact decimal USD wallet charge.
    - `lines` DocumentCostLine[], required
      - `operation` 'parse' | 'split' | 'classify' | 'extract' | 'ground', required
      - `quantity` integer, required
      - `unit` 'page' | 'target', required
      - `execution` 'fresh' | 'reused', required
      - `unit_price_usd` string, required
      - `amount_usd` string, required
      - `reuse_reason` string, nullable, required

## Other responses

- `202`: The job was created and hasn't finished: its `status` is `queued` or `running`. Poll `GET /v1/documents/jobs/{id}`.
- `401`: Missing or invalid API key (`authentication_error`, code `invalid_api_key`).
- `402`: The account has insufficient available funds (`insufficient_credit`) or an unpaid invoice (`payment_required`).
- `409`: The Idempotency-Key was already used for a different request (`conflict_error`, code `idempotency_conflict`).
- `413`: The request body is over 1,000,000 bytes (`invalid_request_error`, code `payload_too_large`).
- `422`: The body is not valid JSON, names a source the account doesn't own (code `invalid_source`), or the document service refused it (`invalid_request_error`).
- `429`: Over the account's requests per minute for document routes, or the document service is throttling this account (`rate_limit_error`); or the free or low-balance prepaid account already has 50 unfinished document jobs and browser runs (code `job_limit_reached`, wait for one to finish).
- `500`: Something failed on Drex's side (`internal_error`).
- `502`: The document service refused Drex's own request (`upstream_error`, code `ndi_refused_drex`). Retry later.
- `503`: Document billing is not configured (code `document_billing_not_configured`), the job is not confirmed yet (code `job_pending`; retry with the same key), or the document service is unavailable.
- `504`: The document service timed out (`upstream_error`).
- `529`: The public API is paused (code `service_disabled`) (`overloaded`).

---

[API](https://skmtc.dev/nace/apis/drex-api.md) - [All operations](https://skmtc.dev/nace/apis/drex-api/llms.txt) - [OpenAPI document](https://skmtc.dev/nace/apis/drex-api/revisions/a0e62d925a61?raw)
