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

# Changelog

## Parse Documents and Spreadsheets Without Indexing

* **The same chunks indexing produces, without a collection**: the Parse API runs a file through the parsing and chunking Captain uses for indexing and returns the chunks without storing them in a collection. Each chunk carries its text, token count, layout type, and page or row location, so the chunks can go into another database and be managed there. See [Parse Document](/reference/v3/parse/documents).
* **Documents and spreadsheets**: `POST /v3/parse/documents` takes PDF, DOCX and DOC files, with `processing_type` set to `advanced` or `basic`. `POST /v3/parse/spreadsheets` takes XLSX, XLSM, XLS, CSV and TSV files, with optional image descriptions and verified facts. See [Parse Spreadsheet](/reference/v3/parse/spreadsheets).
* **Links or uploads**: a parse request takes `input`, either a direct download link (public or presigned) or a `captain://` ID from [Upload File](/reference/v3/parse/uploads). Links without a file extension work too, because Captain reads the file type from the file itself.
* **Jobs with webhooks**: each request starts a job. [Get Parse Job](/reference/v3/parse/jobs/get) returns its status and, once it completes, the chunks in order. Pass `wait` (up to 50 seconds) to hold the request until the job ends instead of polling on a timer. The `parse.completed`, `parse.failed` and `parse.cancelled` webhook events report when a job ends.
* **Billing matches indexing**: document pages bill at the indexing rates for their processing type. Spreadsheets bill for their sheet text and for each described image. Failed and cancelled jobs are not billed.

## Query Several Collections in One Request

