StatsMapped's data API
Every figure on this site is also available as JSON, free and
unauthenticated — the same underlying data the pages themselves render from,
not a separate or delayed copy. The one exception is
tender_awards' supplier filter, which needs a
registered key; see its own access page.
Everything else below needs nothing but a URL.
Try it
# Every area's own latest figure for one stat, in one call (pass a
# stat_key from /api/v1/stats below) — the same cross-section every
# ranking page on the site is built from (Ireland):
curl "https://statsmapped.com/ireland/api/v1/series?stat_key=sale_price"
# Same call, UK:
curl "https://statsmapped.com/united-kingdom/api/v1/series?stat_key=sale_price"
# Every dataset for one area (Ireland):
curl "https://statsmapped.com/ireland/api/v1/geographies/county%3Akerry/datasets/psra_median_price_kerry"
# Every dataset for one area (UK):
curl "https://statsmapped.com/united-kingdom/api/v1/geographies/uk%3Alad%3Ae08000003/datasets/uk_rppi_e08000003"
# Every area at one boundary level (Ireland's own primary level is "county"):
curl "https://statsmapped.com/ireland/api/v1/geographies?level=county"
# Same call, UK (its own primary level is "lad" — local authority district):
curl "https://statsmapped.com/united-kingdom/api/v1/geographies?level=lad"
# The full catalogue of what's tracked:
curl "https://statsmapped.com/api/v1/stats"
Full reference, every route and field: /openapi.json
(machine-readable) or /docs (interactive, browser-only --
it runs entirely in JavaScript, so a plain curl or crawler fetch
of that URL itself returns an empty shell, not documentation text).
Two ways in, same routes
Nearly every route exists both bare (/api/v1/..., this
process's own default country) and country-prefixed
(/{ireland,united-kingdom}/api/v1/..., explicit regardless of
which country happens to be default). Both forms return identical data for
the same country — the prefixed form is the one to use if you ever call more
than one country, since it never depends on which one this server happens to
be defaulting to today. Exceptions:
/api/v1/tender_awards,
/api/v1/tender_awards/access-requests,
/api/v1/tender_awards/summary,
/api/v1/planning_applications,
/api/v1/receipts/{receipt_id} and
/api/v1/stats/ntpf_op/wait_share_rollup exist only in the bare
form today, with no country-prefixed twin yet — checked against the live
route table on 15 Oct 2026 (the first three since 15 Sep; the other three
were added after), not assumed from an older finding.
A third form exists too — don't copy it from devtools
Opening this site's own network tab shows a THIRD form for some routes --
no /v1/ at all (e.g. /api/series, not
/api/v1/series). These are undocumented internal aliases this
site's own front end calls, not a third real way in: they carry no version
guarantee, may change or disappear without notice, and are deliberately left
out of this schema (include_in_schema=False) for exactly that
reason. Always use the /api/v1/... form above, bare or
country-prefixed — copying a URL straight from devtools risks copying one
of these instead.
Errors
Every non-2xx response is {"error": {"status": <code>,
"message": "..."}} — one shape, whether it's a 404, a 422 validation
error, or a 429. No route here ever returns FastAPI's bare
{"detail": "..."} default.
Rate limits
600 requests per 1
hour, per IP, on every read-only route (tender_awards search and
its access-request endpoint have their own separate, narrower limits — see
its own page). Every response carries
X-RateLimit-Limit, X-RateLimit-Remaining and
X-RateLimit-Reset (a Unix timestamp); past the limit, a 429 adds
Retry-After in seconds. Generous deliberately — this bounds
scripted abuse, not legitimate use; this site's own front end calls these same
routes on every page load and has never been close to it.
Versioning
Everything here is v1. No route has changed shape since first
publishing, and none will without a new version path (/api/v2/...)
— an existing integration is never broken by a future change to this API.
Concretely: adding a new field to an existing response is not a breaking
change — an integration should tolerate fields it doesn't recognise. Removing,
renaming, or narrowing what an existing field means gets a new version path, and
the old path keeps working for a transition period. When that first happens we will
announce it on this page with the date the old path stops being served, and send a
Deprecation header on the old path. Nothing on this API is deprecated
today. A change to
what gets redacted or shown on an authorized tender_awards call
(the field's meaning, not its shape) is announced on
its own access page rather than here.
MCP
MCP lets an AI agent (Claude
Desktop, Cursor, others) call this data directly as tool calls instead of
parsing web pages. A hosted endpoint is live at
https://mcp.statsmapped.com/mcp (Streamable HTTP) — no install
needed for a client that speaks it directly. A thin client package is also
published on PyPI for running over stdio instead, calling this same public
API: pip install statsmapped-mcp.
Metadata for agents
An Open Knowledge
Format bundle describing every metric, dataset, caveat and comparability verdict is served at
/okf/ (the bundle root is /okf/; its links are relative to
that root). Ireland only for now.