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

# Query - v3

POST https://api.captain.dev/v3/collections/{collection_name}/query
Content-Type: application/json

Search indexed files and return source chunks with optional document, metadata, region (bounding boxes), relation, and related chunk context.

**Compared with v2:** this response uses `results[].text`, supports explicit include controls, and returns structured rerank details.

**Filter keys are top-level field names.** Never nest them under `metadata` or `custom_metadata`. Use `{"policy_area": "payments"}`, not `{"custom_metadata": {"policy_area": "payments"}}`. Operators are `$`-prefixed (`$gte`, not `gte`). See the [Advanced Querying guide](/guides/advanced-querying) for the full filter reference.

Reference: https://docs.captain.dev/reference/v3/query

## Request

### Path parameters

- `collection_name` (string, required)

### Body (application/json)

This endpoint expects a QueryRequestV3.

- `query` (string, required) — Natural-language search query.
- `limit` (integer, optional, default: 10) — Maximum number of ranked chunks to return.
- `filter` (QueryRequestV3Filter, optional, nullable) — Document metadata filter expression. Keys are top-level field names, never nested under `metadata` or `custom_metadata`. A bare value is an implicit `$eq` (`{"policy_area": "payments"}`). Supported operators: `$eq` (=), `$ne` (≠), `$gt` (>), `$gte` (≥), `$lt` (\<), `$lte` (≤), `$in`, `$nin`, and the logical `$and` and `$or`. `$in` and `$nin` take a list; every other operator takes a scalar. Max nesting depth is 10. To scope a query to specific documents, filter on `file_id` with `$in`. See the [Advanced Querying guide](/guides/advanced-querying) for more.
- `rerank` (QueryRequestV3Rerank, optional, default: false) — Rerank retrieved candidates before returning the top results (adds roughly 200 ms). Boolean form uses the defaults: voyage-rerank-2.5 over a pool of `limit` x 3 candidates. Object form tunes reranking — see RerankOptions. Multimodal collections default to reranking; an explicit `false` (or `{"enabled": false}`) opts out and returns a warning noting reduced cross-modal ranking quality.
- `include` (QueryIncludeV3, optional) — Controls which optional result objects are included in the response.
- `relation_types` (list of string, optional, nullable) — Optional relation type filter when `include.relations` or `include.related_chunks` is enabled.
- `relation_direction` (enum, optional, default: outgoing) — Which graph edge direction to include for relation context.
  - Allowed values: `outgoing`, `incoming`, `both`
- `exclude_chunk_types` (list of enum, optional, nullable) — Layout roles to drop from results: body, table, heading, page_header, page_footer, footnote, figure. Useful for removing repeated page furniture such as running headers and footnotes. Applied during retrieval, before reranking, so excluded chunks never occupy a result slot. Chunks with no layout label always pass. Unknown values return a 400.
  - Allowed values: `body`, `table`, `heading`, `page_header`, `page_footer`, `footnote`, `figure`
- `boost` (list of BoostClauseV3, optional, nullable) — Optional metadata-based ranking: a list of up to 10 boost rules, each naming some of your own custom_metadata and how much to favour the chunks carrying it. Use it when a chunk is the right answer but does not match the query's wording, for example one a reviewer tagged as the answer to this question, or one your application already cited earlier in a conversation. Each rule both retrieves chunks carrying that metadata and multiplies their retrieval score by `weight`. With reranking on the reranker still decides the final order unless a rule sets `reserve`. Omit the field entirely and retrieval is unchanged. See the Advanced Search guide for choosing a weight.
- `semantic_ratio` (double, optional, default: 0.5) — Balance between semantic and keyword retrieval. Captain searches both ways at once: keyword (sparse, BM25) matches the words in the query, semantic (dense vector) matches its meaning. 0.0 is keyword only, 1.0 is semantic only, and 0.5 (the default) weighs them equally. Lower it for corpora full of exact terms such as part numbers or error codes; raise it when callers phrase questions in their own words. Between the endpoints both searches run, so a result found only by the down-weighted side still appears, just lower. The endpoints skip the other search entirely: 0.0 also skips embedding the query, making it the fastest option, though queries using `boost` and collections holding images, video, or audio keep vector search running. See the Advanced Querying guide for more.
- `max_chunks_per_document` (integer, optional, nullable) — Cap on how many chunks any single document may occupy in `results`. Ranking is unchanged: the same ranked chunks come back, minus a document's surplus beyond the cap, backfilled with the next best chunks from other documents so `limit` results still come back whenever the ranked pool has them. The cap is applied inside retrieval itself, so the candidate pool spans many documents rather than being thinned after the fact. Omitted (the default) applies no cap. The two numbers compose: `limit = N x K` returns up to N documents with up to K chunks each, in document-rank order, and each result's `document` object (`include.document`, on by default) carries the document's id, filename, and source. For the five most relevant documents, send `limit: 5` with `max_chunks_per_document: 1`.

## Response

### 200

Query response.

