- Data
- REST API
- Market data
- Market facts
Market facts
POST /v1/market/factsPrice, price per square metre and turnover for one area, asset class, bedroom band and period, from the market cube, with a grade on every number saying how much evidence sits behind it.
Same call over MCP
Market facts for an areamarket_factsAuthenticate with an API key from the API & MCP Hub. The same call is available as an MCP tool at the same price.
Reference
What POST /v1/market/facts returns
The market cube answers "what do two-bedroom flats in Lambeth sell for" without scanning sales at request time. Every cell is one geography, asset class, bedroom band and month, pre-computed from the sold-price record, and every cell carries a decision that says how much evidence it rests on. That decision is the reason to read this page before quoting a number.
Three metrics are populated today: sales_price, price_psm and turnover_rate. Three more exist in the schema and are empty (rental value, gross yield, days on market); the response names them under metrics_with_no_data so nobody ranks on a column of nulls.
The full description, as the assistant reads it
Metrics: sales_price, price_psm, turnover_rate are populated today. rental_value, gross_yield and days_on_market are NOT — the pipeline has never backfilled them, so they come back null and are named in the response's metrics_with_no_data. Do not compare or rank on them, and do not report a null from them as "no activity"; it means "not collected".
turnover_rate is sales as a share of the stock that could have sold. It is the liquidity measure — transaction COUNT is market size, not liquidity (W2 has the largest dwelling stock of any London district and near-bottom turnover).
Geography is postcode (resolved to its district — the cube has no sector or unit grain) or lad_code (a local-authority NAME, e.g. "Lambeth", not a GSS code). There are no LSOA or ward areas in the warehouse; those selectors return 422.
To compare AREAS against each other use market_ranking, not repeated calls here. For "how many sales" use market_volume_series — the tx_n here counts only UPRN-matched, non-anomalous sales and runs well short of the registry. The prices are sound; the count is a sample size.
READ tx_decision BEFORE QUOTING A PRICE. Every row carries one, and it says how much evidence is behind that number. Measured over the whole cube:
direct 2.7% 30+ sales in the cell. Quote it plainly.
modeled 15.4% 5-29 sales. Sound, lightly smoothed.
suppressed 44.0% 1-4 sales. Indicative — say the sample is thin.
imputed 17.3% ZERO sales. The price is the prior BORROWED from a
parent geography, not a measurement of this cohort.
missing 20.7% zero sales and no price at all (null).An imputed row looks exactly like a real one — a confident, specific figure — and it repeats: in one district, 25 cohorts all read the same 353,909, because they are all the same borrowed number. Reporting it as "2-bed detached in AL10 sell for £353,909" states a fact the data does not contain. Say the cohort has no recorded sales instead, or aggregate up to a grain that does. turnover_rate is 0 on every one of these rows, which is a second tell.
Where you want the AREA rather than a cohort, do not read a cohort row and call it the area: aggregate, or use market_ranking, which does it for you weighted by the sales behind each cohort. There is no rollup row in this cube — no bedroom_band="all" and no hmo_flag="all"; filtering on either matches nothing at all.
max_periods (default 3) bounds how many recent MONTHLY periods come back when period is not given. The grain is one row per (asset_subtype × bedroom_band × hmo_flag × period) — about 13 cohorts per period — so a wide window gets large fast. The response reports period_frequency, periods_returned and truncated so you can tell a short answer from a cut-off one.
UK only.
Reference
When to use it, and when not to
Use it for the price and liquidity of one cohort in one area: a district or a local authority, a property type, a bedroom band. Use market_ranking instead when the question compares areas; it aggregates the cube properly, weighted by the sales behind each cohort, and returns one row per area over one window, where a loop over market_facts returns rows from different periods. Use market_volume_series for "how many sales": the cube's tx_n is a UPRN-matched sample that runs well short of the registry, and is a sample size, not a count.
Inputs
Before you call it
Geography is a postcode (resolved to its district; the cube has no sector or unit grain) or a lad_code, which is a local authority name such as "Lambeth", not a GSS code. There are no LSOA or ward cells in the warehouse; those selectors return 422. max_periods (default 3) bounds how many recent months come back when period is not given; the grain is about thirteen cohorts per period, so a wide window gets large fast, and the response reports period_frequency, periods_returned and truncated so a short answer can be told from a cut-off one.
- postcode
- The postcode must be a full UK postcode ("SE22 8HN"), not a district. Where a tool works at district grain it truncates the postcode itself.
Request
Calling POST /v1/market/facts
curl -X POST "https://api.marketcode.ai/v1/market/facts" \
-H "Authorization: Bearer $MARKETCODE_API_KEY"
-H "Content-Type: application/json" \
-d '{"lad_code":"Lewisham"}'Send your API key as a Bearer token. Every response carries credits_charged and credits_remaining.
Inputs
Parameters
This endpoint takes no path or query parameters.
Request body
| Name | In | Type | Required | Description |
|---|---|---|---|---|
| postcode | Body | string | No | UK postcode, e.g. SW1A 1AA |
| lsoa_code | Body | string | No | LSOA 2021 code |
| ward_code | Body | string | No | GSS ward code |
| lad_code | Body | string | No | GSS local-authority code |
| h3_cell | Body | string | No | h3 cell ID (resolution 7-9 recommended) |
| asset_class | Body | string | No | e.g. "residential", "commercial" |
| asset_subtype | Body | string | No | e.g. "flat", "terraced", "detached" |
| bedroom_band | Body | string | No | e.g. "1", "2", "3", "4+" |
| period | Body | string | No | ISO month or quarter, e.g. "2026-Q1" or "2026-05" |
| metrics | Body | string[] | No | Specific metrics to return. Omit for the default set: sales_price, price_psm, rental_value, gross_yield, days_on_market. |
Response
What POST /v1/market/facts returns for a real request
curl -X POST "https://api.marketcode.ai/v1/market/facts" \
-H "Authorization: Bearer $MARKETCODE_API_KEY"
-H "Content-Type: application/json" \
-d '{"lad_code":"Lewisham"}'{
"country": "UK",
"query": {
"lad_code": "Lewisham"
},
"data": {
"area_id": "c0694b59-04d1-48ab-9a4c-c4f9d7b74f60",
"count": 3,
"metrics": [
"sales_price",
"price_psm",
"turnover_rate",
"… 2 more"
],
"period_frequency": "monthly",
"periods_returned": 3,
"max_periods": 3,
"truncated": false,
"data_through": "Dec 2026",
"facts": [
{
"area_id": "c0694b59-04d1-48ab-9a4c-c4f9d7b74f60",
"period_id": "fac8500b-8053-4a65-98d0-e46f3f57b5fe",
"period": "Dec 2026",
"period_start": "2026-12-01",
"period_frequency": "monthly",
"asset_class": "Residential",
"asset_subtype": "ALL",
"bedroom_band": "all",
"hmo_flag": "all",
"sales_price": null,
"price_psm": null,
"turnover_rate": null,
"rental_value": null,
"gross_yield": null,
"stock_count": null,
"tx_n": null,
"tx_decision": null,
"rental_listing_n": null,
"rental_listing_decision": null,
"gross_yield_decision": null
},
{
"area_id": "c0694b59-04d1-48ab-9a4c-c4f9d7b74f60",
"period_id": "3c1b4a4b-2f83-446c-ac98-3293a0e994f7",
"period": "Nov 2026",
"period_start": "2026-11-01",
"period_frequency": "monthly",
"asset_class": "Residential",
"asset_subtype": "ALL",
"bedroom_band": "all",
"hmo_flag": "all",
"sales_price": null,
"price_psm": null,
"turnover_rate": null,
"rental_value": null,
"gross_yield": null,
"stock_count": null,
"tx_n": null,
"tx_decision": null,
"rental_listing_n": null,
"rental_listing_decision": null,
"gross_yield_decision": null
},
{
"area_id": "c0694b59-04d1-48ab-9a4c-c4f9d7b74f60",
"period_id": "7ec536e8-86d8-4ec2-8833-d957c0244720",
"period": "Oct 2026",
"period_start": "2026-10-01",
"period_frequency": "monthly",
"asset_class": "Residential",
"asset_subtype": "ALL",
"bedroom_band": "all",
"hmo_flag": "all",
"sales_price": null,
"price_psm": null,
"turnover_rate": null,
"rental_value": null,
"gross_yield": null,
"stock_count": null,
"tx_n": null,
"tx_decision": null,
"rental_listing_n": null,
"rental_listing_decision": null,
"gross_yield_decision": null
}
],
"cached": true,
"time_ms": 0.5
},
"credits_charged": 0
}A real response, captured from production and trimmed: arrays to three items, long strings shortened, volatile keys dropped.
Response
Response fields
| Field | Type | Example |
|---|---|---|
| country | string | UK |
| query | object | |
| query.lad_code | string | Lewisham |
| data | object | |
| data.area_id | string | c0694b59-04d1-48ab-9a4c-c4f9d7b74f60 |
| data.count | integer | 3 |
| data.metrics | array | |
| data.period_frequency | string | monthly |
| data.periods_returned | integer | 3 |
| data.max_periods | integer | 3 |
| data.truncated | boolean | false |
| data.data_through | string | Dec 2026 |
| data.facts | array | |
| data.facts[].area_id | string | c0694b59-04d1-48ab-9a4c-c4f9d7b74f60 |
| data.facts[].period_id | string | fac8500b-8053-4a65-98d0-e46f3f57b5fe |
| data.facts[].period | string | Dec 2026 |
| data.facts[].period_start | string | 2026-12-01 |
| data.facts[].period_frequency | string | monthly |
| data.facts[].asset_class | string | Residential |
| data.facts[].asset_subtype | string | ALL |
| data.facts[].bedroom_band | string | all |
| data.facts[].hmo_flag | string | all |
| data.facts[].sales_price | null | |
| data.facts[].price_psm | null | |
| data.facts[].turnover_rate | null | |
| data.facts[].rental_value | null | |
| data.facts[].gross_yield | null | |
| data.facts[].stock_count | null | |
| data.facts[].tx_n | null | |
| data.facts[].tx_decision | null | |
| data.facts[].rental_listing_n | null | |
| data.facts[].rental_listing_decision | null | |
| data.facts[].gross_yield_decision | null | |
| data.cached | boolean | true |
| data.time_ms | number | 0.5 |
| credits_charged | integer | 0 |
Fields observed in the example response above; a field the example did not exercise is not listed.
Reference
Things that catch people out
- Read
tx_decisionbefore quoting a price. Over the whole cube: direct (30+ sales) 2.7%, modelled (5 to 29) 15.4%, suppressed (1 to 4) 44.0%, imputed (zero sales, price borrowed from the parent geography) 17.3%, missing 20.7%. An imputed row looks exactly like a real one and repeats: in one district twenty-five cohorts all read the same £353,909 because they are the same borrowed number.turnover_rateis 0 on every imputed row, which is the second tell. - There is no rollup row. No
bedroom_band="all"and nohmo_flag="all"; filtering on either matches nothing. For the area rather than a cohort, aggregate or usemarket_ranking. - Turnover is the liquidity measure. Sales as a share of the stock that could have sold. Transaction count is market size, not liquidity: W2 has the largest dwelling stock of any London district and near-bottom turnover.
Price and licence
What it costs, and where the data comes from
Market facts is free over MCP and over REST, and the two surfaces share one credit balance. Free calls need a signed-in account or an API key and appear in your usage, but they never touch your balance.
Credits are granted on sign-up and bought in packs; the pricing page lists every call.
Computed by MarketCode from
- HM Land Registry
Price Paid Data
Open Government Licence v3 · England and Wales
How the model or index is built, and where it is weak, is on the methodology page.
Related
Endpoints used with Market facts
- Rank areas on a market metricFree
market_rankingRank areas against each other on a market metric — one row per area at the latest period. Defaults to turnover_rate, which is sales as a share of the stock that could have sold: the liquidity measure, as opposed to transaction count, which measures market size.Pairs with this - Monthly transaction volumeFree
market_volume_seriesMonthly transaction VOLUME for a postcode district, postcode area orPairs with this - House price index seriesFree
market_index_seriesThe published house-price INDEX for one postcode district or local authority: the level per month (base period = 100), the forecast tail flagged, and provenance saying how the index was built.Pairs with this - Resolve an area nameFree
area_resolveResolve an area name or code ("Hackney", "E5") to its area_id, centroidPairs with this - Asking-price index (portal listings)Free
asking_price_index_seriesHedonic ASKING-PRICE index for one postcode district, local authority or Great Britain, from portal listings (Rightmove ~95%), 2022M01 = 100, with 80% bands and posterior standard errors, smoothed toward the parent geography.Same product - Live listings stock, dailyFree
listing_stock_seriesLive listings on the market by day for one area, channel and bedroom band — the stock-on-market series, with the median age of the dated live stock, median asking price or rent, and the new-build count.Same product
Glossary
Terms used here
- Local authority district (LAD): The council area a property sits in: about 360 in Great Britain, the second geography MarketCode publishes indices and rankings for.
- Price per square metre (£/m²): Sale or asking price divided by internal floor area; the one number that makes properties of different sizes comparable, and what the valuation back-series is scaled by.
- Market cube: MarketCode's pre-computed table of price, price per square metre and turnover for every area, asset class, bedroom band and month, with a graded decision on how much evidence sits behind each cell.
- Turnover rate: Sales in a period as a share of the dwellings that could have sold; the liquidity measure, distinct from the raw count of sales, which measures market size.
- House in multiple occupation (HMO): A property let to three or more tenants from more than one household who share facilities; licensed by the council above five occupants and often restricted by Article 4.
FAQ
Questions about Market facts
How much does `market_facts` cost?
+
Market facts is free over MCP and over REST, and the two surfaces share one credit balance. Free calls need a signed-in account or an API key and appear in your usage, but they never touch your balance.
How do I authenticate?
+
Send your API key as a Bearer token in the Authorization header. Keys are created in the API & MCP Hub, shown once and revocable. Every response carries the credits charged and your remaining balance.
Is there an MCP version?
+
Yes. The market_facts tool on the MarketCode MCP server is the same call at the same price, signed in with OAuth rather than a key, so Claude, ChatGPT, Codex and Cursor can run it in a conversation.
Where does the data come from?
+
Computed by MarketCode from HM Land Registry price paid data. Coverage is England and Wales. The methodology page describes how the model or index is built.
Does `market_facts` change anything?
+
No. The tool is annotated read-only on the server, so it never writes to your data or ours and an assistant can call it without a confirmation step.
What does a price with tx_decision "imputed" mean?
+
That the cohort had no recorded sales in the period and the price shown is the prior borrowed from the parent geography. It is not a measurement of that cohort. Say the cohort has no recorded sales, or aggregate up to a grain that does.
Why does the sale count differ from HM Land Registry's?
+
Because the cube counts only UPRN-matched, non-anomalous sales, which run 17 to 66% short of the registry depending on the area. The prices are sound; the count is the sample behind them. For counts use market_volume_series, which reads Price Paid directly.
Can I get rents and yields from this?
+
Not yet. rental_value, gross_yield and days_on_market are in the schema and unpopulated. Rent levels and yields are in listing_market_series, from portal listings, by area and bedroom band.
Try Market facts on a real address.
30-minute call. We'll provision a key and walk through the endpoint on your use case.