> This page is for version v2024-12-23.
> For other versions, use one of these documentation indexes:
> - v2026-02-09 (default): https://docs.extend.ai/2026-02-09/llms.txt
> - v2025-04-21: https://docs.extend.ai/2025-04-21/llms.txt
> - v2024-12-23: https://docs.extend.ai/2024-12-23/llms.txt

> ## Documentation Index
> Fetch the complete documentation index at: https://docs.extend.ai/llms.txt
> Use this file to discover all available pages before exploring further.
>
> ## API version
> The current API version is `2026-02-09`, served at the site root (no version prefix in URLs).
> If this page URL contains `/2025-04-21/` or `/2024-12-23/`, you are reading an older API version.
> Prefer the current docs at https://docs.extend.ai/llms.txt unless the user explicitly needs that older version.
> Do not treat older-version pages as the source of truth for new integrations.

# Parse File

The Parse endpoint allows you to convert documents into structured, machine-readable formats with fine-grained control over the parsing process. This endpoint is ideal for extracting cleaned document content to be used as context for downstream processing, e.g. RAG pipelines, custom ingestion pipelines, embeddings classification, etc.

Unlike processor and workflow runs, parsing is a synchronous endpoint and returns the parsed content in the response. Expected latency depends primarily on file size. This makes it suitable for workflows where you need immediate access to document content without waiting for asynchronous processing.

For a deeper guide on how to use the output of this endpoint, jump to [Using Parsed Output](#using-parsed-output).

```curl
curl --request POST \
  --url https://api-prod.extend.app/parse \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "file": {
    "fileName": "<string>",
    "fileUrl": "<string>",
    "fileId": "<string>"
  },
  "config": {
    "target": "<string>",
    "chunkingStrategy": {
      "type": "<string>",
      "minCharacters": 123,
      "maxCharacters": 123
    },
    "blockOptions": {
      "figures": {
        "enabled": true,
        "figureImageClippingEnabled": true
      },
      "tables": {
        "enabled": true,
        "targetFormat": "<string>"
      },
      "text": {
        "signatureDetectionEnabled": true
      }
    },
    "advancedOptions": {
      "pageRotationEnabled": true
    }
  }
}'
```

```python
import requests

url = "https://api-prod.extend.app/parse"

payload = {
    "file": {
        "fileName": "<string>",
        "fileUrl": "<string>",
        "fileId": "<string>"
    },
    "config": {
        "target": "<string>",
        "chunkingStrategy": {
            "type": "<string>",
            "minCharacters": 123,
            "maxCharacters": 123
        },
        "blockOptions": {
            "figures": {
                "enabled": True,
                "figureImageClippingEnabled": True
            },
            "tables": {
                "enabled": True,
                "targetFormat": "<string>"
            },
            "text": {"signatureDetectionEnabled": True}
        },
        "advancedOptions": {"pageRotationEnabled": True}
    }
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.request("POST", url, json=payload, headers=headers)

print(response.text)
```

```javascript
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"file":{"fileName":"<string>","fileUrl":"<string>","fileId":"<string>"},"config":{"target":"<string>","chunkingStrategy":{"type":"<string>","minCharacters":123,"maxCharacters":123},"blockOptions":{"figures":{"enabled":true,"figureImageClippingEnabled":true},"tables":{"enabled":true,"targetFormat":"<string>"},"text":{"signatureDetectionEnabled":true}},"advancedOptions":{"pageRotationEnabled":true}}}'
};

fetch('https://api-prod.extend.app/parse', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
```

```php
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://api-prod.extend.app/parse",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\n  \"file\": {\n    \"fileName\": \"<string>\",\n    \"fileUrl\": \"<string>\",\n    \"fileId\": \"<string>\"\n  },\n  \"config\": {\n    \"target\": \"<string>\",\n    \"chunkingStrategy\": {\n      \"type\": \"<string>\",\n      \"minCharacters\": 123,\n      \"maxCharacters\": 123\n    },\n    \"blockOptions\": {\n      \"figures\": {\n        \"enabled\": true,\n        \"figureImageClippingEnabled\": true\n      },\n      \"tables\": {\n        \"enabled\": true,\n        \"targetFormat\": \"<string>\"\n      },\n      \"text\": {\n        \"signatureDetectionEnabled\": true\n      }\n    },\n    \"advancedOptions\": {\n      \"pageRotationEnabled\": true\n    }\n  }\n}",
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer <token>",
    "Content-Type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://api-prod.extend.app/parse"

	payload := strings.NewReader("{\n  \"file\": {\n    \"fileName\": \"<string>\",\n    \"fileUrl\": \"<string>\",\n    \"fileId\": \"<string>\"\n  },\n  \"config\": {\n    \"target\": \"<string>\",\n    \"chunkingStrategy\": {\n      \"type\": \"<string>\",\n      \"minCharacters\": 123,\n      \"maxCharacters\": 123\n    },\n    \"blockOptions\": {\n      \"figures\": {\n        \"enabled\": true,\n        \"figureImageClippingEnabled\": true\n      },\n      \"tables\": {\n        \"enabled\": true,\n        \"targetFormat\": \"<string>\"\n      },\n      \"text\": {\n        \"signatureDetectionEnabled\": true\n      }\n    },\n    \"advancedOptions\": {\n      \"pageRotationEnabled\": true\n    }\n  }\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```java
HttpResponse<String> response = Unirest.post("https://api-prod.extend.app/parse")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"file\": {\n    \"fileName\": \"<string>\",\n    \"fileUrl\": \"<string>\",\n    \"fileId\": \"<string>\"\n  },\n  \"config\": {\n    \"target\": \"<string>\",\n    \"chunkingStrategy\": {\n      \"type\": \"<string>\",\n      \"minCharacters\": 123,\n      \"maxCharacters\": 123\n    },\n    \"blockOptions\": {\n      \"figures\": {\n        \"enabled\": true,\n        \"figureImageClippingEnabled\": true\n      },\n      \"tables\": {\n        \"enabled\": true,\n        \"targetFormat\": \"<string>\"\n      },\n      \"text\": {\n        \"signatureDetectionEnabled\": true\n      }\n    },\n    \"advancedOptions\": {\n      \"pageRotationEnabled\": true\n    }\n  }\n}")
  .asString();