- `query` (string, required) — Echo of the submitted query.
- `results` (list of FileSearchResultV3, required) — Retrieved source chunks sorted by final retrieval score.
- `total_results` (integer, required) — Number of results returned in this response.
- `limit` (integer, required) — Result limit applied to the request.
- `rerank` (QueryRerankV3, required) — Whether reranking was applied and why.
- `timing` (QueryTimingV3, required) — Always-on query processing timing, including successful empty results. Stage offsets share one monotonic origin; overlapping durations must not be summed.
- `warnings` (list of string, optional) — Non-fatal notices about the request or response, such as forced reranking for multimodal collections.
- `execution_time_ms` (integer, optional, nullable) — Compatibility alias for timing.total_ms. Prefer timing.total_ms for new integrations.
- `request_id` (string, optional, nullable) — Request identifier for support and trace lookup.
- `query_id` (string, optional, nullable) — Id of this query in your history. Fetch it back with GET /v2/queries/\{query\_id}. Present when the query was stored (completed, non-streamed queries).
- `exclude_chunk_types` (list of enum, optional, default: []) — The layout roles this query excluded, echoed back so a caller can confirm what the server applied. Empty when none were requested.
  - Allowed values: `body`, `table`, `heading`, `page_header`, `page_footer`, `footnote`, `figure`
- `boost` (list of BoostAppliedV3, optional, default: []) — The boost rules this query applied, each with `matched`, `in_pool`, and `on_page` counts. Always present; empty when no boost was sent.
- `semantic_ratio` (double, optional, default: 0.5) — The semantic/keyword balance applied to this query. Always present; 0.5 when the request did not set one.

## Errors

### 400 Bad Request Error

Invalid metadata filter.

- `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.

### 401 Unauthorized Error

Missing or invalid authentication.

- `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.

### 403 Forbidden Error

API key cannot query this collection.

- `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.

### 404 Not Found Error

Collection not found.

- `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.

## Types

### QueryRequestV3Filter

Document metadata filter expression. Keys are top-level field names, never nested under `metadata` or `custom_metadata`. A bare value is an implicit `$eq` (`{"policy_area": "payments"}`). Supported operators: `$eq` (=), `$ne` (≠), `$gt` (>), `$gte` (≥), `$lt` (\<), `$lte` (≤), `$in`, `$nin`, and the logical `$and` and `$or`. `$in` and `$nin` take a list; every other operator takes a scalar. Max nesting depth is 10. To scope a query to specific documents, filter on `file_id` with `$in`. See the [Advanced Querying guide](/guides/advanced-querying) for more.

### QueryRequestV3Rerank

Rerank retrieved candidates before returning the top results (adds roughly 200 ms). Boolean form uses the defaults: voyage-rerank-2.5 over a pool of `limit` x 3 candidates. Object form tunes reranking — see RerankOptions. Multimodal collections default to reranking; an explicit `false` (or `{"enabled": false}`) opts out and returns a warning noting reduced cross-modal ranking quality.

### QueryIncludeV3

Optional expansions for v3 query results. Leave expensive context off unless the caller needs it.

- `document` (boolean, optional, default: true) — Include the parent document object for each returned chunk.
- `metadata` (boolean, optional, default: true) — Include Captain-generated retrieval metadata and application-supplied chunk metadata.
- `regions` (boolean, optional, default: false) — Include extracted layout regions, including bounding boxes when available.
- `relations` (boolean, optional, default: false) — Include graph relations connected to each returned chunk.
- `related_chunks` (boolean, optional, default: false) — Include linked chunks for returned relations.
- `neighboring_chunks` (boolean, optional, default: false) — Include the chunk immediately before and after each result in the source file.
- `document_metadata` (boolean, optional, default: false)
- `archived` (boolean, optional, default: false) — Include chunks archived by a sync `archive` deletion policy. Archived content is excluded from search by default; set true to surface it.

### BoostClauseV3

One boost rule. A boost rule is one entry in the request's `boost` array: some metadata to look for, and how much to favour the chunks carrying it. Each rule is exactly one of three shapes, and anything else returns a 422: * `{ "field": ..., "eq": ..., "weight": ... }` - one metadata value * `{ "field": ..., "in": [...], "weight": ... }` - any of several values, and list-valued metadata * `{ "chunk_ids": [...], "weight": ... }` - specific chunks, by id `weight` is always required. The other properties are marked optional only because which ones apply depends on the shape: `field` is required with `eq` or `in`, and unused by a `chunk_ids` rule.

- `weight` (double, required) — Required. Multiplier on the matching chunk's retrieval score, 0.2 to 5.0. The rule's retrieval pass is what makes a chunk appear; the weight decides where it lands. 1.5 to 2.0 is a good default and is usually enough to lift a tagged chunk to the top. Use 3.0 to 5.0 when boosted chunks compete with each other, or when a rule matches many chunks. Below 1.0 demotes, and only reorders chunks the query already found. When several rules match the same chunk their weights multiply, capped at 5.0.
- `field` (string, optional, nullable) — Required with `eq` or `in`; omit it for a `chunk_ids` rule. One of your own custom_metadata keys, the same keys `filter` accepts. Anything filterable is boostable, with no re-indexing. Captain's internal attributes (file_id, job_id, chunk_index and similar) return a 400.
- `eq` (BoostClauseV3Eq, optional, nullable) — Requires `field`. Boost chunks whose `field` equals this value. Strings, numbers, and booleans are supported. A list-valued field matches when any element equals it. Use `in` instead for several values.
- `in` (list of BoostClauseV3InItems, optional, nullable) — Requires `field`. Boost chunks whose `field` matches any of these values, up to 50. Use it for one key with several acceptable values, and for list-valued metadata.
- `chunk_ids` (list of string, optional, nullable) — Use instead of `field`/`eq`/`in` to boost specific chunks, up to 100. Accepts a `chunk_id` from a previous response, or `document_id:chunk_index`, which keeps resolving after the document is re-indexed. Use it to keep a follow-up question anchored to passages an earlier answer cited.
- `reserve` (integer, optional, default: 0) — With reranking on, guarantee this many of this rule's chunks a place on the page, chosen by reranker order. Reranking runs after boosting and can otherwise drop a boosted chunk whose text does not resemble the query. 0 (default) leaves the reranker's judgement in charge. The sum across all boost rules cannot exceed `limit`.

