> For a complete page index of the Captain API documentation, fetch https://docs.captain.dev/llms.txt?excludeSpec=true

# Parse Spreadsheet

POST https://api.captain.dev/v3/parse/spreadsheets
Content-Type: application/json

Parse runs a file through the same parsing and chunking Captain uses for indexing and returns the chunks without storing them in a collection. The output is meant to be taken into another database or pipeline and managed there.

Accepts XLSX, XLSM, XLS, CSV and TSV files. Each chunk is a group of rows under its column headers, with the sheet name, row and column range, and row role on every chunk. Send the file as `input`: a direct download link, or the `captain://` id from Upload File for a local file. Parsing runs as a job: this request returns `202` with a `job_id`, and the chunks come back from Get Parse Job once the job completes. Spreadsheets are billed at the indexing rates for spreadsheets: by the length of the sheet text, plus each image described when `include_images` is on. A failed or cancelled job is not billed.

Reference: https://docs.captain.dev/reference/v3/parse/spreadsheets

## Request

### Headers

- `authorization` (string, optional)
- `Idempotency-Key` (string, optional) — Retrying a request with the same key returns the original job instead of starting a second one.

### Body (application/json)

This endpoint expects a ParseSpreadsheetRequestV3.

- `input` (string, required) — The file to parse, as one of: - A direct download link: a public HTTPS URL, or a presigned URL from S3, Google Cloud Storage, Azure Blob Storage or any other store. - A `captain://` id returned by Upload File, for a file sent from local disk. For a link, Captain copies the file into its own storage right after accepting the job, so the link only needs to work for a few seconds. A link that cannot be read, a file over 100 MB, or a file type the endpoint does not accept ends the job as `failed` with `download_failed`, `file_too_large` or `unsupported_file_type`, and nothing is billed.
- `include_tags_summary` (boolean, optional, default: false) — When true, each chunk also carries the `tags` and `summary` Captain generates during indexing. These are model output, so two runs on the same file can return different values.
- `include_images` (boolean, optional, default: false) — When true, images and charts in the workbook are described and returned as `figure` chunks.
- `include_verified_facts` (boolean, optional, default: false) — When true, each row-group chunk carries `verified_facts`: exact per-column minimums, maximums and row counts computed from the rows in that chunk, with no model involved.

## Response

### 202

Job accepted.

- `job_id` (string, required) — Identifier of the parse job.
- `type` (enum, required)
  - Allowed values: `document`, `spreadsheet`
- `status` (enum, required)
  - Allowed values: `queued`
- `status_url` (string, required) — Path of the Get Parse Job endpoint for this job.
- `created_at` (string, required)

## Errors

### 400 Bad Request Error

Bad request. `error` is one of `invalid_input` (not an https link or captain:// id, or the link points to a private address), `upload_not_found`, `upload_expired`, `download_failed` (the link could not be read), `unsupported_file_type` (the file is not a type this endpoint accepts), or `invalid_idempotency_key`.

- `error` (string, required)
- `message` (string, required)
- `path` (string, optional)

### 401 Unauthorized Error

Missing or invalid API key.

- `error` (string, optional)
- `message` (string, optional)

### 402 Payment Required Error

Not enough credits for the estimated pages.

- `error` (string, optional)
- `message` (string, optional)

### 403 Forbidden Error

The API key lacks the `index` permission.

- `error` (string, optional)
- `message` (string, optional)

### 422 Unprocessable Entity Error

A field failed validation, or a PII masking option was sent. Parse does not offer masking.

- `error` (string, optional)
- `message` (string, optional)

### 429 Too Many Requests Error

Too many parse jobs are running. `too_many_parse_jobs`: this organization's limit of 20 running jobs is reached. `parse_capacity`: Captain is at capacity. Both carry a `Retry-After` header.

- `error` (string, required)
- `message` (string, required)
- `path` (string, optional)

### 503 Service Unavailable Error

Parsing is temporarily unavailable (`parse_unavailable`). Retry after the `Retry-After` header when present.

- `error` (string, required)
- `message` (string, required)
- `path` (string, optional)

## Examples

**Request**

```json
{
  "input": "captain://upl_5d41402abc4b2a76b9719d911017c592",
  "include_verified_facts": true
}
```

**Response**

```json
{
  "job_id": "prs_c9f0f895fb98ab9159f51fd0297e236d",
  "type": "spreadsheet",
  "status": "queued",
  "status_url": "/v3/parse/jobs/prs_c9f0f895fb98ab9159f51fd0297e236d",
  "created_at": "2026-10-01T15:04:05Z"
}
```

**SDK Code**

```python
import requests

BASE_URL = "https://api.captain.dev"
API_KEY = "your_api_key"

response = requests.post(
    f"{BASE_URL}/v3/parse/spreadsheets",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "input": "captain://upl_5d41402abc4b2a76b9719d911017c592",
        "include_verified_facts": True
    },
    timeout=60,
)

print(response.json())
```

```typescript
const BASE_URL = "https://api.captain.dev";
const API_KEY = "your_api_key";

const response = await fetch(`${BASE_URL}/v3/parse/spreadsheets`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "input": "captain://upl_5d41402abc4b2a76b9719d911017c592",
    "include_verified_facts": true
  }),
});

console.log(await response.json());
```