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

# Get Query Latency

GET https://api.filesearch.dev/v2/queries/latency

Latency percentiles and a histogram for a window of your stored queries.

Unlike GET /v2/queries, which pages through individual records, this
summarises the whole filtered population in one bounded response: counts,
exact p50/p95/p99, explicit histogram edges, and the same bins per
collection so their shapes can be compared.

Two numbers are reported separately on purpose. `counts.measured` are the
queries with a recorded processing time; `counts.missing` are matching
queries without one, which are left out of the percentiles rather than
counted as zero milliseconds. `coverage` says how much of the population
recorded each filterable setting, because older queries predate some of
them and answer `unknown`.

Windows are capped at 90 days. Use GET /v2/queries to drill into
individual queries.

Reference: https://docs.runcaptain.com/reference/queries/latency

## Request

### Query parameters

- `from` (string, optional, nullable) — Start of the window, inclusive. ISO-8601 date or timestamp (UTC when no offset is given).
- `to` (string, optional, nullable) — End of the window, exclusive.
- `collection` (string, optional, nullable) — Only queries against this collection.
- `api_version` (string, optional, nullable) — `v3`, `v2`, or `unknown` for queries that recorded no version.
- `rerank` (string, optional, nullable) — The recorded rerank setting: `on`, `off`, or `unknown`. A setting of on does not mean reranking ran.
- `search_mode` (string, optional, nullable) — `keyword`, `semantic`, `hybrid`, or `unknown`, derived from the recorded semantic ratio.
- `has_filter` (string, optional, nullable) — `true`, `false`, or `unknown` for queries that recorded no filter setting.
- `bins` (integer, optional, nullable) — Histogram resolution (4-64; default 16). Edges are returned explicitly.
- `refresh` (boolean, optional, default: false) — Recompute instead of serving a briefly cached result.

## Response

### 200

Successful Response

- `completeness` (LatencyCompletenessV2, required)
- `counts` (LatencyCountsV2, required)
- `filters_applied` (LatencyFiltersAppliedV2, required)
- `generated_at` (string, required) — When these numbers were computed. A cached response keeps its original value.
- `histogram` (LatencyHistogramV2, required)
- `percentiles` (LatencyPercentilesV2, required)
- `population` (string, required) — Which queries the metric covers. Completed, non-evaluation queries: a failed query records no usage row, and evaluation units are excluded.
- `window` (LatencyWindowV2, required)
- `collections` (list of LatencyCollectionSeriesV2, optional)
- `coverage` (map from string to double, optional) — Per filter, the share of matching queries that recorded that dimension (0.0-1.0). A low value means most of the population answers `unknown`.
- `metric` ("query_processing_time", optional, default: query_processing_time) — What is being measured: server-side query processing time, not end-to-end client latency.
- `metric_version` (string, optional, default: 1)
- `percentile_method` ("exact", optional, default: exact) — Percentiles come from the measurements themselves, not an approximate sketch.
- `unit` ("ms", optional, default: ms)

## Errors

### 400 Bad Request Error

Missing or invalid window, filter value, or bin count.

- `code` (string, required) — Stable error code, for example `invalid_time_range`.
- `message` (string, required) — What went wrong.
- `path` (string, required) — The request path.

### 401 Unauthorized Error

Missing or invalid API key.

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

The API key does not have query permission.

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

### 422 Unprocessable Entity Error

Validation Error

- `error` (string, required) — `VALIDATION_ERROR`.
- `message` (string, required)
- `details` (list of V2QueriesLatencyGetResponsesContentApplicationJsonSchemaDetailsItems, required) — One entry per invalid field, with `type`, `loc` and `msg`.
- `path` (string, required)

### 503 Service Unavailable Error

Analytics are unavailable; no metrics were computed.

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

### LatencyCompletenessV2

- `complete` (boolean, required) — True when the window has settled past the ingestion lag, so no further rows are expected for it. This is a settled-not-filling signal, not a guarantee of wholeness: usage rows are written after the response and a failed write is not retried, so compare `watermark` against the window when exactness matters.
- `watermark` (string, optional, nullable) — The most recent query time seen in the window. How far the data actually reaches.

### LatencyCountsV2

- `matching` (integer, required) — Queries in the window that matched every filter.
- `measured` (integer, required) — Of those, the ones with a recorded processing time.
- `missing` (integer, required) — Of those, the ones with no recorded processing time. Not zero-millisecond queries.

### LatencyFiltersAppliedV2

- `api_version` (string, optional, nullable) — `v3` or `v2`.
- `collection` (string, optional, nullable) — Only queries against this collection.
- `has_filter` (enum, optional, nullable) — Whether the request carried a metadata filter.
  - Allowed values: `true`, `false`, `unknown`
- `query_environment` (string, optional, nullable) — The API key environment the queries ran in.
- `rerank` (enum, optional, nullable) — The recorded rerank request setting.
  - Allowed values: `on`, `off`, `unknown`
- `search_mode` (enum, optional, nullable) — Derived from the recorded semantic ratio.
  - Allowed values: `keyword`, `semantic`, `hybrid`, `unknown`

### LatencyHistogramV2

- `counts` (list of integer, required) — Measured queries per bin. Bin i spans edges[i] (inclusive) to edges[i+1] (exclusive); the last bin includes its upper edge.
- `edges` (list of integer, required) — Bin edges in ms, ascending. One more entry than `counts`.

### LatencyPercentilesV2

- `p50` (integer, optional, nullable) — Median processing time in ms; null when nothing was measured.
- `p95` (integer, optional, nullable) — 95th percentile in ms; null when nothing was measured.
- `p99` (integer, optional, nullable) — 99th percentile in ms; null when nothing was measured.