### FileSearchResultV3

A retrieved chunk from an indexed file.

- `chunk_id` (string, required) — Stable identifier for the retrieved chunk. Chunk IDs include the parent document identifier and chunk index.
- `score` (double, required) — Final retrieval score used to rank the result. Use it to compare results within the same response, not across unrelated collections.
- `text` (string, required) — Retrieved chunk text.
- `modality` (enum, optional, default: unknown) — Indexed content type that matched the query.
  - Allowed values: `text`, `pdf`, `document`, `image`, `audio`, `video`, `spreadsheet`, `unknown`
- `match_sources` (list of enum, optional) — Retrieval signals that contributed to the match, such as `content_embedding`, `keyword`, `ocr`, `table`, `transcript`, `metadata`, or `summary`.
  - Allowed values: `content_embedding`, `transcript`, `ocr`, `table`, `metadata`, `summary`, `keyword`
- `document` (FileSearchDocumentV3, optional, nullable) — Parent file for the chunk when `include.document` is enabled.
- `location` (FileSearchLocationFromV3, optional, nullable) — Where the chunk appears inside the source file. PDF and document results use page fields, media results use time fields, and spreadsheet results use sheet, row, and column fields.
- `media` (FileSearchMediaV3, optional, nullable) — Media-specific context for audio and video results, such as transcript data for the retrieved segment.
- `regions` (list of FileSearchRegionFromV3, optional, nullable) — Extracted layout regions when `include.regions` is enabled. Regions can represent OCR text, form fields, headings, tables, charts, or image areas.
- `metadata` (FileSearchResultV3Metadata, optional, nullable) — Captain-generated retrieval, ranking, source location, and indexed content metadata.
- `custom_metadata` (FileSearchResultV3CustomMetadata, optional, nullable) — Application-supplied chunk metadata from indexing or chunk metadata update endpoints.
- `rerank_score` (double, optional, nullable) — Score assigned by the reranker for this result when reranking is applied.
- `relations` (list of ChunkRelationFromV3, optional, nullable) — Graph edges connected to the retrieved chunk when relation context is requested.
- `related_chunks` (list of RelatedChunkV3, optional, nullable) — Linked chunks returned with relation context, including their text, location, and metadata when available.
- `neighboring_chunks` (ChunkNeighborsV3, optional, nullable) — The chunk immediately before and after this result in the source file, when `include.neighboring_chunks` is enabled.
- `chunk_type` (enum, optional, nullable) — Layout role of this chunk, classified from the parser's block structure at indexing time: body, table, heading, page_header, page_footer, footnote, or figure. Null when the chunk has no label: content indexed before chunk types shipped, plain-text and media content, or regions the parser returned without block structure. Treat unknown future values as additive.
  - Allowed values: `body`, `table`, `heading`, `page_header`, `page_footer`, `footnote`, `figure`
- `boost` (ResultBoostV3, optional, nullable) — Set when a boost rule matched this result; null otherwise.

### QueryRerankV3

Reranking status for the query response.

- `used` (boolean, required) — Whether reranking was applied.
- `reason` (enum, required) — Why reranking was applied or skipped.
  - Allowed values: `requested`, `disabled`, `required_for_multimodal`, `default_for_multimodal`
- `model` (string, optional, nullable) — The reranker model that ran. Null when reranking was not applied.
- `candidate_limit` (integer, optional, nullable) — The candidate pool size that was reranked. Null when reranking was not applied.
- `fallback` (string, optional, nullable) — Recorded rerank fallback outcome, when available. Read alongside used, reason, model, candidate_limit, and warnings.

### QueryTimingV3

- `stages` (list of QueryStageV3, required) — Measured stage groups ordered by start offset. Each stage name appears once; repeated work is preserved in segments. Groups can overlap. Skipped operations are omitted. Asset signing, when performed during hydration, is nested inside that hydration interval, not additional disjoint time. Offsets and endpoints use one monotonic origin, rounded down to milliseconds.
- `total_ms` (integer, required) — Query processing time from handler entry before authentication through response model construction. Excludes gateway routing, request-body parsing, JSON serialization, compression, network transfer, client decoding, and background tracking. Measured independently, never summed from stages.

### BoostAppliedV3

One boost rule, echoed back with what it did. See BoostClauseV3 on the request for what each property means.

- `weight` (double, required) — The multiplier this rule applied.
- `field` (string, optional, nullable) — The metadata key this rule targeted.
- `eq` (BoostAppliedV3Eq, optional, nullable) — The value this rule matched on.
- `in` (list of BoostAppliedV3InItems, optional, nullable) — The values this rule matched on.
- `chunk_ids` (list of string, optional, nullable) — The chunks this rule targeted.
- `reserve` (integer, optional, default: 0) — Page slots this rule guaranteed. 0 means the reranker decided.
- `matched` (integer, optional, default: 0) — Retrieved chunks this rule matched.
- `in_pool` (integer, optional, default: 0) — Matched chunks that reached reranking. Equals `matched` when reranking is off.
- `on_page` (integer, optional, default: 0) — Matched chunks in the results returned.
- `applied` (boolean, optional, default: true) — False when boosts were skipped; a warning explains why.

