API Reference
All endpoints return JSON. Authentication uses Authorization: Api-Key YOUR_KEY on every request.
https://api.homedata.co.uk/api
Property Intelligence
Full property record including address, type, tenure, bedrooms, floor area, EPC, construction age, and sold dates. Returns data for any of the UK's 29M+ addressable properties.
curl https://api.homedata.co.uk/api/properties/10093609154 \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/properties/10093609154",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()["data"]
print(data["address"]["full_address"])
const response = await fetch( "https://api.homedata.co.uk/api/properties/10093609154", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); console.log(data.full_address);
View example response
{
"uprn": 10093609154,
"usrn": 74503415,
"udprn": 53129037,
"full_address": "APARTMENT 1009, CHAPMAN HOUSE, SALFORD, M3 5FH",
"address": "Apartment 1009 Chapman House",
"postcode": "M3 5FH",
"outward_postcode": "M3",
"building_name": "CHAPMAN HOUSE",
"street_name": "TRINITY WAY",
"town_name": "SALFORD",
"property_type": "Flat",
"built_form": "Purpose Built",
"construction_age_band": "2007-2011",
"bedrooms": 2,
"bathrooms": 1,
"habitable_rooms": 3,
"epc_floor_area": 56.0,
"internal_area_sqm": 56.0,
"current_energy_efficiency": 84,
"current_energy_rating": "B",
"potential_energy_efficiency": 84,
"tenure": "Leasehold",
"council_tax_band": "C",
"has_garden": false,
"has_parking": false,
"windows_type": "Double glazed",
"last_sold_date": "2019-11-15",
"last_sold_price": 135000,
"latitude": 53.4851,
"longitude": -2.2537
}
80+ fields available — see Data Dictionary for the full list.
EPC & Energy
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/api/epc-checker/100023336956/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/epc-checker/100023336956/",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
epc = response.json()
print(f"Rating: {epc['current_energy_efficiency']}")
const response = await fetch( "https://api.homedata.co.uk/api/epc-checker/100023336956/", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const epc = await response.json(); console.log(`Rating: ${epc.current_energy_efficiency}`);
View example response
{
"uprn": 10093609154,
"current_energy_efficiency": 84,
"potential_energy_efficiency": 84,
"last_epc_date": "2020-07-28",
"epc_floor_area": 59,
"construction_age_band": "2007-2011",
"epc_id": "1813679032512020072814144822200478"
}
Environmental Risks
Environmental risk assessment for any UK property. 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/api/risks/flood/?uprn=100023336956" \ -H "Authorization: Api-Key YOUR_API_KEY" # All risk types in one call curl "https://api.homedata.co.uk/api/risks/all/?uprn=100023336956" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/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/api/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"
}
}
]
}
Postcode Profile
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/api/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
Price Trends
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/api/price_trends/SW1A/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/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/api/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 Distributions
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/api/price_distributions/E1/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/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/api/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
}
}
Comparables
BetaFind comparable sold properties near a given UPRN. Uses PostGIS spatial queries to find nearby sales with similar characteristics.
curl https://api.homedata.co.uk/api/comparables/100023336956/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/comparables/100023336956/",
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
comps = response.json()
print(f"Found {comps['total_results']} comparables")
for c in comps["comparables"]:
print(f"{c['address']}: £{c['sold_let_price']:,} ({c['distance_meters']:.0f}m away)")
const response = await fetch( "https://api.homedata.co.uk/api/comparables/100023336956/", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const comps = await response.json(); console.log(`Found ${comps.total_results} comparables`); comps.comparables.forEach(c => console.log(`${c.address}: £${c.sold_let_price?.toLocaleString()} (${Math.round(c.distance_meters)}m away)`) );
View example response
{
"reference_uprn": 100023336956,
"filters": {
"bedrooms": null,
"property_type": null,
"count": 20,
"start_date": "2025-03-13",
"end_date": "2026-03-13",
"event_type": "all"
},
"comparables": [
{
"uprn": 10033541876,
"address": "Flat 2, 14 Downing Street",
"postcode": "SW1A 2AB",
"bedrooms": 2,
"bathrooms": 1,
"epc_floor_area": 68.0,
"property_type": "Flat",
"construction_age_band": "1900-1929",
"current_energy_efficiency": 62,
"distance_meters": 45.2,
"sale_id": 87234,
"txid": "A1B2C3D4E5F6",
"sold_let_date": "2025-11-15",
"sold_let_price": 925000,
"listing_price": 950000,
"transaction_type": "Sale",
"is_complete": true,
"latest_listing": {
"listing_id": "HD173456789",
"added_date": "2025-08-20",
"latest_price": 950000,
"latest_status": "Sold STC",
"source": "Home.co.uk"
},
"title": {
"title_no": "TGL123456",
"estate_interest": "Leasehold",
"title_class": "Absolute"
}
}
],
"total_results": 18,
"response_time_seconds": 0.2341
}
Address by Postcode
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/api/address/postcode/SW1A2AA/ \
-H "Authorization: Api-Key YOUR_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/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/api/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,
"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.
Address Search
Full-text address search powered by Elasticsearch (36M+ UK addresses). Type-ahead autocomplete for address forms and property lookup interfaces. Returns matched addresses with UPRNs for use with the retrieve endpoint.
Authorization: Api-Key YOUR_KEYq (required) — search query (minimum 2 characters)curl "https://api.homedata.co.uk/api/address/find/?q=10%20Downing%20Street" \
-H "Authorization: Api-Key YOUR_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/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/api/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,
"address": "10 Downing Street",
"address_line_1": "10 Downing Street",
"address_line_2": null,
"town": "London",
"postcode": "SW1A 2AA"
},
{
"uprn": 10004862792,
"address": "10 Downing Street",
"address_line_1": "10 Downing Street",
"address_line_2": null,
"town": "Llanelli",
"postcode": "SA15 2UA"
}
],
"meta": { "query_type": "address_search", "took_ms": 12, "total": 7 }
}
Address Retrieve
Enriched property data for a known UPRN. Use after Address Search or Address by Postcode to get property intelligence.
level (optional) — enrichment level: address (default) or propertyEnrichment levels
address
Address fields, UPRN, coordinates
property
+ property type, bedrooms, bathrooms, EPC, floor area, last sold price
# Address only (default) curl https://api.homedata.co.uk/api/address/retrieve/100023336956/ \ -H "Authorization: Api-Key YOUR_API_KEY" # Property enrichment curl "https://api.homedata.co.uk/api/address/retrieve/100023336956/?level=property" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/address/retrieve/100023336956/",
params={"level": "property"},
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/api/address/retrieve/100023336956/?level=property", { 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 (level=address)
{
"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,
"level": "address"
}
View example response (level=property)
{
// ... 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": 925000,
"last_sold_adjusted_price": 980000,
"classification_code": "RD03",
"level": "property"
}
Broadband Speeds
Limited Coverage⚠ 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/api/broadband?postcode=SW1A2AA" \
-H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/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/api/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 |
Boundaries Autocomplete
No authSearch for administrative boundaries (local authorities, wards, parishes) by name. Returns boundary metadata. Available on all plans including Free — no API key required.
curl "https://api.homedata.co.uk/api/boundaries/autocomplete/?q=islington"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/boundaries/autocomplete/",
params={"q": "islington"}
)
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/api/boundaries/autocomplete/?q=islington"
);
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 Titles
Land Registry title boundary data for a property. Returns a GeoJSON Feature with the title polygon.
curl https://api.homedata.co.uk/api/property_lr_titles/100023336956/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/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/api/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"
}
}
Land Registry Sales
HM Land Registry confirmed sale completions for a property. Returns one row per HMLR-registered transaction with txid, sold_let_date and sold_let_price. Accepts either ?uprn= (every confirmed sale on the property) or ?sale= (a single sale ID from /property_listings).
uprn (required), page (optional, pagination)curl "https://api.homedata.co.uk/api/lr_sales/?uprn=10093609154" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/lr_sales/",
params={"uprn": "10093609154"},
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
for sale in data["results"]:
print(f"{sale['transaction_type']}: £{sale.get('sold_let_price', 'N/A')}")
const response = await fetch( "https://api.homedata.co.uk/api/lr_sales/?uprn=10093609154", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); data.results.forEach(s => console.log(`${s.transaction_type}: £${s.sold_let_price ?? 'N/A'}`) );
View example response
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 6648488,
"sold_let_date": "2020-11-18",
"first_listing_date": "2020-07-22",
"sold_let_price": 180000,
"is_complete": true,
"is_available": false,
"property": 100090913175,
"txid": "BEF7EBBF-2334-7A76-E053-6B04A8C092F7",
"transaction_type": "Sale",
"property_listings": [
{
"id": "d7aa77e7-8f91-4164-94d0-bffd4dcc0aea",
"agent": 20676,
"property": 100090913175,
"sale": 6648488,
"display_address": "Moorland Close Norwich Norfolk",
"postcode": "NR7 8HD",
"transaction_type": "Sale",
"added_date": "2020-07-22",
"first_offer_date": null,
"first_sold_or_let_date": "2020-08-28",
"sale_cancelled_date": null,
"withdrawn_date": "2020-11-18",
"is_withdrawn": true,
"reduced_date": null,
"latest_status": "Undetermined",
"latest_price": 200000,
"is_new_build": null,
"listing_property_type": null,
"bedrooms": 3,
"bathrooms": 1,
"reception_rooms": null,
"ownership": null,
"description": null,
"source": "Home.co.uk",
"is_live": false,
"images": ["https://api.homedata.co.uk/api/images/p/..."]
}
]
}
]
}
Historic Listings
Every historic listing ever created for a property, sourced from Home.co.uk. One row per listing with price, status, agent, and lifecycle dates. There's no bare list view — query by uprn or property, or fetch a single listing by its UUID at /api/property_listings/{id}/.
Parameters
| Name | Type | Required | Validation | Example |
|---|---|---|---|---|
uprn |
int | one of* | 8–12 digits | 100090913175 |
property |
int | one of* | Alias for uprn |
100090913175 |
page_size |
int | optional | 1–100 (default 20) | 20 |
* Provide either uprn or property.
# All listings ever created for a UPRN curl "https://api.homedata.co.uk/api/property_listings/?uprn=100090913175" \ -H "Authorization: Api-Key YOUR_API_KEY" # Single listing by UUID curl "https://api.homedata.co.uk/api/property_listings/2e33a1ae-8fce-4a1a-862b-3bdac78a5f9a/" \ -H "Authorization: Api-Key YOUR_API_KEY"
View example response
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": "2e33a1ae-8fce-4a1a-862b-3bdac78a5f9a",
"agent": 21244,
"property": 100090913175,
"sale": 56838418,
"display_address": "Moorland Close, Norwich",
"postcode": "NR7 8HD",
"transaction_type": "Sale",
"added_date": "2026-03-11",
"first_offer_date": null,
"first_sold_or_let_date": null,
"sale_cancelled_date": null,
"withdrawn_date": null,
"is_withdrawn": false,
"reduced_date": null,
"latest_status": "For sale",
"latest_price": 280000,
"is_new_build": false,
"listing_property_type": "Semi-Detached",
"bedrooms": 3,
"bathrooms": 1,
"reception_rooms": null,
"ownership": "Freehold",
"description": "...",
"source": "Home.co.uk"
}
]
}
Market Activity
The full listing lifecycle for any sale — every event from first instruction to completion. Returns Added, Reduced, Under Offer, Sold STC, Completed, Withdrawn and more, each timestamped and priced. Unlike Land Registry (completions only, 3–6 month lag), this includes properties that were listed but never sold. 30 years of data from Home.co.uk.
At least one filter is required. The typical flow: call Property Sales with a UPRN to get sale IDs, then pass ?sale= here for that sale's timeline.
sale)Filters (at least one required)
| Param | Type | Example | Description |
|---|---|---|---|
sale |
int | ?sale=789 |
Events for a specific sale. This is how you get the timeline. |
uprn |
int (8–12 digits) | ?uprn=100090913175 |
All events across every sale for a UPRN |
listing |
UUID | ?listing=abc-def… |
Events from a specific listing |
event_type |
string | ?event_type=Sold STC |
Only events of this type |
date |
date | ?date=2026-01-15 |
Exact date match |
date__gte |
date | ?date__gte=2025-01-01 |
Events on or after this date |
date__lte |
date | ?date__lte=2026-04-01 |
Events on or before this date |
id |
int | ?id=12345 |
Single event by ID |
Sorting & Pagination
| Param | Description |
|---|---|
?ordering=-date |
Default — newest first |
?ordering=date |
Oldest first (chronological timeline) |
?ordering=-price |
Highest price first |
?ordering=price |
Lowest price first |
?ordering=event_type |
Alphabetical by event type |
?page=1 |
Page number (default 1) |
?limit=5 |
Max results per request (default 10, max 100) |
Event Types
| Event | What it means |
|---|---|
Added | Listing first appeared on market |
Added by another agent | Re-listed by a different agent |
Added by new agent | New agent took over the listing |
Added by another undetermined agent | Re-listed by an agent we couldn't uniquely identify |
Added date modified for old listing | Backfill correction on an older listing's added date |
Reduced | Price dropped |
Price Increased | Price went up |
Under offer | Buyer's offer accepted (not yet legally committed) |
Sold STC | Sold Subject to Contract (sale agreed) |
Sold STCM | Sold STC with mortgage |
Completed | Sale completed (Land Registry confirmed) |
Withdrawn | Taken off market |
Sale Cancelled | Sale fell through after STC |
Let agreed | Rental let agreed |
# Full timeline for a sale, newest first (default) curl "https://api.homedata.co.uk/api/property_sale_events/?sale=789&ordering=-date" \ -H "Authorization: Api-Key YOUR_API_KEY" # Just the latest 3 events curl "https://api.homedata.co.uk/api/property_sale_events/?sale=789&ordering=-date&limit=3" \ -H "Authorization: Api-Key YOUR_API_KEY" # Only price reductions in 2026 curl "https://api.homedata.co.uk/api/property_sale_events/?sale=789&event_type=Reduced&date__gte=2026-01-01" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
headers = {"Authorization": "Api-Key YOUR_API_KEY"}
# Step 1 — get sale IDs for a UPRN via Property Sales
sales = requests.get(
"https://api.homedata.co.uk/api/lr_sales/",
params={"property": "100023336956"},
headers=headers
).json()["results"]
# Step 2 — get chronological timeline for the first sale
events = requests.get(
"https://api.homedata.co.uk/api/property_sale_events/",
params={"sale": sales[0]["id"], "ordering": "date"},
headers=headers
).json()["results"]
for e in events:
price = f"£{e['price']:,}" if e['price'] else "—"
print(f"{e['date']} {e['event_type']:<15} {price}")
const headers = { "Authorization": "Api-Key YOUR_API_KEY" };
// Latest 5 events for sale 789
const resp = await fetch(
"https://api.homedata.co.uk/api/property_sale_events/?sale=789&ordering=-date&limit=5",
{ headers }
);
const { results } = await resp.json();
for (const e of results) {
const price = e.price ? `£${e.price.toLocaleString()}` : "—";
console.log(`${e.date} ${e.event_type} ${price}`);
}
View example response
{
"count": 4,
"next": null,
"previous": null,
"results": [
{
"id": 1001,
"listing": "uuid-of-listing",
"sale": 789,
"event_type": "Completed",
"date": "2026-03-15",
"price": 350000,
"source": "Land registry"
},
{
"id": 1000,
"listing": "uuid-of-listing",
"sale": 789,
"event_type": "Sold STC",
"date": "2026-02-01",
"price": 350000,
"source": "Home.co.uk"
},
{
"id": 999,
"listing": "uuid-of-listing",
"sale": 789,
"event_type": "Reduced",
"date": "2026-01-05",
"price": 360000,
"source": "Home.co.uk"
},
{
"id": 998,
"listing": "uuid-of-listing",
"sale": 789,
"event_type": "Added",
"date": "2025-11-20",
"price": 375000,
"source": "Home.co.uk"
}
]
}
source is always "Home.co.uk" for portal events, "Land registry" for completion events — the originating portal name is never exposed.
Live Listings
Search currently active UK property listings. Filter by boundary, property type, price range, and bedrooms. Returns paginated results with price, property details, and UPRN for chaining into other endpoints.
Two-step workflow: Use Boundaries Autocomplete to find a boundary_id for your location, then pass it here. For example, search for "Manchester" → get id: 14624 → use boundary_id=14624.
Parameters
| Name | Type | Description |
|---|---|---|
boundary_id |
int | Area filter — from Boundaries Autocomplete. Mutually exclusive with uprn. |
uprn |
int (8–12 digits) | Single-property filter. Mutually exclusive with boundary_id. |
transaction_type |
string | "Sale" or "Rental" — omit for both |
bedrooms |
int | Minimum bedrooms |
max_bedrooms |
int | Maximum bedrooms |
min_price |
int | Minimum asking price (GBP) |
max_price |
int | Maximum asking price (GBP) |
property_type |
string | Comma-separated: Detached, Semi-Detached, Terraced, Flat |
new_builds_only |
bool | true to return only new-build listings |
reduced_only |
bool | true to return only listings with a price reduction |
sort |
string | -added_date (default), added_date, -latest_price, latest_price |
page / page_size |
int | Pagination. Default page_size=30, max 100. |
# Step 1: Find the boundary ID for your location curl "https://api.homedata.co.uk/api/boundaries/autocomplete/?q=Manchester" # → {"results": [{"id": 14624, "name": "Manchester", ...}]} # Step 2: Search listings within that boundary curl "https://api.homedata.co.uk/api/live-listings/search/?boundary_id=14624&transaction_type=Sale&bedrooms=3" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests # Step 1: Find boundary ID boundaries = requests.get( "https://api.homedata.co.uk/api/boundaries/autocomplete/", params={"q": "Manchester"} ).json() boundary_id = boundaries["results"][0]["id"] # Step 2: Search listings response = requests.get( "https://api.homedata.co.uk/api/live-listings/search/", params={ "boundary_id": boundary_id, "transaction_type": "Sale", "max_price": 400000 }, headers={"Authorization": "Api-Key YOUR_API_KEY"} ) data = response.json() print(f"Found {data['count']} listings") for listing in data["results"][:5]: print(f"£{listing['latest_price']:,} — {listing['display_address']}")
// Step 1: Find boundary ID const boundaries = await fetch( "https://api.homedata.co.uk/api/boundaries/autocomplete/?q=Manchester" ).then(r => r.json()); const boundaryId = boundaries.results[0].id; // Step 2: Search listings const response = await fetch( `https://api.homedata.co.uk/api/live-listings/search/?boundary_id=${boundaryId}&transaction_type=Sale`, { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); console.log(`Found ${data.count} listings`); data.results.slice(0, 5).forEach(l => console.log(`£${l.latest_price?.toLocaleString()} — ${l.display_address}`) );
View example response
{
"count": 14,
"page": 1,
"page_size": 30,
"total_pages": 1,
"results": [
{
"id": "2e33a1ae-8fce-4a1a-862b-3bdac78a5f9a",
"property_uprn": 100090913175,
"sale_id": null,
"display_address": "Moorland Close, Norwich",
"transaction_type": "Sale",
"latest_status": "For sale",
"latest_price": 280000,
"source": "Home.co.uk",
"bedrooms": 3,
"bathrooms": 1,
"reception_rooms": null,
"listing_property_type": "Semi-Detached",
"loki_property_type": "Semi-Detached",
"ownership": "Freehold",
"is_new_build": false,
"added_date": "2026-03-11T00:00:00",
"first_offer_date": null,
"first_sold_or_let_date": null,
"sale_cancelled_date": null,
"reduced_date": null,
"description": "...",
"geopoint": {"lat": 52.64, "lon": 1.29},
"images": ["https://api.homedata.co.uk/api/images/p/..."],
"agent_name": "..."
}
]
}
Council Tax Band
Coming Soon⚠ Coming Soon — endpoint not yet live
The Council Tax Band endpoint is not currently returning data. The schema and code samples below describe the planned shape so you can prepare your integration, but live requests will fail. Watch this page for go-live, or contact us to join the launch notification list.
Look up the council tax band for any UK residential property. Data sourced live from HMRC's Valuation Office Agency (VOA). Returns the band (A–H) and verified address.
Different from other endpoints: This endpoint uses postcode + building_number (or building_name) — not a UPRN. If you only have a UPRN, use Address Retrieve first to get the building number, then call this endpoint.
postcode (required), building_number or building_name (one required)curl "https://api.homedata.co.uk/api/council_tax_band/?postcode=SW1A+2AA&building_number=10" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/council_tax_band/",
params={
"postcode": "SW1A 2AA",
"building_number": "10"
},
headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()
print(f"Council Tax Band: {data['council_tax_band']}")
const response = await fetch( "https://api.homedata.co.uk/api/council_tax_band/?postcode=SW1A+2AA&building_number=10", { headers: { "Authorization": "Api-Key YOUR_API_KEY" } } ); const data = await response.json(); console.log(`Council Tax Band: ${data.council_tax_band}`);
View example response
{
"address": "10 DOWNING STREET, LONDON, SW1A 2AA",
"council_tax_band": "H"
}
Planning Applications
Search planning applications near a UK location. National coverage across 417 Local Planning Authorities with ~20M geocoded applications. 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/api/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/api/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/api/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
}
]
}
Crime Data
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/api/crime/nearby?postcode=SW1A+2AA" \ -H "Authorization: Api-Key YOUR_API_KEY" # With date and category filter curl "https://api.homedata.co.uk/api/crime/nearby?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/api/crime/nearby",
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/api/crime/nearby?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.
Solar Assessment
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/api/solar-assessment/10003469503/ \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests UPRN = 10003469503 response = requests.get( f"https://api.homedata.co.uk/api/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/api/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. Phase 2 will add satellite-derived roof orientation for ±5% accuracy improvement.
NHS Amenities Nearby
Find nearby NHS GPs, dentists, pharmacies, and hospitals — sorted by distance. Covers GP practices (NHS Digital), dental practices (NHSBSA), pharmacies (NHS Service Directory), and hospitals (NHS Digital). Data cached in Loki — no live external API calls per request.
New endpoint. NHS amenity data is bulk-imported from NHS Digital open datasets. Coverage: ~11,000+ GP practices, 12,000+ pharmacies, 1,000+ dental practices, 1,500+ hospital sites across England.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| uprn | string | required* | Property UPRN (e.g. 100021421083) |
| lat | float | required* | Latitude (e.g. 51.5074) |
| lng | float | required* | Longitude (e.g. -0.1278) |
| radius_km | float | optional | Search radius in km. Default: 1, max: 10 |
| types | string | optional | Comma-separated list: gp, dentist, pharmacy, hospital. Default: all types |
| limit | int | optional | Max results per type. Default: 10, max: 50 |
* Provide uprn OR lat + lng — not both.
curl "https://api.homedata.co.uk/api/amenities/nearby?uprn=100021421083&radius_km=1&types=gp,dentist,pharmacy" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/amenities/nearby",
headers={"Authorization": "Api-Key YOUR_API_KEY"},
params={
"uprn": "100021421083",
"radius_km": 1,
"types": "gp,dentist,pharmacy",
}
)
data = response.json()
for amenity in data["amenities"]:
print(f"{amenity['name']} [{amenity['type']}] — {amenity['distance_km']}km")
const params = new URLSearchParams({
uprn: '100021421083',
radius_km: '1',
types: 'gp,dentist,pharmacy',
});
const response = await fetch(
`https://api.homedata.co.uk/api/amenities/nearby?${params}`,
{ headers: { 'Authorization': 'Api-Key YOUR_API_KEY' } }
);
const data = await response.json();
data.amenities.forEach(a =>
console.log(`${a.name} [${a.type}] — ${a.distance_km}km`)
);
View example response
{
"query": {
"lat": 51.5074,
"lng": -0.1278,
"radius_km": 1,
"uprn": "100021421083",
"types": ["gp", "dentist", "pharmacy"],
"limit": 10
},
"count": 5,
"type_counts": {
"gp": 2,
"dentist": 1,
"pharmacy": 2,
"hospital": 0
},
"amenities": [
{
"organisation_id": "Y00001",
"name": "The Mayfield Practice",
"type": "gp",
"address": {
"line1": "10 High Street",
"city": "London",
"postcode": "SW1A 1AA"
},
"location": { "lat": 51.5074, "lng": -0.1278 },
"contact": {
"telephone": "020 7123 4567",
"website": "https://example.com"
},
"distance_km": 0.23,
"distance_miles": 0.14
},
{
"organisation_id": "V00001",
"name": "Westminster Dental Care",
"type": "dentist",
"address": {
"line1": "5 Parliament Square",
"city": "London",
"postcode": "SW1A 2AA"
},
"location": { "lat": 51.4995, "lng": -0.1248 },
"contact": { "telephone": "020 7123 7890" },
"distance_km": 0.41,
"distance_miles": 0.25
},
{
"organisation_id": "P00001",
"name": "Boots Pharmacy Westminster",
"type": "pharmacy",
"address": {
"line1": "1 Bridge Street",
"city": "London",
"postcode": "SW1A 2AA"
},
"location": { "lat": 51.5015, "lng": -0.1275 },
"contact": { "telephone": "020 7123 1111" },
"dispensary": true,
"distance_km": 0.55,
"distance_miles": 0.34
}
],
"metadata": {
"source": "NHS Digital / NHSBSA / NHS Service Directory",
"coverage": "England",
"note": "Distance is straight-line (as the crow flies). NHS data updated quarterly."
}
}
Error responses
| Status | Code | Meaning |
|---|---|---|
| 401 | authentication_required | Missing or invalid API key |
| 403 | endpoint_not_allowed | Your plan doesn't include NHS Amenities. Requires Starter or above. |
| 422 | invalid_params | Missing location param — provide uprn or lat+lng |
| 429 | rate_limit_exceeded | Request rate limit reached |
Use cases: Property buyers and investors want to know proximity to NHS services — especially GPs accepting new patients and pharmacy access for elderly or family buyers. Estate agents can highlight "doctor and dentist within 0.5km" in listings. Pair with Property Intelligence and Schools Nearby for a complete local amenities profile.
Schools Nearby
Find schools near any UK property or postcode — 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 ratings are being integrated.
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 |
| radius | float | optional | Search radius in miles. Range: 0.1–5.0. Default: 0.5 |
| 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 |
* Provide either postcode or lat + lng — not both.
curl "https://api.homedata.co.uk/api/schools/nearby?postcode=SW1A+2AA&radius=0.5&phase=Primary" \ -H "Authorization: Api-Key YOUR_API_KEY"
import requests
response = requests.get(
"https://api.homedata.co.uk/api/schools/nearby",
headers={"Authorization": "Api-Key YOUR_API_KEY"},
params={
"postcode": "SW1A 2AA",
"radius": 0.5,
"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: '0.5',
phase: 'Primary',
});
const response = await fetch(
`https://api.homedata.co.uk/api/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_miles": 0.5,
"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 |
|---|---|---|
| 401 | authentication_required | Missing or invalid API key |
| 403 | endpoint_not_allowed | Your plan doesn't include Schools. Requires Starter or above. |
| 404 | not_found | School not found for the given URN (applies to /schools/{urn}) |
| 422 | invalid_params | Missing location param — provide postcode or lat+lng |
| 429 | rate_limit_exceeded | Request rate limit reached |
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 Intelligence for a complete area profile.
Flood Risk
Dedicated flood-risk endpoint — NaFRA2 river/sea and surface-water scores for any UK UPRN. Returns structured Low/Medium/High/Very High labels plus a numeric score. Local PostGIS lookup (<1ms), no WMS round-trips.
Parameters
| Name | Type | Required | Validation | Example |
|---|---|---|---|---|
uprn |
int | yes | 8–12 digits | 100023336956 |
View example response
{
"location": {
"lat": 51.503541,
"lng": -0.12767,
"uprn": 100023336956
},
"flood_risk": {
"rivers_and_sea": {
"risk_band": "Very low",
"score": 1,
"confidence": null,
"description": "Less than 1 in 1,000 chance of flooding each year"
},
"surface_water": {
"risk_band": "Low",
"score": 2,
"confidence": null,
"description": "Between 1 in 1,000 and 1 in 100 chance of flooding each year"
}
},
"overall_risk": "Low",
"data_source": "local"
}
Price Growth
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"
}
Demographics
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"]
}
Valuations
Coming Soon⚠ Coming Soon — endpoint not yet live
Automated valuations are currently in private testing. The schema and code samples below describe the planned shape so you can prepare your integration, but live requests will fail. Watch this page for go-live, or contact us for early access.
Estimated sale or rental value for a property. A three-tier fallback picks the strongest available signal:
- Recent sale — if the property completed in the past 12 months, returns the Land Registry sold price (
method: "recent_sale_price", confidence high). - Active listing — if currently listed for sale, returns the asking price (
method: "active_listing_price", confidence high). - Composite comparables — otherwise runs a PostGIS radius search over sold + listed comparables, adjusts for HPI, and returns a weighted average (
method: "composite_score_weighted_average").
Every response includes the method field so you know which signal drove the number, plus confidence_low / confidence_high for the band and comparable_count for how many comparables were used (only meaningful for the composite fallback).
Parameters
| Name | Type | Required | Validation | Example |
|---|---|---|---|---|
uprn |
int | yes | 8–12 digits | 100023336956 |
bedrooms |
int | yes | positive integer | 3 |
property_type |
string | yes | Bungalow, Detached, Flat, Maisonette, Semi-Detached, Terraced | Terraced |
type |
string | optional | sale (default) or rent |
sale |
View example response
// Tier 3 — composite comparable search (most detailed shape)
{
"uprn": 100023336956,
"type": "sale",
"estimate_gbp": 425000,
"range_low_gbp": 382000,
"range_high_gbp": 467000,
"confidence": {
"level": "high",
"tier": "good",
"label": "Good",
"reasons": ["sufficient_comparables", "good_similarity"],
"comparable_count": 6
},
"comparables_count": 6,
"method": "composite_score_weighted_average",
"attribution": "Based on 6 comparable sales within 850m, adjusted to today's prices using Land Registry HPI.",
"comparable_properties": [
{
"uprn": 100022677605,
"address": "5 Example Road",
"postcode": "SW19 1AA",
"bedrooms": 3,
"property_type": "Terraced",
"floor_area_m2": 95,
"distance_m": 85.3,
"sale_date": "2024-03-15",
"sale_price_gbp": 410000,
"adjusted_price_gbp": 418200,
"weight": 0.19
}
],
"methodology": {
"weights": { "distance": 0.40, "bedrooms": 0.30, "type": 0.20, "floor_area": 0.10 },
"hpi_monthly_growth": 0.004,
"comparable_radius_miles": 2,
"sale_date_max_years": 5
},
"response_time_seconds": 0.23
}
Tier 1 — recent sale (simpler shape)
{
"uprn": 100023336956,
"type": "sale",
"estimate_gbp": 350000,
"range_low_gbp": 332000,
"range_high_gbp": 367000,
"confidence": {
"level": "high",
"tier": "recent_sale",
"label": "Recent sale",
"reasons": ["property_sold_within_12_months"],
"comparable_count": 0
},
"comparables_count": 0,
"method": "recent_sale_price",
"attribution": "Property sold for £350,000 on 2025-09-15.",
"comparable_properties": [],
"methodology": { "source": "land_registry_sold_price", "sold_date": "2025-09-15" },
"response_time_seconds": 0.02
}
Tier 2 — active listing (simpler shape)
{
"uprn": 100023336956,
"type": "sale",
"estimate_gbp": 425000,
"range_low_gbp": 403000,
"range_high_gbp": 446000,
"confidence": {
"level": "high",
"tier": "listed",
"label": "Active listing",
"reasons": ["property_currently_listed_for_sale"],
"comparable_count": 0
},
"comparables_count": 0,
"method": "active_listing_price",
"attribution": "Property is currently listed for sale at £425,000. Listed 2026-03-10.",
"comparable_properties": [],
"methodology": { "source": "active_listing", "listing_added_date": "2026-03-10", "listing_status": "For sale" },
"response_time_seconds": 0.05
}
Error codes (all returned as { "error": { "code": "…", "message": "…" } }):
invalid_uprn / invalid_type (400) ·
not_found / no_geopoint / no_comparables / insufficient_comparables (404 — fewer than 3 viable comps).
Listed Buildings
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. |
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/api/listed-buildings/?postcode=SW1A2AA&grade=I" \
-H "Authorization: Api-Key YOUR_API_KEY"
Stamp Duty Calculator
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). |
| country | enum | optional | Currently england (covers Northern Ireland — same rules). Scotland (LBTT) and Wales (LTT) coming soon. |
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/api/calculators/stamp-duty/?price=350000&buyer_type=first_time" \
-H "Authorization: Api-Key YOUR_API_KEY"
Mortgage Calculator
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_years | integer | required | Mortgage term in years (typically 25–35). |
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/api/calculators/mortgage/?price=350000&deposit=35000&rate=4.5&term_years=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
Free to startAll 38 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, comparables, valuations, 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
29M+ UK properties
Every address queryable by UPRN or postcode
REST API
JSON responses, OpenAPI docs, sandbox — first call in under 5 minutes
Free tier: 100 API calls/month across all endpoints, no credit card required. Paid plans from £29/month for production use. Compare plans →
Sources
Further reading
Authentication · Data Dictionary · Error codes · Coverage matrix