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

# Index File

POST https://api.filesearch.dev/v2/collections/{collection_name}/index/file
Content-Type: multipart/form-data

Index uploaded files into a collection.

Upload one or more files directly via multipart form-data. Supports PDF, DOCX,
XLSX, CSV, TXT, images, and other document types. Files are processed through
the same pipeline as cloud storage indexing.

Headers:

* Authorization: Bearer \{api\_key} - Captain API key for authentication
* X-Organization-ID: Organization UUID
* Idempotency-Key: UUID for request deduplication (optional)

Args:
collection\_name: Name of the collection (path parameter)
files: One or more files to upload and index
processing\_type: "advanced" or "basic" (default: "basic")
custom\_metadata: JSON string of custom metadata (optional)

Returns:
\{ job\_id, status: "pending" }

Reference: https://docs.filesearch.dev/reference/indexing/files/create

## Request

### Path parameters

- `collection_name` (string, required)

### Headers

- `authorization` (string, optional, nullable)

### Body (multipart/form-data)

This endpoint expects a multipart form with multiple files.

- `custom_metadata` (string, optional) — JSON string of custom metadata to attach to all indexed chunks.
- `files` (files, required) — One or more files to index (max 20). Supported: PDF, DOCX, XLSX, CSV, TXT, MD, JSON, YAML, PNG, JPG, GIF, BMP, TIFF, WEBP, MP4, MOV, AVI, MKV, WEBM, MP3, WAV, AAC, FLAC, M4A, OGG.
- `overwrite_existing` (boolean, optional) — When true, files that already exist in the collection are re-indexed and replaced with zero downtime: the new version is built alongside the live one and atomically swapped in when complete, so the previous version keeps serving search results throughout the rebuild. The document keeps the same document_id across overwrites, and its status reads 'updating' in the document listing while the rebuild runs. Requires skip_existing=false. Setting both to true returns a 400 error.
- `processing_type` (string, optional) — Document processing type: 'advanced' for AI-enhanced extraction (tables, figures, charts), 'basic' for standard processing, 'auto' to inspect each PDF and use advanced only when it has photos, drawings, tables or scanned pages (logos and signatures do not count).
- `skip_existing` (boolean, optional) — When true, files already indexed in the collection are skipped and will not be re-indexed with incoming changes. When false, all incoming files are indexed regardless of whether they already exist.
- `transcription_language` (string, optional) — AWS Transcribe language code for the spoken audio (e.g. 'es-US', 'pt-BR'). Omit to auto-detect per file. Video and audio files only. Supported codes: https://docs.aws.amazon.com/transcribe/latest/dg/supported-languages.html
- `mask_pii` (boolean, optional) — When true, mask detected PII in the parsed content before it is embedded and stored.
- `pii_engine` (enum, optional) — Masking engine for this job. `kev` (default): the Kev classifier model on Captain's infrastructure; supports `pii_fields` and `pii_instructions`; no fallback, so a file kev cannot mask fails to index and the rest of the job continues. `jev`: TypeSafe's hosted Jev model, slightly more accurate, best-effort availability; supports custom fields and instructions and may list fallbacks in `pii_fallback`. `presidio`: the legacy pattern engine, built-in categories only (rejects `pii_fields` or `pii_instructions` with 422), never a fallback. Requires `mask_pii: true`. The earlier names `captain-jev` and `captain-presidio` keep working as before; new requests should use `kev`, `jev` or `presidio`.
- `pii_fallback` (V2CollectionsCollectionNameIndexFilePostRequestBodyContentMultipartFormDataSchemaPiiFallback, optional) — Ordered fallback engines for `jev`, as `{"engines": [...], "retry_budget_seconds": n}`. Omitted or an empty `engines` list means no fallback. Only valid with `pii_engine: "jev"`; with `kev` or `presidio` a non-empty list answers 422. On the multipart file upload endpoint, send it as a JSON string form field. With the earlier engine name `captain-jev` it is `true` (default, fall back to `captain-presidio`) or `false`.
- `pii_fields` (string, optional) — JSON string of additional PII categories to mask, an array of objects with name, description and optional examples (the same shape as pii_fields on the JSON indexing endpoints). Requires mask_pii to be true.
- `pii_instructions` (string, optional) — Plain-language guidance that steers what counts as personal data for this job. Requires mask_pii to be true. Up to 1,000 characters.

## Response

### 200

Successful Response

- `job_id` (string, required)
- `status` (string, optional, default: pending)
- `custom_metadata` (map from string to any, optional, nullable) — The custom_metadata Captain accepted for this job, echoed back as validated. Null when none was supplied.

## Errors

### 400 Bad Request Error

overwrite_existing and skip_existing cannot both be true

- `error` (string, required) — Error kind. `HTTP_ERROR` for errors raised by the route.
- `message` (string, required) — What went wrong.
- `path` (string, required) — The request path.
- `status_code` (integer, optional) — The HTTP status code.

## Examples

**Request**

```json
{}
```

**Response**

```json
{
  "job_id": "c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8-1783111727",
  "status": "pending"
}
```

**SDK Code**

```python
import json
import requests
import uuid

BASE_URL = "https://api.filesearch.dev"
API_KEY = "your_api_key"
COLLECTION_NAME = "my_documents"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Idempotency-Key": str(uuid.uuid4()),
}

response = requests.post(
    f"{BASE_URL}/v2/collections/{COLLECTION_NAME}/index/file",
    headers=headers,
    timeout=120.0
)

print(json.dumps(response.json(), indent=2))
```

```typescript
const BASE_URL = "https://api.filesearch.dev";

const API_KEY = "your_api_key";

const collection_name = "my_documents";

const headers = {
  Authorization: `Bearer ${API_KEY}`,
  "Idempotency-Key": crypto.randomUUID(),
};

const response = await fetch(`${BASE_URL}/v2/collections/${collection_name}/index/file`, {
  method: "POST",
  headers,
});

const data = await response.json();
console.log(JSON.stringify(data, null, 2));
```