### RerankOptions

Object form of the `rerank` parameter. The boolean form stays valid: `true` is equivalent to sending this object with every field at its default.

- `enabled` (boolean, optional, default: true) — Whether to rerank. Sending the object without this field means enabled — the object form exists to tune reranking.
- `candidate_limit` (integer, optional, nullable) — How many fused retrieval candidates are fetched and reranked before the top `limit` results are returned. Defaults to `limit` x 3 (the measured configuration). Must be >= `limit`; capped at 200. Larger pools can lift recall on corpora with many near-duplicate documents, at the cost of rerank latency.
- `model` (string, optional, nullable) — Reranker model. Voyage cross-encoders: `voyage-rerank-2.5` (default) and `voyage-rerank-3` (aliases `rerank-2.5`, `rerank-3`). Gemini LLM rerankers: `gemini-2.5-flash` and `gemini-3.8-flash` — higher quality ceiling on complex queries, higher latency; best with small candidate pools. The family aliases `voyage` and `gemini` resolve to each family's default. Unknown values return a 400 listing the allowed set.

### BoostClauseV3Eq

Requires `field`. Boost chunks whose `field` equals this value. Strings, numbers, and booleans are supported. A list-valued field matches when any element equals it. Use `in` instead for several values.

### BoostClauseV3InItems

### FileSearchDocumentV3

Parent document for a returned chunk.

- `id` (string, optional, nullable) — Document identifier.
- `filename` (string, optional, nullable) — Original or indexed filename.
- `source` (FileSearchSourceV3, optional, nullable) — Original source location and MIME type for the document.
- `custom_metadata` (map from string to any, optional, nullable)

### FileSearchLocationFromV3

- `page_start` (integer, optional, nullable)
- `page_end` (integer, optional, nullable)
- `chunk_index` (integer, optional, nullable)
- `parent_chunk_index` (integer, optional, nullable)
- `start_seconds` (double, optional, nullable)
- `end_seconds` (double, optional, nullable)
- `sheet_name` (string, optional, nullable)
- `row_start` (integer, optional, nullable)
- `row_end` (integer, optional, nullable)
- `col_start` (integer, optional, nullable)
- `col_end` (integer, optional, nullable)

### FileSearchMediaV3

Media-specific context for audio and video chunks.

- `transcript` (string, optional, nullable) — Transcript text associated with the returned media segment.

### FileSearchRegionFromV3

- `type` (string, optional, nullable) — Region category, such as `text`, `title`, `section_header`, `key_value`, `table`, `figure`, `chart`, or `image`. Regions of type `figure`, `chart`, or `image` also carry a cropped `image_url` (a visual citation).
- `text` (string, optional, nullable)
- `page` (integer, optional, nullable)
- `bbox` (map from string to double, optional, nullable)
- `confidence` (string, optional, nullable)
- `image_url` (string, optional, nullable) — Short-lived presigned URL to a cropped image of the region (a visual citation), returned for `figure`, `chart`, and `image` regions when `include.regions` is true. Null for text regions and for documents indexed before figure cropping was enabled. Fetch promptly — the link expires within minutes.
- `description` (string, optional, nullable)

### FileSearchResultV3Metadata

Captain-generated retrieval, ranking, source location, and indexed content metadata.

### FileSearchResultV3CustomMetadata

Application-supplied chunk metadata from indexing or chunk metadata update endpoints.

### ChunkRelationFromV3

- `relation_id` (string, required)
- `source_chunk_id` (string, required)
- `target_chunk_id` (string, required)
- `relation_type` (string, required)
- `target_document_id` (string, optional, nullable)
- `target_status` (enum, optional, default: unknown)
  - Allowed values: `found`, `missing`, `unknown`
- `metadata` (ChunkRelationFromV3Metadata, optional)
- `created_at` (string, optional, nullable)
- `updated_at` (string, optional, nullable)

### RelatedChunkV3

Chunk linked to a search result through a requested relation.

- `chunk_id` (string, required) — Related chunk identifier.
- `document_id` (string, optional, nullable) — Parent document identifier for the related chunk.
- `text` (string, optional, nullable) — Related chunk text when included.
- `location` (FileSearchLocationFromV3, optional, nullable) — Source position for the related chunk.
- `metadata` (RelatedChunkV3Metadata, optional, nullable) — Metadata associated with the related chunk.
- `chunk_type` (enum, optional, nullable) — Layout role of this chunk, classified from the parser's block structure at indexing time: body, table, heading, page_header, page_footer, footnote, or figure. Null when the chunk has no label: content indexed before chunk types shipped, plain-text and media content, or regions the parser returned without block structure. Treat unknown future values as additive. Present on related and neighboring chunks as well.
  - Allowed values: `body`, `table`, `heading`, `page_header`, `page_footer`, `footnote`, `figure`

### ChunkNeighborsV3

The chunks immediately before and after a result in the source file, returned when `include.neighbors` is enabled.