```

**`200`**

```json 200
{
  "object": "<string>",
  "id": "<string>",
  "fileId": "<string>",
  "chunks": [
    {
      "object": "<string>",
      "type": "<string>",
      "content": "<string>",
      "metadata": {
        "pageRange": {
          "start": 123,
          "end": 123
        }
      },
      "blocks": [
        {
          "object": "<string>",
          "id": "<string>",
          "type": "<string>",
          "content": "<string>",
          "details": {},
          "metadata": {
            "page": {
              "number": 123,
              "width": 123,
              "height": 123
            }
          },
          "polygon": [
            {}
          ],
          "boundingBox": {}
        }
      ]
    }
  ],
  "status": "<string>",
  "failureReason": "<string>",
  "config": {},
  "metrics": {
    "processingTimeMs": 123,
    "pageCount": 123
  },
  "code": "<string>",
  "message": "<string>",
  "requestId": "<string>",
  "retryable": true
}
```

### Body

**`file`** `object` — required

A file object containing either a URL or base64 encoded content. Must contain
either fileUrl or fileId.

#### properties

**`fileName`** `string`

The name of the file. If not set, the file name is taken from the url or generated in case of raw upload.

---

**`fileUrl`** `string`

A URL for the file. For production use cases, we recommend using presigned URLs with
a 5-15 minute expiration time.

---

**`fileId`** `string`

If you already have an Extend file id (for instance from running a workflow or a previous file [upload](/2024-12-23/developers/file-endpoints/upload-file)) then you can
use that file id when running the parse endpoint so that it leverage any cached data that might be available.

---

---

**`config`** `object` — required

Configuration options for the parsing process.

#### properties

**`target`** `string` — default: markdown

The target format for the parsed content. Supported values:

* `markdown`: Convert document to Markdown format
* `spatial`: Preserve spatial information in the output

---

**`chunkingStrategy`** `object`

Strategy for dividing the document into chunks.

#### properties

**`type`** `string` — default: page

The type of chunking strategy. Supported values:

* `page`: Chunk document by pages.
* `document`: Entire document is a single chunk. Essentially no chunking.
* `section`: Split by logical sections. Not support for target=spatial.

---

**`minCharacters`** `number`

Specify a minimum number of characters per chunk.

---

**`maxCharacters`** `number`

Specify a maximum number of characters per chunk.

---

---

**`blockOptions`** `object`

Options for controlling how different block types are processed.

#### properties

**`figures`** `object`

Options for figure blocks.

#### properties

**`enabled`** `boolean` — default: true

Whether to include figures in the output.

---

**`figureImageClippingEnabled`** `boolean` — default: true

Whether to clip and extract images from figures.

---

---

**`tables`** `object`

Options for table blocks.

#### properties

**`enabled`** `boolean` — default: true

Whether to include tables in the output.

---

**`targetFormat`** `string` — default: markdown

The target format for the table blocks. Supported values:

* `markdown`: Convert table to Markdown format
* `html`: Convert table to HTML format

---

---

**`text`** `object`

Options for text blocks.

#### properties

**`signatureDetectionEnabled`** `boolean` — default: true

Whether an additional vision model will be utilized for advanced signature detection.
Recommended, for most use cases, but should be disabled if signature detection is not necessary and latency is a concern.

---

---

---

**`advancedOptions`** `object`

Advanced parsing options.

#### properties

**`pageRotationEnabled`** `boolean` — default: true

Whether to automatically detect and correct page rotation.

---

---

---

### Response

**`object`** `string`

The type of object. Will always be "parser_run".

---

**`id`** `string`

A unique identifier for the parser run.

---

**`fileId`** `string`

The identifier of the file that was parsed. This can be used as a parameter to other Extend endpoints, such as processor runs. This allows downstream processing to reuse a cache of the parsed file content to reduce your usage costs.

---

**`chunks`** `array`

An array of chunks extracted from the document.

#### properties

**`object`** `string`

The type of object. Will be "chunk".

---

**`type`** `string`

The type of chunk (e.g., "page").

---

**`content`** `string`

The textual content of the chunk in the specified target format.

---

**`metadata`** `object`

Metadata about the chunk.

#### properties

**`pageRange`** `object`

The page range this chunk covers. Often will just be a partial page, in which cases `start` and `end` will be the same.

#### properties

**`start`** `number`

The starting page number (inclusive).

---

**`end`** `number`

The ending page number (inclusive).

---

---

---

**`blocks`** `array`

An array of block objects that make up the chunk. See the [Block object](/2024-12-23/developers/objects/block) documentation for more detailed information about block structure and types.

#### properties

**`object`** `string`

The type of object. Will be "block".

---

**`id`** `string`

A unique identifier for the block.

---

**`type`** `string`

The type of block. Possible values include:

* `text`: Regular text content
* `heading`: Section or document headings
* `section_heading`: Subsection headings
* `table`: Tabular data with rows and columns
* `figure`: Images, charts, or diagrams

---

**`content`** `string`

The textual content of the block.

---

**`details`** `object`

Additional details specific to the block type.

---

**`metadata`** `object`

Metadata about the block.

#### properties

**`page`** `object`

Information about the page this block appears on.

#### properties

**`number`** `number`

The page number.

---

**`width`** `number`

The width of the page in inches.

---

**`height`** `number`

The height of the page in inches.

---

---

---

**`polygon`** `array`

An array of points defining the polygon that bounds the block.

---

**`boundingBox`** `object`

A simplified bounding box for the block.

---

---

---

**`status`** `string`

The status of the parser run. Possible values:

* `PROCESSED`: The file was successfully processed
* `FAILED`: The processing failed (see failureReason for details)

---

**`failureReason`** `string`

The reason for failure if status is "FAILED". Will be null for successful runs.

---

**`config`** `object`

The configuration used for the parsing process, including any default values that were applied.

---

**`metrics`** `object`

Metrics about the parsing process.

#### properties

**`processingTimeMs`** `number`

The time taken to process the document in milliseconds.

---

**`pageCount`** `number`

The number of pages in the document.

---

---

**`Node.js`**

```javascript Node.js
const parseDocument = async () => {
  const response = await fetch("https://api-prod.extend.app/parse", {
    method: "POST",
    headers: {
      Authorization: "Bearer <API_TOKEN>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      file: {
        fileName: "example.pdf",
        fileUrl: "https://example.com/documents/example.pdf",
      },
      config: {
        target: "markdown",
        chunkingStrategy: {
          type: "page",
        },
        blockOptions: {
          figures: {
            enabled: true,
            figureImageClippingEnabled: true,
          },
          tables: {
            enabled: true,
          },
          text: {
            enabled: true,
            styleFormattingEnabled: true,
          },
        },
      },
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    console.error("Error:", error);
    return;
  }

  const data = await response.json();
  console.log("Document parsed successfully:", data);
};

parseDocument();
```

---

### Using Parsed Output

The Parse API returns document content in a structured format that provides both high-level formatted content and detailed block-level information. Understanding how to work with this output will help you get the most value from the parsing service.

#### Working with Chunks

Each chunk (currently only page-level chunks are supported) contains two key properties:

1. **`content`**: A fully formatted representation of the entire chunk in the target format (e.g., markdown). This is ready to use as-is if you need the complete formatted content of a page.

2. **`blocks`**: An array of individual content blocks that make up the chunk, each with its own formatting, position information, and metadata.

#### When to use `chunk.content` vs. `chunk.blocks`

* **Use `chunk.content` when:**
  * You need the complete, properly formatted content of a page, already doing the logical placement of blocks (e.g. grouping markdown sections and placing spatially, etc)
  * You want to display or process the document content as a whole (and can just combine all chunk.content values)
  * You're integrating with systems that expect formatted text (e.g., markdown processors)

* **Use `chunk.blocks` when:**
  * You need to work with specific elements of the document (e.g., only tables or figures)
  * You need spatial information about where content appears on the page, perhaps to build citation systems
  * You're building a UI that shows or highlights specific document elements

#### Example: Extracting specific content types

```javascript
// Extract all tables from a document
function extractTables(parseResult) {
  const tables = [];
  
  parseResult.chunks.forEach(chunk => {
    chunk.blocks.forEach(block => {
      if (block.type === 'table') {
        tables.push({
          content: block.content,
          pageNumber: block.metadata.pageNumber,
          position: block.boundingBox
        });
      }
    });
  });
  
  return tables;
}

// Extract all figures with their images
function extractFigures(parseResult) {
  const figures = [];
  
  parseResult.chunks.forEach(chunk => {
    chunk.blocks.forEach(block => {
      if (block.type === 'figure' && block.details.imageUrl) {
        figures.push({
          caption: block.content,
          imageUrl: block.details.imageUrl,
          figureType: block.details.figureType,
          pageNumber: block.metadata.pageNumber
        });
      }
    });
  });
  
  return figures;
}
```

#### Example: Reconstructing content with custom formatting

```javascript
// Extract headings and their content to create a table of contents
function createTableOfContents(parseResult) {
  const toc = [];
  
  parseResult.chunks.forEach(chunk => {
    chunk.blocks.forEach(block => {
      if (block.type === 'heading' || block.type === 'section_heading') {
        toc.push({
          title: block.content,
          pageNumber: block.metadata.pageNumber
        });
      }
    });
  });
  
  return toc;
}
```

#### Spatial Information

Each block contains spatial information in the form of a `polygon` (precise outline) and a simplified `boundingBox`. This information can be used to:

* Highlight specific content in a document viewer
* Create visual overlays on top of the original document
* Understand the reading order and layout of the document

```javascript
// Create highlight coordinates for a document viewer
function createHighlights(parseResult, searchTerm) {
  const highlights = [];
  
  parseResult.chunks.forEach(chunk => {
    chunk.blocks.forEach(block => {
      if (block.type === 'text' && block.content.includes(searchTerm)) {
        highlights.push({
          pageNumber: block.metadata.pageNumber,
          boundingBox: block.boundingBox
        });
      }
    });
  });
  
  return highlights;
}
```

By leveraging both the formatted content and the structured block information, you can build powerful document processing workflows that combine the convenience of formatted text with the precision of block-level access.

### Error Response Format

When an error occurs, the API returns a structured error response with the following fields:

**`code`** `string`

A specific error code that identifies the type of error.

---

**`message`** `string`

A human-readable description of the error.

---

**`requestId`** `string`

A unique identifier for the request, useful for troubleshooting.

---

**`retryable`** `boolean`

Indicates whether retrying the request might succeed.

---

### Custom Error Codes

The API may return the following specific error codes:

### Custom Error Codes

We provide custom error codes to make it easier for your system to know what happened in case of a failure. There will also be a `retryable=true|false` field in the response body, but you can also find a breakdown below. Most errors are not retryable and are client errors related to the file provided for parsing.

| Error Code                         | Description                                                                                                                                                                        | Retryable |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| `INVALID_CONFIG_OPTIONS`           | Invalid combination of options in the incoming config.                                                                                                                             | ❌         |
| `UNABLE_TO_DOWNLOAD_FILE`          | The system could not download the file from the provided URL, likely means your presigned url is expired, or malformed somehow.                                                    | ❌         |
| `FILE_TYPE_NOT_SUPPORTED`          | The file type is not supported for parsing.                                                                                                                                        | ❌         |
| `FILE_SIZE_TOO_LARGE`              | The file exceeds the maximum allowed size.                                                                                                                                         | ❌         |
| `CORRUPT_FILE`                     | The file is corrupt and cannot be parsed.                                                                                                                                          | ❌         |
| `OCR_ERROR`                        | An error occurred in the OCR system. This is a rare error code and would indicate downtime, so requests can be retried. We'd suggest applying a retry with backoff for this error. | ✅         |
| `PASSWORD_PROTECTED_FILE`          | The file is password protected and cannot be parsed.                                                                                                                               | ❌         |
| `FAILED_TO_CONVERT_TO_PDF`         | The system could not convert the file to PDF format.                                                                                                                               | ❌         |
| `FAILED_TO_GENERATE_TARGET_FORMAT` | The system could not generate the requested target format.                                                                                                                         | ❌         |
| `INTERNAL_ERROR`                   | An unexpected internal error occurred. We'd suggest applying a retry with backoff for this error as it likely a result of some outage.                                             | ✅         |

### HTTP error codes

Corresponding http error codes for different types of failures. We generally recommend relying on our custom error codes for programmatic handling.

**`400 Bad Request`**

Returned when:

* Required fields are missing (e.g., `file`)
* `fileUrl` is not provided in the file object
* The provided `fileUrl` is invalid
* The `config` contains invalid values (e.g., unsupported target format or chunking strategy)
* The file type is not supported
* The file size is too large

---

**`401 Unauthorized`**

Returned when:

* The API token is missing
* The API token is invalid

---

**`403 Forbidden`**

Returned when:

* The authenticated workspace doesn't have permission to use the parse functionality
* The API token doesn't have sufficient permissions

---

**`422 Unprocessable Entity`**

Returned when:

* The file is corrupt and cannot be parsed
* The file is password protected
* The file could not be converted to PDF
* The system failed to generate the target format

---

**`500 Internal Server Error`**

Returned when:

* An OCR error occurs
* A chunking error occurs
* Any other unexpected error occurs during parsing

---

### Handling Errors

Here are examples of how to handle errors from the Parse API:

**`Error Handling in Node.js`**

```javascript Error Handling in Node.js
const parseDocument = async () => {
  const response = await fetch("https://api-prod.extend.app/parse", {
    method: "POST",
    headers: {
      Authorization: "Bearer <API_TOKEN>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      file: {
        fileName: "example.pdf",
        fileUrl: "https://example.com/documents/example.pdf",
      },
      config: {
        target: "markdown",
      },
    }),
  });

  const data = await response.json();

  if (!response.ok) {
    const { code, message, requestId, retryable } = data;

    // Handle specific error codes
    switch (code) {
      case "FILE_TYPE_NOT_SUPPORTED":
        console.error("Unsupported file type. Please use a supported format.");
        break;
      case "PASSWORD_PROTECTED_FILE":
        console.error("The file is password protected. Please provide an unprotected file.");
        break;
      case "CORRUPT_FILE":
        console.error("The file is corrupt and cannot be processed.");
        break;
      case "FILE_SIZE_TOO_LARGE":
        console.error("The file is too large. Please reduce the file size.");
        break;
      default:
        console.error(`Error (${code}): ${message}`);
    }

    // Log request ID for troubleshooting
    console.error(`Request ID: ${requestId}`);

    // Potentially retry if the error is retryable
    if (retryable) {
      console.log("This error is retryable. Consider retrying the request.");
    }

    throw new Error(`API error: ${code}`);
  }

  console.log("Document parsed successfully:", data);
  return data;
};
```

**`Error Handling in Python`**

```python Error Handling in Python
import requests

