---
title: "List Stats"
method: GET
path: "/api/v1/stats"
tags: ["stats"]
---

# List Stats

`GET /api/v1/stats`

## Request

- Base URL: `https://statsmapped.com`
- URL: `https://statsmapped.com/api/v1/stats`
- Auth: none declared

Every stat, with which boundary levels it may honestly colour.

`compatible_levels` is computed from `geography_relations` -- the same two
branches `geo_match()` (databeat/geography.py) uses to decide whether ONE series
may honestly answer for ONE requested area, replicated faithfully rather than
reimplemented: `exact` (a stat's series geography IS a geography at this level)
or `aggregate` (a stat's series geography directly `contains` a geography at this
level, one hop only -- geo_match never walks a second hop; that's visible in its
SQL, a single non-recursive join, not stated in its module docstring, which is
about the geography-identifier model instead). See stat-region-selector-design.md
section 2 for the full derivation.

CORRECTED 2026-09-26 (wl:be788e133ac1): this docstring used to say the whole
function was "computed live rather than cached... row counts make it a non-issue".
That was true for a SINGLE call in isolation, but never measured against the real
call pattern -- profiled directly at ~1.2s per call, and a single real page render
calls it 4 times (see the cache above). Now cached per country, 60s TTL.

`cluster` / `cluster_label` / `cluster_sort_order` are the product's five subject
areas (migration 014), served from here so the map's "Colour by" chips, the panel's
tabs, the card ordering and the alert-strip quota all read ONE source of truth rather
than four approximations of it. Until this landed the taxonomy existed only in
documents, and every one of those surfaces fell back to insertion order or to raw
series count -- see unified-design-and-data-plan.md section 2.

A level absent from `compatible_levels` is not a bug to investigate -- it is the
same honest "cannot be shown here" geo_match already enforces per-request for the
panel and deep dive, computed once for the whole stat instead of once per click.
Restricted to KNOWN_BOUNDARY_LEVELS: a stat's series is always trivially "exact"
compatible with its OWN geography's level (crime with garda_division, RPPI's
regional facets with cso_rppi_region, any nationally-published series with nuts3),
which is a correct geo_match verdict but not a level the front end has a button
for -- surfacing it would be noise, not signal.

## Response `200`

Successful Response

- StatEntry[]
  - `country` string
  - `key` string, required
  - `label` string, required
  - `caption` string, nullable
  - `search_label` string, nullable
  - `cluster` string, required
  - `cluster_label` string, nullable
  - `cluster_sort_order` integer, nullable
  - `compatible_levels` string[]
  - `has_ranking_page` boolean
  - `ranking_link` object, nullable
  - `has_comparison` boolean
  - `quick_definition` object, nullable

## Other responses

- `400`: Bad request
- `401`: Missing or invalid credentials
- `403`: Not authorized for this request
- `404`: Not found
- `422`: Validation error
- `429`: Rate limited

---

[API](https://skmtc.dev/statsmapped/apis/statsmapped-api.md) · [All operations](https://skmtc.dev/statsmapped/apis/statsmapped-api/llms.txt) · [OpenAPI document](https://skmtc.dev/statsmapped/apis/statsmapped-api/revisions/7c5b264d05b7?raw)