- `prev` (RelatedChunkV3, optional, nullable) — The chunk immediately before this result in the source file. Null when this result is the first chunk.
- `next` (RelatedChunkV3, optional, nullable) — The chunk immediately after this result in the source file. Null when this result is the last chunk.

### ResultBoostV3

Why a result was boosted, and where it stood before the boost.

- `multiplier` (double, required) — The combined weight applied to this chunk, capped at 5.0.
- `clauses` (list of integer, optional, default: []) — Which boost rules matched, as positions in the request's `boost` array.
- `pre_boost_rank` (integer, optional, nullable) — This chunk's retrieval rank before the boost, 1-based.
- `pre_boost_score` (double, optional, nullable) — This chunk's retrieval score before the boost.
- `reserved` (boolean, optional, default: false) — True when `reserve` placed this result on the page rather than its score.

### QueryStageV3

- `name` (string, required) — Public operation name. New names may be added; clients must tolerate unknown names.
- `start_ms` (integer, required) — Start offset in milliseconds from the shared query-processing origin.
- `duration_ms` (integer, required) — Wall-clock extent from this stage's first start to last finish. May overlap other stages. Use segments when present to preserve gaps and concurrent intervals.
- `segments` (list of QueryStageSegmentV3, optional, nullable) — Actual intervals when a stage runs more than once. Do not add overlapping durations or infer continuous work between them.

### BoostAppliedV3Eq

The value this rule matched on.

### BoostAppliedV3InItems

### FileSearchSourceV3

Original source information for an indexed file.

- `type` (string, optional, nullable) — Source kind, such as uploaded file, cloud object, URL, or Captain-managed file.
- `uri` (string, optional, nullable) — Original file URI or Captain-managed URI.
- `mime_type` (string, optional, nullable) — MIME type when known.

### ChunkRelationFromV3Metadata

### RelatedChunkV3Metadata

Metadata associated with the related chunk.

### QueryStageSegmentV3

- `start_ms` (integer, required)
- `duration_ms` (integer, required)

## Examples

### Basic search

**Request**

```json
{
  "query": "payment authorization requirements",
  "limit": 3
}
```

**Response**

```json
{
  "query": "payment authorization requirements",
  "results": [
    {
      "chunk_id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744:0",
      "score": 0.09523809523809523,
      "text": "# Payment authorization form\n\nI authorize the merchant to charge the card on file for approved purchases.\n\nAmount authorized: <empty>\nCardholder email: <empty>\nProduct or service: <empty>\n\n## Card information\n\nCard type:\n[ ] Visa\n[ ] Mastercard\n[ ] American Express\n[ ] Other <empty>\n\n## Recurring payments\n\nCharge frequency: <empty>\nPayment amount: <empty>\nCancellation terms: <empty>",
      "modality": "pdf",
      "match_sources": [
        "content_embedding",
        "keyword",
        "ocr"
      ],
      "document": {
        "id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744",
        "filename": "payment-authorization-form.pdf",
        "source": {
          "type": "file",
          "uri": "captain://org_example/users/user_example/collections/customer_forms/payment-authorization-form.pdf",
          "mime_type": null
        }
      },
      "location": {
        "page_start": 1,
        "page_end": 1,
        "chunk_index": 0,
        "parent_chunk_index": 0,
        "start_seconds": null,
        "end_seconds": null,
        "sheet_name": null,
        "row_start": null,
        "row_end": null,
        "col_start": null,
        "col_end": null
      },
      "media": null,
      "metadata": {
        "vectorScore": 0.42747492,
        "bm25Score": 2.2132137,
        "rrfScore": 0.09523809523809523,
        "pageStart": 1,
        "pageEnd": 1
      },
      "custom_metadata": {
        "document_type": "authorization_form",
        "review_status": "approved"
      },
      "rerank_score": null,
      "boost": null
    }
  ],
  "total_results": 1,
  "limit": 3,
  "rerank": {
    "used": false,
    "reason": "disabled",
    "model": null,
    "candidate_limit": null
  },
  "timing": {
    "stages": [
      {
        "name": "preparation",
        "start_ms": 0,
        "duration_ms": 13
      },
      {
        "name": "embedding",
        "start_ms": 13,
        "duration_ms": 37
      },
      {
        "name": "retrieval",
        "start_ms": 50,
        "duration_ms": 22
      },
      {
        "name": "fusion",
        "start_ms": 72,
        "duration_ms": 1
      },
      {
        "name": "hydration",
        "start_ms": 73,
        "duration_ms": 113
      }
    ],
    "total_ms": 186
  },
  "warnings": [],
  "execution_time_ms": 186,
  "request_id": "req_1787610044_2c8f41ab",
  "query_id": "019a0e2a-7b31-7c4e-9d2f-3a8c1e5b6f90",
  "exclude_chunk_types": [],
  "boost": []
}
```

**SDK Code**

```python Python REST
import requests

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

response = requests.post(
    f"{BASE_URL}/v3/collections/{COLLECTION_NAME}/query",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json={
        "query": "payment authorization requirements",
        "limit": 3,
    },
    timeout=60.0,
)

for result in response.json()["results"]:
    print(result["chunk_id"], round(result["score"], 4))
    print(result["text"][:200])

```

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

const response = await fetch(
  `${BASE_URL}/v3/collections/${COLLECTION_NAME}/query`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: "payment authorization requirements",
      limit: 3,
    }),
  },
);