def parse_document(file_url, file_name, config=None):
    if config is None:
        config = {"target": "markdown"}
        
    url = "https://api-prod.extend.app/parse"
    headers = {
        "Authorization": "Bearer <API_TOKEN>",
        "Content-Type": "application/json"
    }
    payload = {
        "file": {
            "fileName": file_name,
            "fileUrl": file_url
        },
        "config": config
    }

    try:
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()  # Raise exception for 4XX/5XX responses
        return response.json()
    except requests.exceptions.HTTPError as e:
        error_data = e.response.json()
        code = error_data.get("code")
        message = error_data.get("message")
        request_id = error_data.get("requestId")
        retryable = error_data.get("retryable", False)
        
        # Handle specific error codes
        if code == "FILE_TYPE_NOT_SUPPORTED":
            print(f"Error: Unsupported file type. {message}")
        elif code == "PASSWORD_PROTECTED_FILE":
            print(f"Error: Password protected file. {message}")
        elif code == "CORRUPT_FILE":
            print(f"Error: Corrupt file. {message}")
        elif code == "FILE_SIZE_TOO_LARGE":
            print(f"Error: File too large. {message}")
        else:
            print(f"Error ({code}): {message}")
            
        # Log request ID for troubleshooting
        print(f"Request ID: {request_id}")
        
        # Potentially retry if the error is retryable
        if retryable:
            print("This error is retryable. Consider retrying the request.")
            
        raise
    except requests.exceptions.RequestException as e:
        print(f"Network error: {str(e)}")
        raise
```