### LatencyWindowV2

- `from` (string, required) — Start of the window, inclusive (UTC).
- `to` (string, required) — End of the window, exclusive (UTC).

### LatencyCollectionSeriesV2

- `collection_name` (string, required) — The collection, or `Other` for the folded remainder.
- `count` (integer, required) — Measured queries against this collection.
- `counts` (list of integer, required) — Per-bin counts against the same edges as the overall histogram, so shapes are comparable.
- `is_other` (boolean, optional, default: false) — True for the folded remainder rather than a real collection.
- `p50` (integer, optional, nullable) — Median in ms; null for the `Other` group, whose percentiles cannot be derived exactly.
- `p95` (integer, optional, nullable) — 95th percentile in ms; null for `Other`.
- `p99` (integer, optional, nullable) — 99th percentile in ms; null for `Other`.

### V2QueriesLatencyGetResponsesContentApplicationJsonSchemaDetailsItems

## Examples

**Response**

```json
{
  "completeness": {
    "complete": true,
    "watermark": "2026-09-07T23:58:11.402Z"
  },
  "counts": {
    "matching": 2614,
    "measured": 2611,
    "missing": 3
  },
  "filters_applied": {
    "api_version": null,
    "collection": null,
    "has_filter": null,
    "query_environment": null,
    "rerank": null,
    "search_mode": null
  },
  "generated_at": "2026-09-08T00:04:02.118Z",
  "histogram": {
    "counts": [
      104,
      1387,
      702,
      298,
      81,
      39
    ],
    "edges": [
      0,
      200,
      400,
      600,
      800,
      1000,
      1200
    ]
  },
  "percentiles": {
    "p50": 287,
    "p95": 715,
    "p99": 1204
  },
  "population": "Completed, non-evaluation queries. A failed query records no usage row, and evaluation units are excluded.",
  "window": {
    "from": "2026-09-01T00:00:00Z",
    "to": "2026-09-08T00:00:00Z"
  },
  "collections": [
    {
      "collection_name": "customer_forms",
      "count": 1902,
      "counts": [
        88,
        1094,
        486,
        190,
        30,
        14
      ],
      "is_other": false,
      "p50": 271,
      "p95": 668,
      "p99": 1122
    },
    {
      "collection_name": "policy_library",
      "count": 512,
      "counts": [
        12,
        221,
        158,
        83,
        27,
        11
      ],
      "is_other": false,
      "p50": 352,
      "p95": 790,
      "p99": 1290
    },
    {
      "collection_name": "Other",
      "count": 197,
      "counts": [
        4,
        72,
        58,
        25,
        24,
        14
      ],
      "is_other": true,
      "p50": null,
      "p95": null,
      "p99": null
    }
  ],
  "coverage": {
    "rerank": 0.99,
    "search_mode": 0.69,
    "has_filter": 0.15
  },
  "metric": "query_processing_time",
  "metric_version": "1",
  "percentile_method": "exact",
  "unit": "ms"
}
```

**SDK Code**

```python Python
import requests

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

response = requests.get(
    f"{BASE_URL}/v2/queries/latency",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={
        "from": "2026-09-01",
        "to": "2026-09-08",
        "bins": 6,
    },
    timeout=30.0
)

if response.status_code == 200:
    data = response.json()
    p = data["percentiles"]
    counts = data["counts"]
    print(f"p50={p['p50']} ms  p95={p['p95']} ms  p99={p['p99']} ms")
    print(f"{counts['measured']} of {counts['matching']} queries measured, "
          f"{counts['missing']} without a recorded duration")
    for c in data["collections"]:
        # The "Other" bucket carries counts but no percentiles: a summed
        # histogram cannot yield an exact quantile.
        shown = f"p95={c['p95']} ms" if c["p95"] is not None else "no percentiles"
        print(f"  {c['collection_name']:24s} {c['count']:6d} queries  {shown}")
    if not data["completeness"]["complete"]:
        print(f"Partial: usage is written up to {data['completeness']['watermark']}")
else:
    print(f"Error: {response.status_code}")
```

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

type Series = { collection_name: string; count: number; p95: number | null };
type Latency = {
    percentiles: { p50: number | null; p95: number | null; p99: number | null };
    counts: { matching: number; measured: number; missing: number };
    collections: Series[];
    completeness: { watermark: string | null; complete: boolean };
};

const query = new URLSearchParams({
    from: "2026-09-01",
    to: "2026-09-08",
    bins: "6"
});

const response = await fetch(`${BASE_URL}/v2/queries/latency?${query}`, {
    headers: { Authorization: `Bearer ${API_KEY}` }
});

if (response.ok) {
    const data: Latency = await response.json();
    const { p50, p95, p99 } = data.percentiles;
    console.log(`p50=${p50} ms  p95=${p95} ms  p99=${p99} ms`);
    console.log(
        `${data.counts.measured} of ${data.counts.matching} queries measured, ` +
        `${data.counts.missing} without a recorded duration`
    );
    for (const c of data.collections) {
        // The "Other" bucket carries counts but no percentiles: a summed
        // histogram cannot yield an exact quantile.
        const shown = c.p95 !== null ? `p95=${c.p95} ms` : "no percentiles";
        console.log(`  ${c.collection_name}  ${c.count} queries  ${shown}`);
    }
    if (!data.completeness.complete) {
        console.log(`Partial: usage is written up to ${data.completeness.watermark}`);
    }
} else {
    console.error(`Error: ${response.status}`);
}
```