const data = await response.json();
for (const result of data.results) {
  console.log(result.chunk_id, result.score.toFixed(4));
  console.log(result.text.slice(0, 200));
}

```

### Advanced search

**Request**

```json
{
  "query": "payment authorization requirements",
  "limit": 5,
  "filter": {
    "policy_area": "payments",
    "review_status": {
      "$in": [
        "approved",
        "in_review"
      ]
    }
  },
  "rerank": {
    "enabled": true,
    "candidate_limit": 40
  },
  "include": {
    "document": true,
    "metadata": true,
    "regions": true,
    "relations": true,
    "related_chunks": true,
    "neighboring_chunks": true
  },
  "relation_types": [
    "supporting_detail"
  ],
  "relation_direction": "both",
  "exclude_chunk_types": [
    "page_header",
    "page_footer",
    "footnote"
  ],
  "boost": [
    {
      "weight": 3,
      "field": "answers",
      "in": [
        "authorization-window"
      ],
      "reserve": 1
    },
    {
      "weight": 1.5,
      "field": "policy_area",
      "eq": "payments"
    }
  ],
  "semantic_ratio": 0.35,
  "max_chunks_per_document": 2
}
```

**Response**

```json
{
  "query": "payment authorization requirements",
  "results": [
    {
      "chunk_id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744:0",
      "score": 0.4128,
      "text": "# Payment authorization form\n\nI authorize the merchant to charge the card on file for approved purchases.\n\nAmount authorized: <empty>\nCardholder email: <empty>\nProduct or service: <empty>\n\n## Card information\n\nCard type:\n[ ] Visa\n[ ] Mastercard\n[ ] American Express\n[ ] Other <empty>\n\n## Recurring payments\n\nCharge frequency: <empty>\nPayment amount: <empty>\nCancellation terms: <empty>",
      "modality": "pdf",
      "match_sources": [
        "content_embedding",
        "keyword",
        "ocr",
        "metadata"
      ],
      "document": {
        "id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744",
        "filename": "payment-authorization-form.pdf",
        "source": {
          "type": "file",
          "uri": "captain://org_example/users/user_example/collections/customer_forms/payment-authorization-form.pdf",
          "mime_type": null
        }
      },
      "location": {
        "page_start": 1,
        "page_end": 1,
        "chunk_index": 0,
        "parent_chunk_index": 0,
        "start_seconds": null,
        "end_seconds": null,
        "sheet_name": null,
        "row_start": null,
        "row_end": null,
        "col_start": null,
        "col_end": null
      },
      "media": null,
      "regions": [
        {
          "type": "title",
          "text": "Payment authorization form",
          "page": 1,
          "bbox": {
            "top": 0.0619,
            "left": 0.0662,
            "width": 0.3382,
            "height": 0.0183
          },
          "confidence": "high",
          "image_url": null,
          "description": null
        },
        {
          "type": "key_value",
          "text": "Amount authorized: <empty>\nCardholder email: <empty>\nProduct or service: <empty>",
          "page": 1,
          "bbox": {
            "top": 0.2134,
            "left": 0.0621,
            "width": 0.8676,
            "height": 0.0385
          },
          "confidence": "high",
          "image_url": null,
          "description": null
        },
        {
          "type": "section_header",
          "text": "Card information",
          "page": 1,
          "bbox": {
            "top": 0.3283,
            "left": 0.098,
            "width": 0.1536,
            "height": 0.012
          },
          "confidence": "high",
          "image_url": null,
          "description": null
        },
        {
          "type": "figure",
          "text": null,
          "page": 1,
          "bbox": {
            "top": 0.4471,
            "left": 0.0662,
            "width": 0.4013,
            "height": 0.0788
          },
          "confidence": "high",
          "image_url": "https://captain-visual-citations.s3.amazonaws.com/crops/org_example/f4a91c7e8b2d4a0c9e6f13b5a8d02744/p1-0.png?AWSAccessKeyId=AKIAEXAMPLE&Expires=1785084004&Signature=EXAMPLESIGNATUREvalue%3D",
          "description": "Accepted card network logos (Visa, Mastercard, American Express)."
        }
      ],
      "metadata": {
        "vectorScore": 0.42747492,
        "bm25Score": 2.2132137,
        "rrfScore": 0.09523809523809523,
        "pageStart": 1,
        "pageEnd": 1
      },
      "custom_metadata": {
        "answers": [
          "authorization-window"
        ],
        "policy_area": "payments"
      },
      "rerank_score": 0.4128,
      "relations": [
        {
          "relation_id": "019ef651-2c1b-74d2-b2c9-example001",
          "source_chunk_id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744:0",
          "target_chunk_id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744:1",
          "relation_type": "supporting_detail",
          "target_document_id": null,
          "target_status": "found",
          "metadata": {
            "note": "Pair the authorization language with the signature block."
          },
          "created_at": "2026-06-23T21:09:35.388273Z",
          "updated_at": "2026-06-23T21:09:35.388273Z"
        }
      ],
      "related_chunks": [
        {
          "chunk_id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744:1",
          "document_id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744",
          "text": "Customer signature: <empty>\nDate: <empty>",
          "location": {
            "page_start": 1,
            "page_end": 1,
            "chunk_index": 1,
            "parent_chunk_index": 0,
            "start_seconds": null,
            "end_seconds": null,
            "sheet_name": null,
            "row_start": null,
            "row_end": null,
            "col_start": null,
            "col_end": null
          },
          "metadata": {
            "source": "vector",
            "modality": "text",
            "vectorScore": 0.50538486,
            "bm25Score": null,
            "rrfScore": 0.045454545454545456,
            "rerankScore": null,
            "pageStart": 1,
            "pageEnd": 1,
            "category": "signature_block"
          }
        }
      ],
      "neighboring_chunks": {
        "prev": null,
        "next": {
          "chunk_id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744:1",
          "document_id": "f4a91c7e8b2d4a0c9e6f13b5a8d02744",
          "text": "Customer signature: <empty>\nDate: <empty>",
          "location": {
            "page_start": 1,
            "page_end": 1,
            "chunk_index": 1,
            "parent_chunk_index": 0,
            "start_seconds": null,
            "end_seconds": null,
            "sheet_name": null,
            "row_start": null,
            "row_end": null,
            "col_start": null,
            "col_end": null
          },
          "metadata": {
            "source": "vector",
            "modality": "text",
            "vectorScore": 0.50538486,
            "bm25Score": null,
            "rrfScore": 0.045454545454545456,
            "rerankScore": null,
            "pageStart": 1,
            "pageEnd": 1,
            "category": "signature_block"
          }
        }
      },
      "boost": {
        "multiplier": 4.5,
        "clauses": [
          0,
          1
        ],
        "pre_boost_rank": 3,
        "pre_boost_score": 0.0417,
        "reserved": true
      }
    },
    {
      "chunk_id": "a1c3e5f7b9d24f6082ab46ce9d135790:0",
      "score": 0.5,
      "text": "[Video: product-demo.mp4, 0s-25s]\nThe clip shows a presenter explaining how payment authorization works. Visual elements include an approval checklist, a diagram of stored payment credentials, and a short walkthrough of recurring billing controls.",
      "modality": "video",
      "match_sources": [
        "keyword"
      ],
      "document": {
        "id": "a1c3e5f7b9d24f6082ab46ce9d135790",
        "filename": "product-demo.mp4",
        "source": {
          "type": "file",
          "uri": "s3://example-video-eval/payment/product-demo.mp4",
          "mime_type": "video/mp4"
        }
      },
      "location": {
        "page_start": null,
        "page_end": null,
        "chunk_index": 0,
        "parent_chunk_index": null,
        "start_seconds": null,
        "end_seconds": null,
        "sheet_name": null,
        "row_start": null,
        "row_end": null,
        "col_start": null,
        "col_end": null
      },
      "media": null,
      "regions": null,
      "metadata": {
        "bm25Score": 9.5263195,
        "rrfScore": 0.047619047619047616,
        "rerankScore": 0.75390625,
        "crossModalRrfScore": 0.5,
        "rerankOrigin": "text"
      },
      "custom_metadata": null,
      "rerank_score": 0.75390625,
      "relations": [],
      "related_chunks": [],
      "neighboring_chunks": null
    },
    {
      "chunk_id": "c9e8a7b6d5f4432190acbe1782345678:3",
      "score": 0.333333,
      "text": "The spreadsheet row lists authorization category, required approval, renewal cadence, and current policy owner for recurring payments.",
      "modality": "spreadsheet",
      "match_sources": [
        "table",
        "metadata"
      ],
      "document": {
        "id": "c9e8a7b6d5f4432190acbe1782345678",
        "filename": "billing-policy-controls.xlsx",
        "source": {
          "type": "file",
          "uri": "captain://org_example/users/user_example/collections/policies/billing-policy-controls.xlsx",
          "mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        }
      },
      "location": {
        "page_start": null,
        "page_end": null,
        "chunk_index": 3,
        "parent_chunk_index": null,
        "start_seconds": null,
        "end_seconds": null,
        "sheet_name": "authorization_controls",
        "row_start": 18,
        "row_end": 22,
        "col_start": 1,
        "col_end": 6
      },
      "media": null,
      "regions": null,
      "metadata": {
        "vectorScore": 0.38133752,
        "bm25Score": 4.10291,
        "rrfScore": 0.333333,
        "sheetName": "authorization_controls",
        "rowStart": 18,
        "rowEnd": 22,
        "colStart": 1,
        "colEnd": 6,
        "columns": [
          "policy",
          "approval_required",
          "renewal_cadence",
          "owner"
        ]
      },
      "custom_metadata": {
        "policy_area": "payments"
      },
      "rerank_score": 0.7109375,
      "relations": [],
      "related_chunks": [],
      "neighboring_chunks": null
    }
  ],
  "total_results": 3,
  "limit": 5,
  "rerank": {
    "used": true,
    "reason": "requested",
    "model": "voyage-rerank-2.5",
    "candidate_limit": 40
  },
  "timing": {
    "stages": [
      {
        "name": "preparation",
        "start_ms": 0,
        "duration_ms": 169
      },
      {
        "name": "embedding",
        "start_ms": 169,
        "duration_ms": 485
      },
      {
        "name": "retrieval",
        "start_ms": 654,
        "duration_ms": 291
      },
      {
        "name": "fusion",
        "start_ms": 945,
        "duration_ms": 24
      },
      {
        "name": "reranking",
        "start_ms": 969,
        "duration_ms": 1213
      },
      {
        "name": "hydration",
        "start_ms": 2182,
        "duration_ms": 245
      }
    ],
    "total_ms": 2427
  },
  "warnings": [],
  "execution_time_ms": 2427,
  "request_id": "req_20260623_example001",
  "query_id": "019a0e2a-7b31-7c4e-9d2f-3a8c1e5b6f90",
  "exclude_chunk_types": [
    "page_header",
    "page_footer",
    "footnote"
  ],
  "boost": [
    {
      "weight": 3,
      "field": "answers",
      "in": [
        "authorization-window"
      ],
      "reserve": 1,
      "matched": 1,
      "in_pool": 1,
      "on_page": 1,
      "applied": true
    },
    {
      "weight": 1.5,
      "field": "policy_area",
      "eq": "payments",
      "matched": 2,
      "in_pool": 2,
      "on_page": 1,
      "applied": true
    }
  ]
}
```

**SDK Code**

```python Python REST
import json
import requests

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

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

response = requests.post(
    f"{BASE_URL}/v3/collections/{COLLECTION_NAME}/query",
    headers=headers,
    json={
        "query": "payment authorization requirements",
        "limit": 5,
        # Lean toward keyword matching; these documents are full of exact
        # policy terms. 0.0 is keyword only, 1.0 semantic only, 0.5 balanced.
        "semantic_ratio": 0.35,
        # Rerank the top candidates with a cross-encoder before returning.
        "rerank": {"enabled": True, "candidate_limit": 40},
        # Cap one document's share of the page.
        "max_chunks_per_document": 2,
        # Restrict retrieval to documents matching this metadata.
        "filter": {
            "policy_area": "payments",
            "review_status": {"$in": ["approved", "in_review"]},
        },
        # Drop repeated page furniture from the results.
        "exclude_chunk_types": ["page_header", "page_footer", "footnote"],
        # Promote chunks your own metadata marks as relevant. `reserve` keeps
        # the reviewer-tagged chunk on the page even if the reranker disagrees.
        "boost": [
            {
                "field": "answers",
                "in": ["authorization-window"],
                "weight": 3.0,
                "reserve": 1,
            },
            {"field": "policy_area", "eq": "payments", "weight": 1.5},
        ],
        # Ask for the extra context this UI renders.
        "include": {
            "document": True,
            "metadata": True,
            "regions": True,
            "relations": True,
            "related_chunks": True,
            "neighboring_chunks": True,
        },
        "relation_types": ["supporting_detail"],
        "relation_direction": "both",
    },
    timeout=60.0,
)
data = response.json()

# Each boost rule reports what it did.
for rule in data["boost"]:
    field = rule.get("field") or "chunk_ids"
    print(f"{field}: matched={rule['matched']} on_page={rule['on_page']}")

for result in data["results"]:
    print(result["chunk_id"], round(result["score"], 4), result["match_sources"])
    boost = result.get("boost")
    if boost:
        print(
            f"  boosted x{boost['multiplier']} from rank "
            f"{boost['pre_boost_rank']} (reserved={boost['reserved']})"
        )

# Warnings explain anything that did less than you asked.
for warning in data.get("warnings", []):
    print("warning:", warning)

```

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

const headers = {
  Authorization: `Bearer ${API_KEY}`,
  "Content-Type": "application/json",
};

const response = await fetch(
  `${BASE_URL}/v3/collections/${COLLECTION_NAME}/query`,
  {
    method: "POST",
    headers,
    body: JSON.stringify({
      query: "payment authorization requirements",
      limit: 5,
      // Lean toward keyword matching; these documents are full of exact
      // policy terms. 0.0 is keyword only, 1.0 semantic only, 0.5 balanced.
      semantic_ratio: 0.35,
      // Rerank the top candidates with a cross-encoder before returning.
      rerank: { enabled: true, candidate_limit: 40 },
      // Cap one document's share of the page.
      max_chunks_per_document: 2,
      // Restrict retrieval to documents matching this metadata.
      filter: {
        policy_area: "payments",
        review_status: { $in: ["approved", "in_review"] },
      },
      // Drop repeated page furniture from the results.
      exclude_chunk_types: ["page_header", "page_footer", "footnote"],
      // Promote chunks your own metadata marks as relevant. `reserve` keeps
      // the reviewer-tagged chunk on the page even if the reranker disagrees.
      boost: [
        {
          field: "answers",
          in: ["authorization-window"],
          weight: 3.0,
          reserve: 1,
        },
        { field: "policy_area", eq: "payments", weight: 1.5 },
      ],
      // Ask for the extra context this UI renders.
      include: {
        document: true,
        metadata: true,
        regions: true,
        relations: true,
        related_chunks: true,
        neighboring_chunks: true,
      },
      relation_types: ["supporting_detail"],
      relation_direction: "both",
    }),
  },
);
const data = await response.json();

// Each boost rule reports what it did.
for (const rule of data.boost) {
  const field = rule.field ?? "chunk_ids";
  console.log(`${field}: matched=${rule.matched} on_page=${rule.on_page}`);
}

for (const result of data.results) {
  console.log(result.chunk_id, result.score.toFixed(4), result.match_sources);
  if (result.boost) {
    console.log(
      `  boosted x${result.boost.multiplier} from rank ` +
        `${result.boost.pre_boost_rank} (reserved=${result.boost.reserved})`,
    );
  }
}

```