* **One request for up to 10 collections**: `POST /v3/collections/batch-query` takes a list of `collections`, and each entry accepts every v3 Query parameter plus `collection`. A top-level `query` fills any entry that omits its own. Captain runs the entries at the same time, so the request takes about as long as its slowest entry. See [Query Several Collections](/guides/advanced-querying#query-several-collections).
* **One ranked list per collection**: `results[i]` answers `collections[i]`, with the full Query response for that collection. Lists are never merged, and scores from different collections are not comparable. See [Batch Query](/reference/v3/batch-query).
* **Failures stay in their own entry**: a problem found before any search, such as an unknown collection or a missing query, fails the whole request. Once searching starts, a failed entry reports its own `error` in its slot and the rest still return. Retry only the failed entries.

## Product Search Release Candidate

Product Search is in release candidate with our design partners. It searches the records inside an application or website: products in a store, listings on a marketplace, articles in a help center, or records inside a SaaS product.

Everything we've learned searching complex files with File Search now goes into Product Search. Ranking blends keyword and meaning-based matching the same way, and the query understanding that fixes typos and recognizes codes like SKUs and CUSIPs works on records too. File Search still handles files and their contents, so Captain now searches both the documents a company keeps and the records its product serves. Each customer gets a dedicated endpoint, such as `acme.captain.dev`. See the [Product Search overview](/guides/product-search/introduction).

* **Results while people type**: typeahead answers each keystroke with spelling fixes and completions. Full search combines keyword and meaning-based matching with filters, facets and sort, and browse, similar records and multi-search return the same response shape. See [Search](/guides/product-search/search).
* **An index that keeps up with your data**: records you add or replace are searchable within a few seconds, and updates and deletes apply within about a second. There's no build step to run. See [Records](/guides/product-search/records).
* **Per-user access for sensitive records**: when records carry access lists, a scoped key minted for one end user returns only what that user may see, and suggestions and facet counts follow the same rule. See [Per-record access control](/guides/product-search/search#per-record-access-control).
* **Search analytics**: send click and conversion events, then read top queries, zero-result queries, click-through rate and conversion rate for each index. See [Analytics](/guides/product-search/analytics).
* **Works with existing Algolia clients**: an Algolia client or InstantSearch front end can point at your endpoint with a Captain search key, and an existing Algolia index can be imported. Captain reviews each import before it builds. See [Algolia compatibility](/guides/product-search/algolia-compatibility).

## PII Engines kev, jev and presidio

* **Three engines, chosen with `pii_engine`**: `kev` (the default) runs the Kev classifier model on Captain's infrastructure. `jev` runs TypeSafe's hosted Jev model, slightly more accurate with best-effort capacity. `presidio` is the legacy pattern engine for the built-in categories only. See [Engines](/guides/pii-masking#engines).
* **New default for `{"mask_pii": true}`**: a request with no `pii_engine` now masks with `kev` and no fallback. Before, it masked with `captain-jev` and fell back to Presidio. To keep that behaviour, send `"pii_engine": "captain-jev"`.
* **Ordered fallbacks for `jev`**: `pii_fallback` takes an object, `{"engines": [...], "retry_budget_seconds": 60}`. List any of `jev-openrouter`, `jev-ai-gateway` and `kev` in the order to try them. Custom fields and instructions stay applied on every fallback. If every engine fails, that file fails to index and the rest of the job continues. See [Fallback](/guides/pii-masking#fallback).
* **Per-file engine report**: each file in [Get PII Report](/reference/jobs/pii/get) carries `requested_engine`, `used_engines`, `fallback_used`, `fallback_reason`, `coverage`, `model` and `image_redaction`.
* **Earlier engine names keep working**: `captain-jev` and `captain-presidio`, with the boolean `pii_fallback`, behave as before. See [Earlier engine names](/guides/pii-masking#earlier-engine-names).

## Webhooks for Indexing Jobs

* **Know when a job finishes, without polling**: Captain sends a signed HTTPS request to your endpoint when an indexing job ends. Each job sends exactly one event: `job.completed`, `job.completed_with_errors`, `job.failed`, `job.timed_out` or `job.cancelled`, with the `job_id`, file counts and a link to the full job. See [Webhooks](/guides/webhooks).
* **One endpoint for every job**: an endpoint receives events for every indexing job in the organization, from the API and from syncs, however many run at once. Match each event to the job you started with `data.job_id`. See [Many jobs at once](/guides/webhooks#many-jobs-at-once).
* **Set up in Studio or with the API**: add endpoints, send test events, read delivery logs and resend failed deliveries on the new **Webhooks** page in Captain Studio, or with the [Endpoint management](/reference/webhooks/endpoints/create) routes. The Captain MCP server adds `captain_webhook_setup` and `captain_webhook_events`.
* **Reliable delivery**: failed deliveries are retried for about 28 hours, and filters limit an endpoint to certain events, collections, syncs or sources. Each event's payload is documented under [Webhook events](/reference/webhooks/events/job-completed).

## Email Uploads and Chat Citations in Studio

* **Upload emails from Studio**: the file picker and drag-and-drop now accept `.msg` and `.eml` files, and email is listed with the other supported formats. An uploaded email is indexed the same way as through the API: one document for the message and one per attachment, linked by `email_attachment` and `email_reply_to` relations. See [Supported File Types](/guides/supported-file-types#email).
* **Chat answers quote their sources**: an answer on Home backs its key facts with one to three quoted passages, each attributed to the file and page it came from (or the timestamp, for audio and video). This replaces the numbered markers and the source list that sat under the answer.

## Email Ingestion

* **Email files (`.msg`, `.eml`)**: an email is indexed as a text document for the message and one document per attachment, each parsed as its own type. `email_attachment` and `email_reply_to` relations link the parts and the thread in both directions, and every part carries `email_*` metadata for filtering by thread, sender, subject, or date. See [Supported File Types](/guides/supported-file-types#email).

## Custom PII Fields

* **Mask identifiers of your own**: with `mask_pii: true`, `pii_fields` takes up to 20 categories described in plain language with a tag you choose. Badge numbers, patient record numbers, bed assignments and the like are masked alongside the built-in categories, stored as `<YOUR_TAG>` and listed under that name in the masking report. See [PII Masking](/guides/pii-masking#custom-pii-fields).
* **Say whose values count**: `pii_instructions` takes plain-language guidance for the job (keep clinician names, mask patients and record numbers) and applies it to built-in and custom categories.
* **Two engines**: `captain-jev` is the default. Captain's classifier engine reads every token in context and decides which values are personal data and of which kind, your categories included. It catches dates of birth, member ids, usernames and plates, and leaves version, ticket and product names alone. The previous engine remains as `pii_engine: "captain-presidio"`. Details: [Engines and fallback](/guides/pii-masking#engines).
* **Fallback is explicit and reported**: when the `captain-jev` model is unreachable, `pii_fallback` chooses between masking with the legacy engine (default) and failing the file. Job status, [Get PII Report](/reference/jobs/pii/get) and every report object carry `engine` and `fallback`.

## Query Latency Metrics

* **Latency over a period in one call**: [Get Query Latency](/reference/queries/latency) returns exact p50, p95 and p99 for every query matching your filters, a histogram with bin edges, and the same bins per collection. This used to mean paging [List Queries](/reference/queries/list) a hundred records at a time. Response size follows the number of bins, and windows cover up to 90 days.
* **Unrecorded times are counted, not averaged in**: `measured` and `missing` are reported separately, so a query with no timing stays out of the percentiles instead of counting as zero.
* **Filters say when a setting was never recorded**: filter by collection, environment, API version, rerank, search mode or metadata filter; each accepts `unknown` for queries that predate the field, and `coverage` reports what share recorded it.
* **Find the slow ones**: [List Slowest Queries](/reference/queries/latency/slowest) returns durations and identifiers that open in [Get Query](/reference/queries/get); [List Latency Collections](/reference/queries/latency/collections) pages the collections active in a window. Guide: [Query latency](/guides/query-latency). The hosted [MCP server](/guides/mcp) adds `captain_get_query_latency`.

## Evaluation API

* **Evaluate retrieval as a job**: upload up to 10,000 queries with the documents each should retrieve, then [Queue Evaluation](/reference/evals/create) runs them under one to eight named [v3 query](/reference/v3/query) configurations side by side. The eval runs as a paced job and keeps results, questions, configurations and every answer.
* **Scorecards per configuration**: [Get Evaluation Results](/reference/evals/get) returns recall at 1, 3 and 10, MRR, nDCG at 10 and latency percentiles per config, plus a result for every case under every config. Scoring is document level, like the MCP `captain_eval` tool.
* **Billed as queries**: each question under one configuration is one query at the plan's query price. Only queries that ran count; Captain-side failures and unresolvable expected documents do not. The `201` response previews the maximum before anything runs.
* **Every answer readable**: each result carries a `query_id`, and `GET /v3/evals/{eval_id}/answers/{case_id}/{config_name}` returns the stored `request` and `response` for one case under one configuration.
* Case-set format, gold resolution, limits and persistence: [Evaluations](/guides/evaluations).

Same day: [Evaluation Tools over MCP](/changelog/2026-09-16-mcp-eval-tools)

## Evaluation Tools over MCP

* **Run an eval over MCP**: the hosted [MCP server](/guides/mcp) adds `captain_create_eval_upload`, `captain_run_eval` and `captain_get_eval_results`, the three steps of the [Evaluation API](/guides/evaluations): upload up to 10,000 questions, queue them under one to eight named [v3 query](/reference/v3/query) configurations, poll for scorecards. They need an API-key connection, since the Evaluation API accepts API keys only in v1.
* **Retries replay instead of rerunning**: `captain_run_eval` derives an idempotency key from the collection, upload and configurations, so a repeated call returns the original eval instead of billing a second one.
* **Results sized for a conversation**: `captain_get_eval_results` returns status, progress, per-configuration scorecards, billing and a compact row per case (hit, rank, latency, `query_id`, error code), paged by cursor; `include_answers` adds the stored request and top results for up to 20 cases. `captain_eval` stays for quick client-side comparisons. The hosted server is now at 70 tools.

## Batch Metadata & Relations

* **Batch document metadata**: [`PATCH /v3/collections/{collection_name}/documents/metadata/batch`](/reference/v3/document/metadata/batch/update) merges custom metadata into up to 100 documents at once; [`PUT`](/reference/v3/document/metadata/batch/replace) replaces each document's whole object.
* **Batch chunk metadata**: the same two operations on chunks: [`PATCH`](/reference/v3/documents/chunk/metadata/batch/update) and [`PUT /v3/collections/{collection_name}/chunks/metadata/batch`](/reference/v3/documents/chunk/metadata/batch/replace).
* **Batch chunk relations**: [`PUT /v3/collections/{collection_name}/relations/batch`](/reference/v3/documents/chunk/relations/batch) creates or updates up to 100 relations, matched by source, target and `relation_type`.
* **One result per item**: a `200` carries `succeeded`, `failed` or `unknown` per item in request order; a failed item never rolls back the others.
* Envelope, partial success and limits: [Batch Metadata & Relations](/guides/batch-writes). Over MCP: `captain_batch_document_metadata`, `captain_batch_chunk_metadata`, `captain_batch_chunk_relations`.

## Documents in Studio

* **Documents, a new page in Studio.** Pick an environment, a collection and a document, and see what Captain actually indexed from it. Every chunk is listed in order with its type and its page. The text is rendered the way the parser produced it, so a heading looks like a heading and a table looks like a table. Open any chunk to see its stored text and its metadata.
* **Chunks as a table.** Filter by chunk type or search the loaded chunks. Markdown files have no layout types, so they get no type column. A Rendered / Raw switch shows the stored text exactly as it is.
* **Figures.** Every figure the parser extracted, grouped by page, each with a link to the chunk it belongs to. These are the same crops the [asset URLs](/reference/v3/document/asset-urls) endpoint returns.
* **Edit metadata in place.** Change the custom metadata on a document or on any chunk directly from the page. Saving replaces the whole set, the same way the [document](/reference/v3/document/metadata/replace) and [chunk](/reference/v3/documents/chunk/metadata/replace) metadata endpoints work, so what you see is what your queries filter on. You can delete a document here as well.
* **Linked to the rest of Studio.** Open a document from its row on Home. From the document, jump to the collection's feed on Activity or to the job that indexed it. From a query in Activity, open the exact chunk it cited. Every view has its own URL, so a link to a document or a chunk survives a reload and can be shared.

Same day: [MCP server catches up with the API](/changelog/2026-09-11-mcp-server-api-parity), [Improved MCP Server](/changelog/2026-09-11-sign-in-to-the-mcp-server)

## MCP server catches up with the API

* **12 new tools on the hosted MCP server**, 64 in total: read a document or a single page, mint viewable URLs for figures, set or merge document metadata, list and roll back jobs, read or delete a job's PII report, validate a parsing script, create a Google Cloud Storage sync, and dry-run a sync's credentials before creating it.
* **Every indexing tool now takes the full request**: `custom_metadata`, `mask_pii`, `max_files`, `skip_existing`, `overwrite_existing`, `transcription_language`, and `parsing_script`. R2 takes the bucket's `jurisdiction`, including `us`; S3 accepts a cross-account role; YouTube takes `mode` (transcript, audio, or video).
* **Search**: `captain_search_v3` takes `max_chunks_per_document`; `captain_search` takes a metadata filter, semantic ratio, and rerank options, and returns `query_id` and `chunk_id` so results feed the query-history and chunk tools.
* **Job status** shows credits billed, per-file results with paging, YouTube fallbacks, and the PII report state. Details on [MCP Server](/guides/mcp).

Same day: [Improved MCP Server](/changelog/2026-09-11-sign-in-to-the-mcp-server)

## Improved MCP Server

* **Sign in to the hosted MCP server**: add `https://mcp.captain.dev/mcp` to Claude Code, Cursor, VS Code or any client with remote MCP sign-in; a browser opens on Captain's approval page to pick the organization, the environments and whether the connection may write.
* **One connection, every environment**: every tool takes an optional `environment` (`development`, `staging` or `production`), so one session can search development and production without reconnecting.
* Client configs for Claude Code, Codex, Cursor, VS Code, Devin and others: [MCP Server](/guides/mcp).

## Edge Routing

* **Edge routing for `api.captain.dev`**: requests now connect at an edge location near the caller and travel a private backbone to Captain, so connection handshakes no longer cross the public internet. Nothing changes in your integration.
* Most agent integrations open a fresh connection for each query, and that handshake is where the time went. Median [v3 Query](/reference/v3/query) time on a fresh connection, 100 samples per city:

| Calling from  | Before   | After  | Change |
| ------------- | -------- | ------ | ------ |
| São Paulo     | 805 ms   | 590 ms | −27%   |
| Singapore     | 1,136 ms | 692 ms | −39%   |
| Sydney        | 1,065 ms | 661 ms | −38%   |
| Dublin        | 687 ms   | 529 ms | −23%   |
| Frankfurt     | 738 ms   | 555 ms | −25%   |
| San Francisco | 641 ms   | 516 ms | −20%   |
| Portland      | 656 ms   | 551 ms | −16%   |

Same day: [US Jurisdiction for Cloudflare R2](/changelog/2026-09-10-r2-us-jurisdiction)

## US Jurisdiction for Cloudflare R2

* **Index and sync US-jurisdiction R2 buckets**: `jurisdiction` on the [R2 indexing](/reference/indexing/r2/bucket) and [R2 sync](/reference/sync/r2/create) requests now accepts `us` alongside `default` (global), `eu`, and `fedramp`. Jurisdiction-restricted buckets are only visible through their jurisdiction's endpoint, so a US-restricted bucket previously could not be reached at all; pass `"jurisdiction": "us"` and Captain talks to `https://<account_id>.us.r2.cloudflarestorage.com`. The [cloud storage guide](/guides/connect-cloud-storage#r2-jurisdictions) lists all four options.

## Document Diversity

* **Cap one document's share of the ranked list**: `max_chunks_per_document` on the [v3 Query](/reference/v3/query) request stops a single long file from occupying every result slot. Surplus chunks drop and the page backfills with the next best chunks from other documents; ranking is unchanged, only the page composition is.

Same day: [Studio Improvements](/changelog/2026-09-09-studio-surfaces), [Terminal Job Stages](/changelog/2026-09-09-terminal-job-stages)

## Studio Improvements

* **Indexing options on Home**: a popover next to the Advanced / Basic choice sets Mask PII (`mask_pii`), skip or overwrite existing files (`skip_existing` / `overwrite_existing`), tags (`custom_metadata`, with reserved and `$`-prefixed keys rejected as you type), and the spoken language for audio and video (`transcription_language`). **Remember for this collection** keeps the processing type, Mask PII, and skip/overwrite choice as the collection's defaults, and Google Drive, SharePoint, and Dropbox continuous syncs re-index with them. New source tiles cover URLs, YouTube (transcript, audio, or video mode plus `on_missing_transcript`), and S3, GCS, Azure Blob, R2, Supabase, and Backblaze, all without an API key in the browser.
* **Search settings in the chat**: results per collection, rerank on/off with the model (`voyage-rerank-2.5`, `voyage-rerank-3`, `gemini-2.5-flash`, `gemini-3.8-flash`) and candidate limit, the keyword ↔ semantic balance (`semantic_ratio`), skipped chunk types, archived documents, and a metadata filter, remembered per organization in the browser. The **view code** panel now shows the [v3 Query](/reference/v3/query) request the settings produce, next to the v2 answer mode, with a parameter table.
* **Playground covers every public endpoint**: v3 Query with `semantic_ratio`, rerank Off / On / Custom, `exclude_chunk_types`, `boost`, all `include` keys, and relations; v2 Query; [query history](/reference/queries/list) list and get (by `query_id` or `request_id`); multipart file upload; parsing script validation; document page, asset URLs, and metadata; Azure Blob sync create and a credentials check; job PII report get and delete; feedback. Query cards render a ranked results view with total, server time, rerank model, and `query_id`, and every card exports cURL, Python, and TypeScript.
* **Sync Manager**: Azure Blob Storage as a provider (`container`, `account_name`, `account_key`, with Event Grid guidance in the Webhook dialog), tags on create, **Rotate secret** for webhooks (`rotate_secret`), and an Environment choice on the create form. Syncs stay organization-wide; the choice picks the target collection's environment, and an API key must exist there (`412` otherwise).
* **Activity**: **Cancel job** for running or queued jobs ([`DELETE /v2/jobs/{job_id}`](/reference/jobs/cancel)) and **Roll back** for finished ones ([`PATCH /v2/jobs/{job_id}/rollback`](/reference/jobs/rollback)); a PII masking row with the report state and the `GET /v2/jobs/{job_id}/pii` call; file rows that expand to URI, document id, status, stage, error, and update time.
* **API Keys and usage**: renaming a key persists, **Rotate key** reveals the new secret once and retires the old one immediately, and the sidebar usage figure sums the current billing period from the same source as the Usage page.
* **Faster chunk and document reads**: [`GET /v3/collections/{collection_name}/chunks`](/reference/v3/documents/chunks) and [`GET /v3/collections/{collection_name}/documents/{document_id}`](/reference/v3/document) no longer transfer each chunk's stored embedding from the index before dropping it. A 100-chunk page went from about 3 s to under a second, and a 317-chunk document from 9 s to under half a second, with the same response bodies. The same routes back the Playground's document and chunk cards and the MCP `captain_list_chunks` tool.

## Terminal Job Stages

* **Jobs report a terminal stage**: a finished job's `progress.current_stage` now ends at `completed`, `failed`, or `cancelled` instead of sitting on `finalizing` forever, and per-file `stage` values end at `completed` (indexed or skipped; the file's `status` carries which) or `failed`. A job whose files all failed now says `Job failed` rather than `Job completed`.

Same day: [Studio Improvements](/changelog/2026-09-09-studio-surfaces)

_Showing the 20 most recent of 95 entries. Append `/llms.txt` to the changelog URL for the complete index._