API Reference
All endpoints return JSON. Authentication uses Authorization: Api-Key YOUR_KEY on every request.
https://api.homedata.co.uk/api
Complete endpoint catalogue
Every endpoint currently offered in the Playground. Enterprise data is arranged with our team.
-
Address Find GET
/address/find/ -
Property — Discovery GET
/property/:uprn/ -
Property — Address tier GET
/property/:uprn/address/ -
Property — Base tier GET
/property/:uprn/base/ -
Property — Core tier GET
/property/:uprn/core/ -
Property — Complete tier GET
/property/:uprn/complete/ -
Property — Custom (?with=…) GET
/property/:uprn/ -
All Property Listings EnterpriseEnquire about this data
-
Sale Events GET
/property_sale_events/ -
Rooms GET
/properties/:uprn/rooms/ -
Roof GET
/properties/:uprn/roof/ -
Garden GET
/properties/:uprn/garden/ -
Parking GET
/properties/:uprn/parking/ -
EPC Renovations GET
/properties/:uprn/epc_renovations/ -
Dimensions GET
/properties/:uprn/dimensions/ -
Land Area GET
/properties/:uprn/land/ -
Construction GET
/properties/:uprn/construction/ -
EPC Rating GET
/properties/:uprn/epc/ -
Environmental Risks GET
/risks/:risk_type/ -
Deprivation Index GET
/deprivation/ -
Price Trends GET
/price_trends/:outcode/ -
Price Distributions GET
/price_distributions/:outcode/ -
Postcode Lookup GET
/address/postcode/:postcode/ -
Land Registry Sales EnterpriseEnquire about this data
-
Council Tax Band GET
/council_tax_band/:uprn/ -
Council Tax Full GET
/council_tax/:uprn/ -
Comparables EnterpriseEnquire about this data
-
Search live listings EnterpriseEnquire about this data
-
Unlock UPRN + Address POST
/listing-address/ -
Land Registry Titles GET
/property_lr_titles/:uprn/ -
Boundary Autocomplete GET
/boundaries/autocomplete/ -
Planning Applications GET
/planning/search/ -
Crime Data GET
/crime/ -
Solar Assessment GET
/solar-assessment/:uprn/ -
Postcode Profile GET
/postcode-profile/ -
Price Growth GET
/price-growth/:outcode/ -
Schools Nearby GET
/schools/nearby -
Broadband Speed GET
/broadband/ -
Amenities (all) GET
/amenities/ -
Food GET
/amenities/food/ -
Education GET
/amenities/education/ -
Healthcare (OSM) GET
/amenities/healthcare/ -
Financial GET
/amenities/financial/ -
Civic GET
/amenities/civic/ -
Worship GET
/amenities/worship/ -
Culture GET
/amenities/culture/ -
Convenience GET
/amenities/convenience/ -
Green Spaces GET
/amenities/green_spaces/ -
Transport GET
/amenities/transport/ -
Shops GET
/amenities/shops/ -
Fuel Stations (all) GET
/fuel-stations/ -
Petrol Stations GET
/fuel-stations/petrol/ -
EV Chargers GET
/fuel-stations/ev/ -
Healthcare (all) GET
/healthcare/ -
GPs GET
/healthcare/gps/ -
Dentists GET
/healthcare/dentists/ -
Pharmacies GET
/healthcare/pharmacies/ -
Hospitals GET
/healthcare/hospitals/ -
Demographics GET
/demographics/ -
Listed Buildings GET
/listed-buildings/ -
Stamp Duty Calculator GET
/calculators/stamp-duty/ -
Mortgage Calculator GET
/calculators/mortgage/ -
Flood risk expert EnterpriseEnquire about this data
-
Plot intelligence EnterpriseEnquire about this data
-
Development suitability EnterpriseEnquire about this data
-
Lender-grade AVM EnterpriseEnquire about this data
-
Subsidence risk EnterpriseEnquire about this data
-
Land quality EnterpriseEnquire about this data
Everything you can know about a UPRN now lives behind one URL: /property/{uprn}/. Pick a tier, build your own with ?with=, or just call the bare URL for a discovery menu of what's available. Same fetchers, same response shape, predictable bundle pricing.
| Behaviour | URL | Cost | Returns |
|---|---|---|---|
| Discovery | /property/{uprn}/ | 1 | Menu — slug list with per-slug cost + per-UPRN availability + tier shortcuts |
| Custom | /property/{uprn}/?with=… | sum | Pick slugs, pay per slug at native weights |
| Address | /property/{uprn}/address | 5 | Address fields only — replaces /address/retrieve/ |
| Base | /property/{uprn}/base | 10 | Address + rooms + EPC + lr_title + last sold + construction + dimensions + garden/parking |
| Core | /property/{uprn}/core | 25 | Base + council tax band + flood + schools + broadband + crime + demographics + valuation estimate + solar + lr_sales + title boundary (GeoJSON) + planning constraints (listed / conservation / designations) |
| Complete | /property/{uprn}/complete | 50 | Core + council tax full (GBP charges) + comparables + live listings + full env risks + deprivation + planning application history + price trends/distributions/growth + full title (ownership + boundary) |
/address/retrieve/{uprn}/ and /properties/{uprn}/ (plural) are deprecated aliases. They are still served and have no removal date yet. Migrate by updating the URL — same UPRN, same response shape, same cost on the address-retrieve path.
Lean property record: 15 base fields covering property type and classification, EPC scores and floor area, windows, fireplaces, extensions, the last Land Registry sale, and price estimates. Add address, rooms, title and more with ?with= (e.g. ?with=address,rooms). Returns data for any of the UK's 29M+ addressable properties.
curl https://api.homedata.co.uk/properties/10093609154 \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/properties/10093609154",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
print(data["property_type"], data["last_sold_date"])
const response = await fetch( "https://api.homedata.co.uk/properties/10093609154", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); console.log(data.property_type, data.last_sold_date);
View example response
{
"uprn": 10093609154,
"property_type": "Flat",
"classification_code": "RD06",
"epc_floor_area": 56.0,
"current_energy_efficiency": 84,
"potential_energy_efficiency": 84,
"last_epc_date": "2020-07-28",
"windows_type": "Double glazed",
"fireplaces": 0,
"extensions": 0,
"last_sold_date": "2019-11-15",
"last_sold_price": 135000,
"last_sold_txid": "9A1C2E3F-…",
"predicted_price": 142000,
"average_area_price": 198000
}
These are the 15 base fields. Add more with ?with= (e.g. ?with=address,rooms) — see the Data Dictionary.
Energy Performance Certificate data. Returns current and potential energy efficiency scores (1–100), last EPC date, floor area, construction age band, and certificate ID.
curl https://api.homedata.co.uk/epc-checker/100023336956/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/epc-checker/100023336956/",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
epc = response.json()
print(f"Rating: {epc['current_energy_rating']}") # the A-G letter
print(f"Score: {epc['current_energy_efficiency']}") # the SAP score, 1-100
const response = await fetch( "https://api.homedata.co.uk/epc-checker/100023336956/", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const epc = await response.json(); console.log(`Rating: ${epc.current_energy_rating}`); // the A-G letter console.log(`Score: ${epc.current_energy_efficiency}`); // the SAP score, 1-100
View example response
{
"uprn": 10093609154,
"current_energy_efficiency": 84,
"potential_energy_efficiency": 84,
"current_energy_rating": "B",
"potential_energy_rating": "B",
"last_epc_date": "2020-07-28",
"epc_floor_area": 59,
"construction_age_band": "2007-2011",
"epc_id": "1813679032512020072814144822200478"
}
Environmental risk assessment by UPRN. Returns risk level, score, and contextual data. Use all to get every risk type in a single request.
Available risk types
flood
radon
noise
landfill
coal_mining
invasive_plants
air_quality_today
all
# Single risk type curl "https://api.homedata.co.uk/risks/flood/?uprn=100023336956" \ -H "Authorization: Api-Key YOUR_API_KEY" # All risk types in one call curl "https://api.homedata.co.uk/risks/all/?uprn=100023336956" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/risks/flood/",
params={"uprn": "100023336956"},
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
for risk in data["results"]:
print(f"{risk['risk_type']}: {risk['label']} (score {risk['score']})")
const response = await fetch( "https://api.homedata.co.uk/risks/flood/?uprn=100023336956", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); data.results.forEach(r => console.log(`${r.risk_type}: ${r.label} (score ${r.score})`) );
View example response
{
"risk_type": "flood",
"uprn": 100023336956,
"location": {
"lat": 51.503541,
"lon": -0.12767
},
"results": [
{
"risk_type": "flood_rivers_sea",
"label": "Very low",
"score": 1,
"score_unit": "band",
"intersects": true,
"distance_m": 0,
"radius_description": "At property",
"properties": {
"description": "Less than 1 in 1,000 chance of flooding each year"
}
},
{
"risk_type": "flood_surface_water",
"label": "Low",
"score": 2,
"score_unit": "band",
"intersects": true,
"distance_m": 0,
"radius_description": "At property",
"properties": {
"description": "Between 1 in 1,000 and 1 in 100 chance of flooding each year"
}
}
]
}
One API call returns the full area profile for a UK postcode. Bundles deprivation index, broadband speed, sold price history, nearby schools (Ofsted), transport stops, Census 2021 demographics, environmental risk (flood + radon), council tax band distribution, property count by type, and HPI trend. Equivalent to PropertyData's /postcode-key-stats — we return it in a single call.
postcode (required) — full UK postcodecurl "https://api.homedata.co.uk/postcode-profile?postcode=SW1A%202AA" \ -H "Authorization: Api-Key YOUR_API_KEY"
from homedata import Homedata
client = Homedata("YOUR_API_KEY")
profile = client.postcode_profile.get("SW1A 2AA")
print(profile.deprivation.imd_decile) # 8
print(profile.broadband.avg_download_mbps) # 142.3
print(profile.census.tenure.owned_outright_pct) # 20.5
import { Homedata } from '@homedata/js'
const client = new Homedata('YOUR_API_KEY')
const profile = await client.postcodeProfile.get('SW1A 2AA')
console.log(profile.deprivation.imd_decile) // 8
console.log(profile.broadband.full_fibre_available_pct) // 62.0
Response shape
Attribution
location is a postcode centroid published under the Open Government Licence. The API returns this notice in the attribution field, and you must reproduce it wherever you publish the coordinates:
Contains OS data © Crown copyright and database right 2026. Contains Royal Mail data © Royal Mail copyright and database right 2026. Contains National Statistics data © Crown copyright and database right 2026. Licensed under the Open Government Licence v3.0.
Monthly median asking prices by outcode (e.g. E1, SW1A, M3) over the past 12 months. Also returns a volatility score (0–100) based on month-to-month price variation.
outcode (path) — UK outcode (e.g. E1, SW1A)curl https://api.homedata.co.uk/price_trends/SW1A/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/price_trends/SW1A/",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
for month, price in data["monthly_average_prices"].items():
print(f"{month}: £{price:,}")
const response = await fetch( "https://api.homedata.co.uk/price_trends/SW1A/", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); Object.entries(data.monthly_average_prices).forEach(([month, price]) => console.log(`${month}: £${price.toLocaleString()}`) );
View example response
{
"outcode": "SW1A",
"monthly_average_prices": {
"2025-03": 5750000,
"2025-04": 5147500,
"2025-05": 1000000,
"2025-06": 8600000,
"2025-07": 1900000,
"2025-08": 1850000,
"2025-09": 2000000,
"2025-11": 8600000,
"2025-12": 6269900,
"2026-01": 5225000,
"2026-02": 5975000
},
"volatility_score": 100
}
Price distribution data for an outcode. Shows percentile breakdowns (25th, 50th, 75th) and averages by property type, useful for market segmentation and pricing analysis.
outcode (path) — UK outcode (e.g. E1, SW1A)curl https://api.homedata.co.uk/price_distributions/E1/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/price_distributions/E1/",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
for price_range, count in data["bins"].items():
print(f"£{price_range}: {count} properties")
const response = await fetch( "https://api.homedata.co.uk/price_distributions/E1/", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); Object.entries(data.bins).forEach(([range, count]) => console.log(`£${range}: ${count} properties`) );
View example response
{
"outcode": "E1",
"bins": {
"125000-695000": 342,
"695000-1265000": 187,
"1265000-1835000": 45,
"1835000-2405000": 12,
"2405000-2975000": 3
}
}
List all addresses in a postcode. Returns UPRNs so you can chain into other endpoints. Use URL-encoded or concatenated postcodes (e.g. SW1A2AA or SW1A%202AA).
Authorization: Api-Key YOUR_KEYcurl https://api.homedata.co.uk/address/postcode/SW1A2AA/ \
-H "Authorization: Api-Key YOUR_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/address/postcode/SW1A2AA/",
headers={"Authorization": "Api-Key YOUR_KEY"},
)
data = response.json()
for addr in data["addresses"]:
print(f"{addr['address']} (UPRN: {addr['uprn']})")
const response = await fetch( "https://api.homedata.co.uk/address/postcode/SW1A2AA/", { headers: { "Authorization": "Api-Key YOUR_KEY" } } ); const data = await response.json(); data.addresses.forEach(a => console.log(`${a.address} (UPRN: ${a.uprn})`) );
View example response
{
"postcode": "SW1A 2AA",
"count": 1,
"addresses": [
{
"uprn": 100023336956,
"uprn_token": "gAAAAABm4xK…",
"address": "PRIME MINISTER & FIRST LORD OF THE TREASURY, 10 DOWNING STREET, LONDON, SW1A 2AA",
"building_name": "",
"building_number": "10",
"sub_building": "",
"street": "Downing Street",
"town": "London"
}
]
}
⚠️ URL encoding: Use %20 or remove spaces entirely in the URL path. Do NOT use + — it's treated literally in URL paths.
Full-text search across 36 million UK addresses. Type-ahead autocomplete for address forms and property lookup interfaces. Returns matched addresses with the raw numeric uprn (a public OS AddressBase id, for use with external systems) plus an encrypted uprn_token you can pass into any property endpoint.
Authorization: Api-Key YOUR_KEYq (required) — search query (minimum 2 characters)curl "https://api.homedata.co.uk/address/find/?q=10%20Downing%20Street" \
-H "Authorization: Api-Key YOUR_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/address/find/",
params={"q": "10 Downing Street"},
headers={"Authorization": "Api-Key YOUR_KEY"},
)
results = response.json()
for addr in results["suggestions"]:
print(f"{addr['address']}, {addr['postcode']}")
const response = await fetch( "https://api.homedata.co.uk/address/find/?q=10%20Downing%20Street", { headers: { "Authorization": "Api-Key YOUR_KEY" } } ); const data = await response.json(); data.suggestions.forEach(a => console.log(`${a.address}, ${a.postcode}`) );
View example response
{
"suggestions": [
{
"uprn": 100023336956,
"uprn_token": "gAAAAABm4xK…",
"address": "10 Downing Street",
"postcode": "SW1A 2AA",
"town": "London"
},
{
"uprn": 10004862792,
"uprn_token": "gAAAAABm4xQ…",
"address": "10 Downing Street",
"postcode": "SA15 2UA",
"town": "Llanelli"
}
],
"count": 2
}
Enriched property data for a known UPRN. Use after Address Search or Address by Postcode to get property intelligence.
{tier} is a path segment — address or base (each tier is a strict superset of the one below; core and complete extend further still).Enrichment tiers
/address/
Address fields, UPRN, coordinates — 5 tokens
/base/
+ property type, bedrooms, bathrooms, EPC, floor area, last sold price — 10 tokens
# Address tier — 5 tokens curl https://api.homedata.co.uk/property/100023336956/address/ \ -H "Authorization: Api-Key YOUR_API_KEY" # Base tier — adds property type, beds, EPC, sold price — 10 tokens curl https://api.homedata.co.uk/property/100023336956/base/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/property/100023336956/base/",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
addr = response.json()
print(f"{addr['full_address']} — {addr.get('bedrooms')} bed {addr.get('property_type')}")
const response = await fetch( "https://api.homedata.co.uk/property/100023336956/base/", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const addr = await response.json(); console.log(`${addr.full_address} — ${addr.bedrooms} bed ${addr.property_type}`);
View example response (address tier)
{
"uprn": 100023336956,
"udprn": 7832854,
"usrn": 8400709,
"full_address": "10 DOWNING STREET, LONDON, SW1A 2AA",
"address_line_1": "10 Downing Street",
"address_line_2": "",
"address_line_3": "",
"building_name": "",
"building_number": "10",
"sub_building": "",
"street_name": "Downing Street",
"locality": "",
"town_name": "London",
"post_town": "London",
"postcode": "SW1A 2AA",
"outward_postcode": "SW1A",
"latitude": 51.5033,
"longitude": -0.1276
}
View example response (base tier)
{
// ... all address fields above, plus:
"property_type": "Semi-Detached",
"bedrooms": 4,
"predicted_bedrooms": 4,
"bathrooms": 2,
"habitable_rooms": 6,
"floors": 3,
"epc_floor_area": 180.0,
"predicted_floor_area": 175.0,
"current_energy_efficiency": 62,
"potential_energy_efficiency": 78,
"last_epc_date": "2020-07-28",
"last_sold_date": "2019-11-15",
"last_sold_price_gbp": 925000,
"last_sold_txid": "B8F2A1...",
"classification_code": "RD03"
}
⚠ Limited postcode coverage
Broadband data currently returns 404 for a significant share of UK postcodes while coverage is being expanded. Treat as best-effort for now and code against the missing-data path (handle 404 cleanly). Full coverage is planned — watch this page for go-live.
Broadband speed and coverage data for any UK postcode — average and max download/upload speeds, superfast/ultrafast/gigabit availability percentages, and full-fibre coverage. Data sourced from Ofcom's Connected Nations report, updated annually.
Authorization: Api-Key YOUR_KEYpostcode (required) — UK postcode, spaces optionalParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string | required | UK postcode. Spaces are stripped automatically. e.g. SW1A2AA or SW1A 2AA |
curl "https://api.homedata.co.uk/broadband?postcode=SW1A2AA" \
-H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/broadband",
params={"postcode": "SW1A2AA"},
headers={"Authorization": "Api-Key YOUR_API_KEY"},
)
data = response.json()
print(f"Avg download: {data['avg_download_speed']} Mbps")
print(f"Gigabit available: {data['gigabit_available_pct']}%")
const response = await fetch( "https://api.homedata.co.uk/broadband?postcode=SW1A2AA", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); console.log(`Avg download: ${data.avg_download_speed} Mbps`); console.log(`Gigabit available: ${data.gigabit_available_pct}%`);
View example response
{
"postcode": "SW1A 2AA",
"avg_download_speed": 67.4,
"max_download_speed": 362.0,
"avg_upload_speed": 18.2,
"max_upload_speed": 36.0,
"superfast_available_pct": 98.0,
"ultrafast_available_pct": 72.0,
"gigabit_available_pct": 45.0,
"full_fibre_available_pct": 45.0,
"below_uso_pct": 0.5,
"connections_count": 24,
"premises_count": 26,
"data_year": 2025
}
Response fields
| Field | Type | Description |
|---|---|---|
| avg_download_speed | float | Average download speed in Mbps |
| max_download_speed | float | Maximum download speed in Mbps |
| avg_upload_speed | float | Average upload speed in Mbps |
| max_upload_speed | float | Maximum upload speed in Mbps |
| superfast_available_pct | float | % of premises with superfast broadband (≥30 Mbps) available |
| ultrafast_available_pct | float | % of premises with ultrafast broadband (≥300 Mbps) available |
| gigabit_available_pct | float | % of premises with gigabit-capable connectivity |
| full_fibre_available_pct | float | % of premises with full-fibre (FTTP) available |
| below_uso_pct | float | % of premises below the Universal Service Obligation (10 Mbps down / 1 Mbps up) |
| connections_count | integer | Number of active broadband connections at this postcode |
| premises_count | integer | Total addressable premises at this postcode |
| data_year | integer | Year of the Ofcom Connected Nations dataset (e.g. 2025) |
Error codes
| Status | Code | Meaning |
|---|---|---|
| 422 | missing_postcode | No postcode query parameter provided |
| 422 | invalid_postcode | Postcode doesn't match UK format (e.g. SW1A 2AA) |
| 404 | not_found | Valid postcode but no Ofcom data available for it |
| 503 | service_unavailable | Broadband data temporarily unavailable |
Search for administrative boundaries (local authorities, wards, parishes) by name. Returns boundary metadata. Available to every account.
Authorization: Api-Key {your_key} header required (every account)curl "https://api.homedata.co.uk/boundaries/autocomplete/?q=islington" \
-H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/boundaries/autocomplete/",
params={"q": "islington"},
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
for b in data["results"]:
print(f"{b['name']} (level {b['admin_level']})")
const response = await fetch( "https://api.homedata.co.uk/boundaries/autocomplete/?q=islington", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); data.results.forEach(b => console.log(`${b.name} (level ${b.admin_level})`) );
View example response
{
"results": [
{
"id": 14445,
"name": "London Borough of Islington",
"display_name": "London Borough of Islington, Greater London, England",
"admin_level": 8
}
]
}
Land Registry title boundary data for a property. Returns a GeoJSON Feature with the title polygon.
curl https://api.homedata.co.uk/property_lr_titles/100023336956/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/property_lr_titles/100023336956/",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
feature = response.json() # GeoJSON Feature
print(f"Geometry type: {feature['geometry']['type']}")
const response = await fetch( "https://api.homedata.co.uk/property_lr_titles/100023336956/", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const feature = await response.json(); // GeoJSON Feature console.log(`Geometry: ${feature.geometry.type}`);
View example response
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-0.12764, 51.50332],
[-0.12758, 51.50338],
[-0.12771, 51.50341],
[-0.12777, 51.50335],
[-0.12764, 51.50332]
]
]
},
"properties": {
"title_no": "NGL936618",
"property": 100023336956,
"record_status": "A",
"estate_interest_code": "F",
"estate_interest": "Freehold",
"title_class_code": "ABS",
"title_class": "Absolute",
"has_restrictive_covenant": false,
"created_at": "2024-06-15T10:30:00Z",
"updated_at": "2024-06-15T10:30:00Z"
}
}
Light shape (3 tokens) — returns band, billing authority name and GSS code. For yearly + monthly charge in GBP and the full bundle, call /council_tax/{uprn}/ instead (5 tokens). Coverage: England, Scotland and Wales, fiscal year 2026-27.
Look up the council tax band for any UK residential property. Light response — band, billing authority name and GSS code. For yearly + monthly charge in GBP and the full bundle, call /council_tax/{uprn}/ (5 tokens). Charges come from each local authority's published rates.
{uprn} in the path (recommended), or by ?postcode= + building_number/building_name when no UPRN.curl "https://api.homedata.co.uk/council_tax_band/10012963615/" \ -H "Authorization: Api-Key YOUR_API_KEY" # Or by postcode + building when no UPRN: curl "https://api.homedata.co.uk/council_tax_band/?postcode=SW1A+2AA&building_number=10" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests uprn = 10012963615 response = requests.get( f"https://api.homedata.co.uk/council_tax_band/{uprn}/", headers={"Authorization": "Api-Key YOUR_API_KEY"} ) data = response.json() print(f"Council Tax Band: {data['council_tax_band']}")
const uprn = 10012963615; const response = await fetch( `https://api.homedata.co.uk/council_tax_band/${uprn}/`, { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); console.log(`Council Tax Band: ${data.council_tax_band}`);
View example response
{
"council_tax_band": "H",
"authority_name": "Westminster"
}
Full bundle (5 tokens) — band, billing authority + GSS code, country, current-year yearly and monthly charge in GBP, 1991 valuation band bounds, and fiscal year. For just band + authority, use the lighter /council_tax_band/ (3 tokens).
Full council tax record for a UPRN. Returns the band, billing authority name and GSS code, country, the current-year yearly + monthly charge in GBP (2dp strings), 1991 valuation band bounds, and the fiscal year label. Coverage: 25.3M properties resolve to a 2026-27 charge across England, Scotland and Wales (~96.4% of bands have charge data; the remainder return null charges with band + authority still populated).
{uprn} in the path (UPRN required — postcode mode lives on the lighter /council_tax_band/ endpoint).curl "https://api.homedata.co.uk/council_tax/10012963615/" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests uprn = 10012963615 response = requests.get( f"https://api.homedata.co.uk/council_tax/{uprn}/", headers={"Authorization": "Api-Key YOUR_API_KEY"} ) data = response.json() print(f"Band {data['council_tax_band']} in {data['authority_name']} — £{data['yearly_charge_gbp']}/yr")
const uprn = 10012963615; const response = await fetch( `https://api.homedata.co.uk/council_tax/${uprn}/`, { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); console.log(`Band ${data.council_tax_band} — £${data.yearly_charge_gbp}/yr`);
View example response
{
"council_tax_band": "D",
"authority_name": "Cornwall",
"gss_code": "E06000052",
"country": "England",
"yearly_charge_gbp": "2389.56",
"monthly_charge_gbp": "199.13",
"value_low_gbp": "68001.00",
"value_high_gbp": "88000.00",
"fiscal_year_label": "2026-27"
}
Search planning applications near a UK location. Covers over 300 local planning authorities and nearly 4 million applications; completeness varies by authority. Returns current and historical planning data including application status, type, decision dates, and case officer details.
Parameters
postcode UK postcode (e.g., SW1A 2AA). Either postcode or lat+lng required.lat, lng Coordinates for centre of search (alternative to postcode).radius_km Search radius in km. Default: 0.5, max: 5.days Only applications from last N days. Default: 90, max: 365.type Filter: Full, Outline, Heritage, Trees, Conditions.status Filter: Undecided, Approved, Refused, Withdrawn.page Page number (25 results per page).curl "https://api.homedata.co.uk/planning/search/?postcode=SW1A+2AA&radius_km=0.5&days=90" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/planning/search/",
params={"postcode": "SW1A 2AA", "radius_km": 0.5, "days": 90},
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
for app in data["results"]:
print(f"{app['reference']} — {app['description'][:80]}...")
const response = await fetch(
"https://api.homedata.co.uk/planning/search/?postcode=SW1A+2AA&radius_km=0.5&days=90",
{ headers: { "Authorization": "Api-Key YOUR_API_KEY" } }
);
const data = await response.json();
console.log(`${data.count} planning applications found`);
data.results.forEach(app => console.log(`${app.reference}: ${app.status}`));
Example response
{
"count": 47,
"page": 1,
"per_page": 25,
"radius_km": 0.5,
"days": 90,
"results": [
{
"reference": "26/01372/LBC",
"address": "10 Downing Street London SW1A 2AA",
"postcode": "SW1A 2AA",
"description": "Removal and replacement of internal doors...",
"status": "Pending",
"decision": "Undecided",
"type": "Heritage",
"size": "Small",
"authority": "Westminster",
"ward": "St James's",
"date_received": "2026-02-25",
"date_validated": "2026-02-25",
"date_decided": null,
"target_decision_date": "2026-04-22",
"case_officer": "See source",
"agent_name": "See source",
"applicant_name": null,
"num_comments": 0,
"num_documents": 0,
"url": "https://idoxpa.westminster.gov.uk/...",
"location": {
"longitude": -0.127695,
"latitude": 51.50354
},
"distance_km": 0.0
}
]
}
Search street-level crime near a UK postcode or coordinate. Returns crime counts aggregated by category (burglary, theft, violent crime, etc). Data sourced from Police UK covering England, Wales, and Northern Ireland. Updated monthly.
postcode (e.g. SW1A 2AA) or
lat + lng (required),
date (YYYY-MM, optional — defaults to latest),
category (optional — filter by crime type)
curl "https://api.homedata.co.uk/crime/?postcode=SW1A+2AA" \ -H "Authorization: Api-Key YOUR_API_KEY" # With date and category filter curl "https://api.homedata.co.uk/crime/?lat=51.5074&lng=-0.1278&date=2025-12&category=burglary" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/crime/",
params={"postcode": "SW1A 2AA"},
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
print(f"Total crimes: {data['total_crimes']} in {data['month']}")
for cat in data["categories"]:
print(f" {cat['label']}: {cat['count']}")
const response = await fetch( "https://api.homedata.co.uk/crime/?postcode=SW1A+2AA", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); console.log(`${data.total_crimes} crimes in ${data.month}`); data.categories.forEach(c => console.log(` ${c.label}: ${c.count}`) );
View example response
{
"total_crimes": 847,
"month": "2025-12",
"search_point": {
"latitude": 51.50354,
"longitude": -0.127695
},
"categories": [
{
"category": "violent-crime",
"label": "Violence and sexual offences",
"count": 203,
"latest_month": "2025-12",
"sample_locations": [
{
"street": "On or near Whitehall",
"latitude": "51.504284",
"longitude": "-0.126366"
}
]
},
{
"category": "anti-social-behaviour",
"label": "Anti-social behaviour",
"count": 156,
"latest_month": "2025-12",
"sample_locations": []
},
{
"category": "theft-from-the-person",
"label": "Theft from the person",
"count": 112,
"latest_month": "2025-12",
"sample_locations": []
},
{
"category": "other-theft",
"label": "Other theft",
"count": 98,
"latest_month": "2025-12",
"sample_locations": []
},
{
"category": "burglary",
"label": "Burglary",
"count": 45,
"latest_month": "2025-12",
"sample_locations": []
}
],
"coverage_note": "England, Wales, and Northern Ireland. Scotland shows British Transport Police data only."
}
Categories: anti-social-behaviour, bicycle-theft, burglary, criminal-damage-arson, drugs, other-crime, other-theft, possession-of-weapons, public-order, robbery, shoplifting, theft-from-the-person, vehicle-crime, violent-crime. Use the category parameter to filter by type, or omit to get all.
Full solar energy potential assessment for a UK property. Returns estimated system size, annual generation, savings, payback period, and CO₂ offset. Based on property roof data, local solar irradiance (120 UK postcode zones), and standard PV calculation models. Designed for solar installers, energy advisors, and home improvement platforms.
uprn (path, required)curl https://api.homedata.co.uk/solar-assessment/10003469503/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests UPRN = 10003469503 response = requests.get( f"https://api.homedata.co.uk/solar-assessment/{UPRN}/", headers={"Authorization": "Api-Key YOUR_API_KEY"} ) data = response.json() solar = data["solar_potential"] print(f"{solar['system_size_kwp']} kWp — £{solar['annual_savings_gbp']}/yr savings") print(f"Payback: {solar['payback_years']} years ({solar['co2_saved_kg_per_year']} kg CO₂/yr)")
const uprn = 10003469503; const response = await fetch( `https://api.homedata.co.uk/solar-assessment/${uprn}/`, { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const { solar_potential: s } = await response.json(); console.log(`${s.system_size_kwp} kWp — £${s.annual_savings_gbp}/yr, payback ${s.payback_years}y`);
View example response
{
"property": {
"uprn": 10003469503,
"address": "14 Acacia Avenue, Manchester, M20 4LN",
"property_type": "Semi-Detached",
"bedrooms": 3,
"construction_age_band": "1950-1966"
},
"roof": {
"estimated_area_m2": 72.0,
"usable_area_m2": 32.4,
"material": "Pitched, Slate",
"has_existing_solar": false,
"pitch_estimate_degrees": 35,
"orientation_estimate": "mixed"
},
"solar_potential": {
"max_panels": 18,
"system_size_kwp": 7.56,
"annual_generation_kwh": 4787,
"annual_savings_gbp": 673,
"annual_export_income_gbp": 145,
"system_cost_estimate_gbp": 13230,
"payback_years": 19.7,
"co2_saved_kg_per_year": 694,
"trees_equivalent_per_year": 33,
"local_irradiance_kwh_m2": 990
},
"with_battery": {
"annual_savings_gbp": 991,
"self_consumption_pct": 80,
"battery_cost_gbp": 4200,
"total_system_cost_gbp": 17430,
"payback_years": 17.6
},
"assumptions": {
"panel_wattage_w": 420,
"electricity_rate_p_kwh": 24.5,
"export_rate_p_kwh": 5.5,
"system_efficiency": 0.82
},
"data_quality": {
"confidence": "medium",
"missing_for_higher_confidence": ["os_footprint_area", "lidar_roof_pitch"],
"note": "Orientation assumed mixed — south-facing adds ~10-15% to estimates."
}
}
Use case: Solar installers, energy advisors, boiler-to-heat-pump assessors, home improvement tools. The has_existing_solar flag in the response (from our property database) indicates if solar panels are already present — useful for targeting leads.
Places around a property from OpenStreetMap, nearest first. Call /amenities/ for every group in one response,
or a single group: food, education, healthcare,
financial, civic, worship,
culture, convenience, green_spaces,
transport, shops.
Billing: 5 tokens for /amenities/, 1 token for a single group. Every account reaches this endpoint.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| uprn | string | one of* | UPRN the search is anchored on, e.g. 100023336956. The response echoes the resolved latitude and longitude. |
| radius_km | float | optional | Search radius in kilometres. Defaults to 8, maximum 25. The response echoes the value used. |
| lat + lng | float | one of* | WGS84 coordinates to search from, instead of a UPRN. |
| limit | integer | optional | Maximum results. Defaults to 50, maximum 200. |
| include_tags | boolean | optional | Include the full source tags for each result. Defaults to false. |
* Anchor the search with either uprn or lat + lng.
curl "https://api.homedata.co.uk/amenities/food/?uprn=100023336956&radius_km=0.5" \ -H "Authorization: Api-Key YOUR_API_KEY"
{
"uprn": 100023336956,
"group": "food",
"latitude": 51.503541,
"longitude": -0.12767,
"radius_km": 0.5,
"total": 6,
"type_counts": {
"cafe": 2,
"ice_cream": 1,
"restaurant": 1,
"pub": 1,
"fast_food": 1
},
"results": [
{
"osm_id": 11554148969,
"osm_type": "node",
"name": "The Drawing Room",
"type": "cafe",
"latitude": 51.505166,
"longitude": -0.126117,
"distance_m": 338
},
{
"osm_id": 12757688483,
"osm_type": "node",
"name": "The Royal Parks Ice-cream",
"type": "ice_cream",
"latitude": 51.502204,
"longitude": -0.130137,
"distance_m": 364
},
{
"osm_id": 13037832782,
"osm_type": "node",
"name": null,
"type": "cafe",
"latitude": 51.501456,
"longitude": -0.130079,
"distance_m": 459
}
]
}
Reading the response: a wide radius in a dense area returns the nearest results rather than everything —
the capture behind the example above came back with 50 for an 8 km search. type_counts totals each OSM tag in the result set, and every
result carries its distance_m from the property along with its OSM id and coordinates. name is
null for features OpenStreetMap has not named.
GPs, dentists and hospitals from the Care Quality Commission register, plus pharmacies from OpenStreetMap, nearest first. Call
/healthcare/ for all four, or one kind: gps,
dentists, pharmacies, hospitals.
Billing: 3 tokens for /healthcare/, 1 token for a single kind. Every account reaches this endpoint.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| uprn | string | one of* | UPRN the search is anchored on, e.g. 100023336956. The resolved coordinates come back as query.lat and query.lng. |
| radius_km | float | optional | Search radius in kilometres. Defaults to 1, maximum 10. The response echoes the radius and the limit it applied under query. |
| lat + lng | float | one of* | WGS84 coordinates to search from, instead of a UPRN. |
| limit | integer | optional | Maximum results per type. Defaults to 10, maximum 50. |
* Anchor the search with either uprn or lat + lng.
curl "https://api.homedata.co.uk/healthcare/gps/?uprn=100023336956&radius_km=2" \ -H "Authorization: Api-Key YOUR_API_KEY"
{
"query": {
"lat": 51.503541,
"lng": -0.12767,
"radius_km": 2.0,
"uprn": "100023336956",
"kind": "gps",
"types": [
"gp"
],
"limit": 10
},
"count": 10,
"type_counts": {
"gp": 10
},
"facilities": [
{
"id": "1-12687408410",
"source": "cqc",
"name": "Medloop",
"type": "gp",
"service_types": [
"Doctors/GPs",
"Doctors/GPs"
],
"address": {
"full_address": "24 Old Queen Street,London",
"postcode": "SW1H 9HP",
"local_authority": "Westminster",
"region": "London"
},
"location": {
"lat": 51.501,
"lng": -0.130912
},
"contact": {
"telephone": "3308180062",
"website": null
},
"cqc_url": "https://www.cqc.org.uk/location/1-12687408410",
"last_checked": "2024-01-22",
"distance_km": 0.36,
"distance_miles": 0.22
},
{
"id": "1-10241877096",
"source": "cqc",
"name": "Embankment Place Primary Healthcare",
"type": "gp",
"service_types": [
"Doctors/GPs",
"Doctors/GPs"
],
"address": {
"full_address": "1 Embankment Place,,London",
"postcode": "WC2N 6RH",
"local_authority": "Westminster",
"region": "London"
},
"location": {
"lat": 51.507987,
"lng": -0.124688
},
"contact": {
"telephone": null,
"website": null
},
"cqc_url": "https://www.cqc.org.uk/location/1-10241877096",
"last_checked": "2023-08-18",
"distance_km": 0.54,
"distance_miles": 0.33
}
],
"metadata": {
"sources": {
"gp": "Care Quality Commission",
"dentist": "Care Quality Commission",
"hospital": "Care Quality Commission",
"pharmacy": "OpenStreetMap (shop=pharmacy)"
},
"coverage": "United Kingdom",
"note": "Distance is straight-line (as the crow flies). CQC refreshes monthly; OSM via planet-osm extract. CQC doesn't regulate pharmacies \u2014 those come from OSM."
}
}
Reading the response: CQC entries carry the register id, address, telephone and a
cqc_url you can link to, plus last_checked — the date of the inspection CQC holds, not the date we
refreshed. Distances come as both distance_km and distance_miles, straight-line from the property.
The CQC register is refreshed monthly; pharmacies come from OpenStreetMap because CQC does not regulate them.
Petrol stations and EV charge points from OpenStreetMap, nearest first. Call /fuel-stations/ for both — each result is
tagged with its type — or one kind: petrol, ev.
Billing: 1 token. Every account reaches this endpoint.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| uprn | string | one of* | UPRN the search is anchored on, e.g. 100023336956. The response echoes the resolved latitude and longitude. |
| radius_km | float | optional | Search radius in kilometres. Defaults to 8, maximum 25. The response echoes the value used. |
| lat + lng | float | one of* | WGS84 coordinates to search from, instead of a UPRN. |
| limit | integer | optional | Maximum results. Defaults to 50, maximum 200. |
| include_tags | boolean | optional | Include the full source tags for each result. Defaults to false. |
* Anchor the search with either uprn or lat + lng.
curl "https://api.homedata.co.uk/fuel-stations/?uprn=100023336956&radius_km=2" \ -H "Authorization: Api-Key YOUR_API_KEY"
{
"uprn": 100023336956,
"kind": "all",
"latitude": 51.503541,
"longitude": -0.12767,
"radius_km": 2.0,
"total": 6,
"type_counts": {
"electric": 6
},
"results": [
{
"osm_id": 5584773894,
"osm_type": "node",
"name": "Source London",
"type": "electric",
"latitude": 51.506454,
"longitude": -0.123758,
"distance_m": 679
},
{
"osm_id": 12869392044,
"osm_type": "node",
"name": "Source London",
"type": "electric",
"latitude": 51.510999,
"longitude": -0.122007,
"distance_m": 1475
},
{
"osm_id": 5262372193,
"osm_type": "node",
"name": null,
"type": "electric",
"latitude": 51.494884,
"longitude": -0.12837,
"distance_m": 1550
}
]
}
Index of Multiple Deprivation (IMD) for any postcode in England — the overall rank/decile plus the seven underlying domains: income, employment, education, health, crime, barriers to housing & services, and living environment — and the two income-deprivation indices, for children (IDACI) and older people (IDAOPI). Sourced from MHCLG IMD open data.
Billing: 1 token per request. Auth: API key required.
curl "https://api.homedata.co.uk/deprivation/?postcode=SW1A+2AA" \ -H "Authorization: Api-Key YOUR_KEY"
Find schools near any property or postcode in England — with phase, age range, pupil numbers, type, and straight-line distance. Data sourced directly from the DfE's GIAS register (~27,000 open schools in England).
Ofsted data now included. The ofsted object returns rating (Outstanding, Good, Requires Improvement, Inadequate) and last_inspection date. Filter results with ?ofsted=Good. Coverage: ~27,000 schools with inspections.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string | one of* | UK postcode. e.g. SW1A 2AA |
| lat + lng | float | one of* | WGS84 decimal coordinates. e.g. lat=51.5074&lng=-0.1278 |
| uprn | string | one of* | Anchor on a property instead: the search runs from that UPRN's coordinates. |
| radius_km | float | optional | Search radius in kilometres. Default: 3, maximum 10. |
| limit | int | optional | Max results to return. Range: 1–50. Default: 20 |
| phase | string | optional | Filter by school phase: Primary, Secondary, All-through, Nursery, 16 plus |
| ofsted | string | optional | Filter by Ofsted rating: Outstanding, Good, Requires Improvement, Inadequate |
* Anchor the search with one of postcode, lat + lng, or uprn. Send one anchor, not several. The official SDK clients do not expose uprn for this endpoint yet — call it directly if you need it.
curl "https://api.homedata.co.uk/schools/nearby?postcode=SW1A+2AA&radius_km=1&phase=Primary" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/schools/nearby",
headers={"Authorization": "Api-Key YOUR_API_KEY"},
params={
"postcode": "SW1A 2AA",
"radius_km": 1,
"phase": "Primary",
}
)
data = response.json()
for school in data["schools"]:
ofsted = school["ofsted"]
rating = ofsted["rating"] if ofsted else "Not yet inspected"
print(f"{school['name']} — {rating} ({school['distance_km']}km)")
const params = new URLSearchParams({
postcode: 'SW1A 2AA',
radius_km: '1',
phase: 'Primary',
});
const response = await fetch(
`https://api.homedata.co.uk/schools/nearby?${params}`,
{ headers: { 'Authorization': 'Api-Key YOUR_API_KEY' } }
);
const data = await response.json();
data.schools.forEach(s =>
console.log(`${s.name} — ${s.ofsted?.rating ?? 'Not yet inspected'} (${s.distance_km}km)`)
);
View example response
{
"query": {
"lat": 51.5034,
"lng": -0.1276,
"radius_km": 1,
"postcode": "SW1A 2AA",
"phase": "Primary",
"ofsted": null
},
"count": 3,
"total_in_radius": 3,
"ofsted_summary": {},
"schools": [
{
"urn": 100024,
"name": "Westminster Cathedral Catholic Primary School",
"type": "Voluntary aided school",
"type_group": "Faith schools",
"phase": "Primary",
"gender": "Mixed",
"religious_character": "Roman Catholic",
"admissions_policy": "Selective",
"age_range": "3-11",
"number_of_pupils": 453,
"school_capacity": 480,
"percentage_fsm": 14.2,
"ofsted": null,
"address": {
"street": "Ambrosden Avenue",
"locality": null,
"town": "London",
"county": "Westminster",
"postcode": "SW1P 1QH"
},
"local_authority": "Westminster",
"contact": {
"website": "https://www.wccs.org.uk",
"telephone": "020 7798 9020",
"head_teacher": "Mrs Jane Smith"
},
"trust": null,
"location": {
"lat": 51.4968,
"lng": -0.1354
},
"distance_km": 0.34,
"distance_miles": 0.21
}
],
"metadata": {
"source": "GIAS — DfE Get Information About Schools",
"coverage": "England (~27,000 open schools)",
"note": "Distance is straight-line (as the crow flies)"
}
}
Error responses
| Status | Code | Meaning |
|---|---|---|
| 400 | — | Missing or unusable location: provide one of postcode, lat+lng, or uprn. This endpoint returns error as a plain message rather than a code object |
| 402 | insufficient_tokens | Not enough tokens for this request. Top up, then retry |
| 403 | INVALID_API_KEY | Key missing, wrong, revoked or unknown. A request with no key lands here too, not on 401 |
| 404 | RESOURCE_NOT_FOUND | School not found for the given URN (applies to /schools/{urn}) |
Use cases: School catchment analysis for estate agent listings, property valuation tools (proximity to top-rated schools is a significant price signal), family home search platforms, and conveyancing due diligence. Pair with Property Data for a complete area profile.
Capital-appreciation data for an outcode — annual growth rate, 1Y/3Y/5Y/10Y returns, and historical price index. Computed from Land Registry sold-price transactions.
Parameters
| Name | Type | Required | Validation | Example |
|---|---|---|---|---|
outcode |
string (path) | yes | UK outcode | SW1A |
View example response
{
"outcode": "SW1A",
"current_period": {
"from": "2025-06-17",
"to": "2025-08-12",
"median_sold_price": 2000000,
"sale_count": 3
},
"prior_period": {
"from": "2024-05-13",
"to": "2025-04-14",
"median_sold_price": 1400000,
"sale_count": 14
},
"yoy_change_pct": 42.86,
"yoy_change_gbp": 600000,
"trend": "rising",
"data_quality": "low"
}
ONS Census 2021 demographics for a postcode. The postcode is resolved to its MSOA (middle-layer super output area, ~7,500 residents), so the response describes that neighbourhood rather than the individual postcode unit.
Returns population counts, tenure breakdown (owned outright / owned with mortgage / social rented / private rented / rent-free), age bands, ethnicity, occupation, household size, and car ownership — plus MHCLG IMD 2019 deprivation when available. Includes the LSOA, MSOA and local authority codes so you can join to other ONS datasets.
Parameters
| Name | Type | Required | Validation | Example |
|---|---|---|---|---|
postcode |
string | yes | UK postcode | SW1A 2AA |
View example response
{
"postcode": "SW1A 2AA",
"area": {
"local_authority": null,
"local_authority_code": null,
"lsoa_code": null,
"lsoa_name": null,
"msoa_code": "E02000977"
},
"geography": {
"latitude": 51.503538,
"longitude": -0.127695,
"msoa_code": "E02000977",
"lsoa_code": null
},
"population": { "total": 6387, "households": 3432 },
"tenure": {
"owned_outright_pct": 16.35,
"owned_mortgage_pct": 7.4,
"shared_ownership_pct": 0.38,
"social_rented_pct": 23.92,
"private_rented_pct": 51.89,
"rent_free_pct": 0.06
},
"age": {
"age_0_15_pct": 7.34,
"age_16_29_pct": 29.53,
"age_30_44_pct": 24.58,
"age_45_64_pct": 25.5,
"age_65_plus_pct": 13.04
},
"ethnicity": {
"white_british_pct": 33.72,
"white_other_pct": 25.99,
"mixed_pct": 6.29,
"asian_pct": 22.2,
"black_pct": 4.02,
"other_pct": 7.12
},
"occupation": {
"managerial_professional_pct": 45.4,
"intermediate_pct": 17.66,
"routine_manual_pct": 12.81,
"never_worked_pct": 8.79
},
"household_size": { "one_person_pct": 56.53, "two_person_pct": 28.79, "three_plus_pct": 14.77 },
"car_ownership": { "no_car_pct": 75.92, "one_car_pct": 18.84, "two_plus_cars_pct": 5.24 },
"census_year": 2021,
"deprivation": null,
"data_sources": ["ONS Census 2021", "MHCLG IMD 2019"]
}
Historic England listed buildings within a radius of a UK postcode. Returns Grade I, II*, and II entries with name, location, list date, and a link back to the official Historic England record. Useful for planning, due-diligence, conveyancing, and heritage flows.
Authorization: Api-Key YOUR_KEYParameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| postcode | string | required | UK postcode. Spaces optional. |
| radius_km | number | optional | Search radius in km. Default 1, max 5. |
| grade | enum | optional | Filter to a single grade: I · II* · II. |
| limit | integer | optional | Maximum results. Defaults to 50, maximum 100. |
Response shape
{
"postcode": "SW1A 2AA",
"radius_km": 1.0,
"total": 50,
"grade_counts": { "I": 103, "II*": 149, "II": 574 },
"results": [
{
"list_entry": 1356989,
"name": "11, DOWNING STREET SW1",
"grade": "I",
"latitude": 51.5034, "longitude": -0.1278,
"date_listed": "1970-01-14",
"hyperlink": "https://historicengland.org.uk/listing/the-list/list-entry/1356989",
"distance_km": 0.019
}
]
}
curl "https://api.homedata.co.uk/listed-buildings/?postcode=SW1A2AA&grade=I" \
-H "Authorization: Api-Key YOUR_API_KEY"
Calculate UK Stamp Duty Land Tax (SDLT) for England and Northern Ireland. Returns total tax, effective rate, and a band-by-band breakdown. Supports standard buyers, first-time buyers (with £300k relief), and additional-dwelling purchases (5% surcharge on the full price).
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| price | integer (£) | required | Property purchase price in GBP. Positive integer. |
| buyer_type | enum | required | standard · first_time · additional (second home / BTL). |
Response shape — first-time buyer, £350k
{
"price": 350000,
"buyer_type": "first_time",
"total_tax": 2500.0,
"effective_rate_pct": 0.714,
"breakdown": [
{ "band": "Up to £300,000 (first-time buyer relief)", "rate_pct": 0.0, "taxable_amount": 300000, "tax": 0.0 },
{ "band": "£300,000 – £500,000 (first-time buyer)", "rate_pct": 5.0, "taxable_amount": 50000, "tax": 2500.0 }
],
"jurisdiction": "England and Northern Ireland",
"thresholds_from": "1 April 2025"
}
curl "https://api.homedata.co.uk/calculators/stamp-duty/?price=350000&buyer_type=first_time" \
-H "Authorization: Api-Key YOUR_API_KEY"
Mortgage repayment calculator — given price, deposit, annual rate and term in years, returns the monthly payment, total repayment, total interest, and the LTV / LTI ratios. Standard amortising-loan formula.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| price | integer (£) | required | Property purchase price in GBP. |
| deposit | integer (£) | required | Up-front deposit, GBP. Non-negative. |
| rate | number (%) | required | Annual interest rate, percent (e.g. 4.5). |
| term | integer | optional | Mortgage term in years, 1–40. Default: 25. Echoed back as term_years. |
Response shape — £350k @ 4.5% / 25y, £35k deposit
{
"loan_amount": 315000,
"deposit": 35000,
"property_price": 350000,
"annual_rate_pct": 4.5,
"term_years": 25,
"monthly_payment": 1750.87,
"total_repayment": 525261.69,
"total_interest": 210261.69,
"ltv_pct": 90.0,
"lti_ratio": 14.99
}
curl "https://api.homedata.co.uk/calculators/mortgage/?price=350000&deposit=35000&rate=4.5&term=25" \
-H "Authorization: Api-Key YOUR_API_KEY"
Try every endpoint with your own key
The developer playground runs live requests against your account and gives you copy-paste curl / Python / Node / PHP snippets for every endpoint above.
Open the Playground →Calling from the browser?
Don't put your API key in client-side JavaScript. Create a public key scoped to the tools and domains you need, then call the relay at /embed/v2/{tool_slug} with the public key in an Authorization: Public-Key header. Or skip the wiring entirely — drop-in widget bundles are ready for the common tools.
Integrate into your own product
Pay as you goAll 40+ production endpoints return UPRN-matched, structured JSON responses with consistent field naming and OGL-licensed source attribution — covering 29M+ UK properties across address, property, EPC, risks, planning, council tax, and market data via a single authenticated API key.
Structured as JSON · queryable by UPRN or postcode · ready to embed in any application
Exact measurements
Real values — distances, concentrations, counts — not rounded ratings
29 million UK properties covered
Every address queryable by UPRN or postcode
REST API
JSON responses, OpenAPI docs, sandbox — first call in under 5 minutes
Pay as you go: 100 tokens = £1 across every endpoint, no subscription needed. Bonus tokens with an optional monthly subscription, and your first top-up matched 100%. See pricing →
Sources
Further reading
Authentication · Data Dictionary · Error codes · Coverage matrix