Skip to main content
Free UK property data API Start free →
·

API Reference

All endpoints return JSON. Authentication uses Authorization: Api-Key YOUR_KEY on every request.

Base URL: https://api.homedata.co.uk/api

Property — one endpoint, five behaviours

New 2026-05-30

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 + amenities + valuations + 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)
Migration: /address/retrieve/{uprn}/ and /properties/{uprn}/ (plural) keep working for 30 days with Deprecation + Sunset: 2026-06-29 response headers. Migrate by updating the URL — same UPRN, same response shape, same cost on the address-retrieve path.
GET

Property Data

/properties/{uprn}
Core Property

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.

Auth: API key required
cURL
curl https://api.homedata.co.uk/properties/10093609154 \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
import requests

response = requests.get(
    "https://api.homedata.co.uk/properties/10093609154",
    headers={"Authorization": "Api-Key YOUR_API_KEY"}
)
data = response.json()["data"]
print(data["address"]["full_address"])
JavaScript
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.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.
GET

EPC & Energy

/epc-checker/{uprn}/
Core Property

Energy Performance Certificate data. Returns current and potential energy efficiency scores (1–100), last EPC date, floor area, construction age band, and certificate ID.

Auth: API key required
cURL
curl https://api.homedata.co.uk/epc-checker/100023336956/ \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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_efficiency']}")
JavaScript
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_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"
}
GET

Environmental Risks

/risks/{risk_type}/?uprn={uprn}
Risk & Environment

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.

Auth: API key required

Available risk types

flood radon noise landfill coal_mining invasive_plants air_quality_today all
cURL
# 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"
Python
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']})")
JavaScript
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"
      }
    }
  ]
}
GET

Postcode Profile

/postcode-profile?postcode={postcode}
Aggregator

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.

Auth: API key required
Parameters: postcode (required) — full UK postcode
cURL
curl "https://api.homedata.co.uk/postcode-profile?postcode=SW1A%202AA" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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
JavaScript
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

{ "postcode": "SW1A 2AA", "outcode": "SW1A", "location": { "lat": 51.5014, "lng": -0.1419 } }
"deprivation": { imd_decile, imd_score, imd_rank, domains{...} }
"broadband": { avg_download_mbps, full_fibre_available_pct, ... }
"sold_prices": { median_sold_price, sale_count, period_start, period_end }
"schools": { total, radius_km, by_ofsted_rating }
"transport": { total, radius_m, by_type }
"census": { source, msoa_code, population_total, tenure{...}, age_bands{...} }
"environmental_risk": { flood{...}, radon{classification, description}, overall_risk }
"council_tax": { dominant_band, band_distribution, properties_with_band, yearly_charge_gbp, monthly_charge_gbp, fiscal_year_label, authority_name, gss_code }
"properties": { total, type_breakdown }
"hpi": { trend[{year, month, index}], current_index, source }
GET

Price Distributions

/price_distributions/{outcode}/
Market & Pricing

Price distribution data for an outcode. Shows percentile breakdowns (25th, 50th, 75th) and averages by property type, useful for market segmentation and pricing analysis.

Auth: API key required
Parameters: outcode (path) — UK outcode (e.g. E1, SW1A)
cURL
curl https://api.homedata.co.uk/price_distributions/E1/ \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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")
JavaScript
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
  }
}
GET

Comparables

Beta
/comparables/{uprn}/
Market & Pricing

Find comparable sold properties near a given UPRN. Uses PostGIS spatial queries to find nearby sales with similar characteristics.

Auth: API key required
cURL
curl https://api.homedata.co.uk/comparables/100023336956/ \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
import requests

response = requests.get(
    "https://api.homedata.co.uk/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)")
JavaScript
const response = await fetch(
  "https://api.homedata.co.uk/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
}
GET

Address by Postcode

/address/postcode/{postcode}/
Core Property

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).

Auth: API key required — Authorization: Api-Key YOUR_KEY
cURL
curl https://api.homedata.co.uk/address/postcode/SW1A2AA/ \
  -H "Authorization: Api-Key YOUR_KEY"
Python
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']})")
JavaScript
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.

GET

Address Search

/address/find/?q={query}
Core Property

Full-text address search powered by Elasticsearch (36M+ 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.

Auth: API key required — Authorization: Api-Key YOUR_KEY
Parameters: q (required) — search query (minimum 2 characters)
cURL
curl "https://api.homedata.co.uk/address/find/?q=10%20Downing%20Street" \
  -H "Authorization: Api-Key YOUR_KEY"
Python
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']}")
JavaScript
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",
      "address_line_1": "10 Downing Street",
      "address_line_2": null,
      "town": "London",
      "postcode": "SW1A 2AA"
    },
    {
      "uprn": 10004862792,
      "uprn_token": "gAAAAABm4xQ…",
      "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 }
}
GET

Address Retrieve

/property/{uprn}/{tier}/
Core Property

Enriched property data for a known UPRN. Use after Address Search or Address by Postcode to get property intelligence.

Auth: API key required
Tier: {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 calls
/base/ + property type, bedrooms, bathrooms, EPC, floor area, last sold price — 10 calls
cURL
# Address tier — 5 calls
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 calls
curl https://api.homedata.co.uk/property/100023336956/base/ \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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')}")
JavaScript
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"
}
GET

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?postcode={postcode}
Area Intelligence

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.

Auth: API key required — Authorization: Api-Key YOUR_KEY
Parameters: postcode (required) — UK postcode, spaces optional
Data source: Ofcom Connected Nations (annual)

Parameters

Parameter Type Required Description
postcode string required UK postcode. Spaces are stripped automatically. e.g. SW1A2AA or SW1A 2AA
cURL
curl "https://api.homedata.co.uk/broadband?postcode=SW1A2AA" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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']}%")
JavaScript
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
GET

Boundaries Autocomplete

No auth
/boundaries/autocomplete/?q={query}

Search for administrative boundaries (local authorities, wards, parishes) by name. Returns boundary metadata. Available on all plans including Free — no API key required.

Auth: None required (open endpoint)
cURL
curl "https://api.homedata.co.uk/boundaries/autocomplete/?q=islington"
Python
import requests

response = requests.get(
    "https://api.homedata.co.uk/boundaries/autocomplete/",
    params={"q": "islington"}
)
data = response.json()
for b in data["results"]:
    print(f"{b['name']} (level {b['admin_level']})")
JavaScript
const response = await fetch(
  "https://api.homedata.co.uk/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
    }
  ]
}
GET

Land Registry Titles

/property_lr_titles/{uprn}/
Planning & Land

Land Registry title boundary data for a property. Returns a GeoJSON Feature with the title polygon.

Auth: API key required
Response format: GeoJSON Feature
cURL
curl https://api.homedata.co.uk/property_lr_titles/100023336956/ \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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']}")
JavaScript
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"
  }
}
GET

Land Registry Sales

/lr_sales/?uprn={uprn}
Core Property

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).

Auth: API key required
Parameters: uprn (required), page (optional, pagination)
cURL
curl "https://api.homedata.co.uk/lr_sales/?uprn=10093609154" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
import requests

response = requests.get(
    "https://api.homedata.co.uk/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')}")
JavaScript
const response = await fetch(
  "https://api.homedata.co.uk/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/..."]
        }
      ]
    }
  ]
}
GET

Historic Listings

/property_listings/?uprn={uprn}
Market & Pricing

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 /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.

cURL
# All listings ever created for a UPRN
curl "https://api.homedata.co.uk/property_listings/?uprn=100090913175" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# Single listing by UUID
curl "https://api.homedata.co.uk/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"
    }
  ]
}
GET

Market Activity

/property_sale_events/?sale={sale_id}
Market Data

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.

Auth: API key required
Required: at least one filter (typically 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
AddedListing first appeared on market
Added by another agentRe-listed by a different agent
Added by new agentNew agent took over the listing
Added by another undetermined agentRe-listed by an agent we couldn't uniquely identify
Added date modified for old listingBackfill correction on an older listing's added date
ReducedPrice dropped
Price IncreasedPrice went up
Under offerBuyer's offer accepted (not yet legally committed)
Sold STCSold Subject to Contract (sale agreed)
Sold STCMSold STC with mortgage
CompletedSale completed (Land Registry confirmed)
WithdrawnTaken off market
Sale CancelledSale fell through after STC
Let agreedRental let agreed
cURL
# Full timeline for a sale, newest first (default)
curl "https://api.homedata.co.uk/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/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/property_sale_events/?sale=789&event_type=Reduced&date__gte=2026-01-01" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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/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/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}")
JavaScript
const headers = { "Authorization": "Api-Key YOUR_API_KEY" };

// Latest 5 events for sale 789
const resp = await fetch(
  "https://api.homedata.co.uk/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.

GET

Live Listings

/live-listings/search/?boundary_id={id}
Market & Pricing

Search currently active UK property listings. Filter by area or postcode, price, bedrooms, EPC band, floor area, reduction count, days-on-market and more. Returns paginated results with motivation signals — times_reduced, days_on_market, is_reduced — so you can spot warm leads before paying to reveal them.

£

Flat 5 calls per search. The cost is the same whether you return 1 listing or 200. Filter wide, narrow with precision, then unlock the specific addresses worth converting via /listing-address (£0.20 per first reveal).

💡

Two-step workflow: Use Boundaries Autocomplete to find a boundary_id for your area, then pass it here. Or pass an exact postcode for narrow lookups (no boundary lookup needed).

Auth: API key required
Pricing: 5 calls per request, flat

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
reduction_count_min int Only listings reduced at least N times (1, 2, 3+) — motivated-seller filter
postcode string Exact postcode filter, e.g. NR1 1TA. Comma-separated for multiple.
min_epc_band / max_epc_band string EPC range filter, A–G. e.g. max_epc_band=D returns D/E/F/G — renovation / solar prospects.
min_floor_area / max_floor_area int (m²) Floor area range filter (from EPC data)
has_garden / has_parking / has_solar_panels bool Property attribute filters (matched via UPRN)
garden_type / parking_type string More granular than the boolean — comma-separated types
min_dom int (days) Days on market — e.g. 90 returns listings added 90+ days ago (stale stock)
construction_age_band string Comma-separated, e.g. Pre-1919,1930-1949
sort string -added_date (default), added_date, -latest_price, latest_price
page / page_size int Pagination. Default page_size=30, max 200. Cost stays 5 calls regardless of page size.
cURL
# Step 1: Find the boundary ID for your location
curl "https://api.homedata.co.uk/boundaries/autocomplete/?q=Manchester"
# → {"results": [{"id": 14624, "name": "Manchester", ...}]}

# Step 2: Search listings within that boundary
curl "https://api.homedata.co.uk/live-listings/search/?boundary_id=14624&transaction_type=Sale&bedrooms=3" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
import requests

# Step 1: Find boundary ID
boundaries = requests.get(
    "https://api.homedata.co.uk/boundaries/autocomplete/",
    params={"q": "Manchester"}
).json()
boundary_id = boundaries["results"][0]["id"]

# Step 2: Search listings
response = requests.get(
    "https://api.homedata.co.uk/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']}")
JavaScript
// Step 1: Find boundary ID
const boundaries = await fetch(
  "https://api.homedata.co.uk/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/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": "..."
    }
  ]
}
GET

Council Tax Band

Live
/council_tax_band/{uprn}/
or by postcode: /council_tax_band/?postcode={postcode}&building_number={number}

Light shape (3 calls) — returns band, billing authority name and GSS code. For yearly + monthly charge in GBP and the full bundle, call /council_tax/{uprn}/ instead (5 calls). Coverage: England, Scotland and Wales, fiscal year 2026-27.

Core Property

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 calls). Data sourced from HMRC's Valuation Office Agency (VOA) and Finn's per-LA charge pipeline.

Auth: API key required
Lookup: by {uprn} in the path (recommended), or by ?postcode= + building_number/building_name when no UPRN.
Coverage: England, Scotland and Wales. Fiscal year 2026-27 charges live in the full endpoint.
cURL
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"
Python
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']}")
JavaScript
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"
}
GET

Council Tax

Live
/council_tax/{uprn}/

Full bundle (5 calls) — 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 calls).

Core Property

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).

Auth: API key required
Lookup: by {uprn} in the path (UPRN required — postcode mode lives on the lighter /council_tax_band/ endpoint).
Pricing: 5 calls per request
cURL
curl "https://api.homedata.co.uk/council_tax/10012963615/" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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")
JavaScript
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"
}
GET

Planning Applications

/planning/search/?postcode={postcode}
Planning & Land

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.

Auth: API key required

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
curl "https://api.homedata.co.uk/planning/search/?postcode=SW1A+2AA&radius_km=0.5&days=90" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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]}...")
JavaScript
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
JSON
{
  "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
    }
  ]
}
GET

Crime Data

/crime/nearby?postcode={postcode}
Risk & Environment

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.

Auth: API key required
Parameters: postcode (e.g. SW1A 2AA) or lat + lng (required), date (YYYY-MM, optional — defaults to latest), category (optional — filter by crime type)
⏱ Uncached requests call the Police UK API which can take 1–5s. Cached responses are near-instant. Data updates monthly.
cURL
curl "https://api.homedata.co.uk/crime/nearby?postcode=SW1A+2AA" \
  -H "Authorization: Api-Key YOUR_API_KEY"

# With date and category filter
curl "https://api.homedata.co.uk/crime/nearby?lat=51.5074&lng=-0.1278&date=2025-12&category=burglary" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
import requests

response = requests.get(
    "https://api.homedata.co.uk/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']}")
JavaScript
const response = await fetch(
  "https://api.homedata.co.uk/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.

GET

Solar Assessment

/solar-assessment/{uprn}/
Risk & Environment

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.

Auth: API key required
Parameters: uprn (path, required)
Confidence: High (OS footprint) / Medium (EPC floor area) / Low (bedroom estimate)
Phase 2: LIDAR roof pitch + satellite orientation analysis
cURL
curl https://api.homedata.co.uk/solar-assessment/10003469503/ \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
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)")
JavaScript
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. Phase 2 will add satellite-derived roof orientation for ±5% accuracy improvement.

GET

Amenities Nearby (OSM)

/amenities/  ·  /amenities/{group}/
Area Intelligence

Nearby points of interest from OpenStreetMap, sorted by distance. Call /amenities/ for all 11 groups in one response (5 calls), or a single group like /amenities/food/ (1 call). Groups: food, education, healthcare, financial, civic, worship, culture, convenience, green_spaces, transport, shops. For NHS-specific services (GPs, dentists, pharmacies, hospitals) use the dedicated Healthcare endpoint instead. Data cached in Loki — no live external API calls per request.

Billing: 5 calls for the all-groups response, 1 call for a single group. Pass either a uprn or a lat/lng pair, with an optional radius.

Auth: API key required

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
curl "https://api.homedata.co.uk/amenities/nearby?uprn=100021421083&radius_km=1&types=gp,dentist,pharmacy" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
import requests

response = requests.get(
    "https://api.homedata.co.uk/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")
JavaScript
const params = new URLSearchParams({
  uprn: '100021421083',
  radius_km: '1',
  types: 'gp,dentist,pharmacy',
});

const response = await fetch(
  `https://api.homedata.co.uk/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 Data and Schools Nearby for a complete local amenities profile.

GET

NHS Healthcare Nearby

/healthcare/  ·  /healthcare/{kind}/

Nearest NHS services, sorted by distance: GPs, dentists, pharmacies, hospitals. Call /healthcare/ for all four types in one response (3 calls), or a single type like /healthcare/gps/ (1 call). Sourced from NHS Digital / NHSBSA open datasets and cached in Loki — no live external API calls per request. Coverage: ~11,000+ GP practices, 12,000+ pharmacies, 1,000+ dental practices, 1,500+ hospital sites across England.

Billing: 3 calls for all types, 1 call per single type. Pass either a uprn or a lat/lng pair, with an optional radius. Auth: API key required.

curl "https://api.homedata.co.uk/healthcare/gps/?uprn=100023336956&radius=2" \
  -H "Authorization: Api-Key YOUR_KEY"
GET

Fuel Stations & EV Chargers

/fuel-stations/  ·  /fuel-stations/petrol/  ·  /fuel-stations/ev/

Nearest petrol stations and EV charge points, sorted by distance. Call /fuel-stations/ for both, or /fuel-stations/petrol/ / /fuel-stations/ev/ for one. Pass either a uprn or a lat/lng pair, with an optional radius.

Billing: 1 call per request. Auth: API key required.

curl "https://api.homedata.co.uk/fuel-stations/ev/?uprn=100023336956&radius=3" \
  -H "Authorization: Api-Key YOUR_KEY"
GET

Deprivation Index

/deprivation/?postcode={postcode}

Index of Multiple Deprivation (IMD) for any postcode — the overall rank/decile plus the underlying domains: income, employment, education, health, crime, barriers to housing & services, and living environment. Sourced from MHCLG IMD open data.

Billing: 1 call per request. Auth: API key required.

curl "https://api.homedata.co.uk/deprivation/?postcode=SW1A+2AA" \
  -H "Authorization: Api-Key YOUR_KEY"
GET

Schools Nearby

/schools/nearby
Area Intelligence

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.

Auth: API key required

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
curl "https://api.homedata.co.uk/schools/nearby?postcode=SW1A+2AA&radius=0.5&phase=Primary" \
  -H "Authorization: Api-Key YOUR_API_KEY"
Python
import requests

response = requests.get(
    "https://api.homedata.co.uk/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)")
JavaScript
const params = new URLSearchParams({
  postcode: 'SW1A 2AA',
  radius: '0.5',
  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_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 Data for a complete area profile.

GET

Flood Risk

/flood-risk/?uprn={uprn}

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"
}
GET

Price Growth

/price-growth/{outcode}/

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"
}
GET

Demographics

/demographics/?postcode={postcode}

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"]
}
GET

Valuations — Sale + Rent AVM

/valuations/estimate/?uprn={uprn}&type=sale|rent

Sale price estimate or monthly rent estimate for any UK property. The engine assembles evidence from three sources in parallel — sold/let comparables, active listings, and the property's local outcode price index — then produces an outlier-robust estimate:

  1. Comparable search — sold (sale) or let-agreed (rent) records within 5 miles, beds ±1, matching and adjacent property types, scored 0–1 on distance, beds, baths, floor area, type, and recency.
  2. Time adjustment — every sold price is brought to today's money using the outcode's monthly median index, so a comp from 14 months ago in a moving market doesn't skew the answer. Each comparable carries its time_adjustment_pct.
  3. Weighted-median estimate — score-weighted median price-per-sqft × the subject's floor area (method: "weighted_median_ppsf"). Active listings enter at a 3% asking-price discount; sold comparables carry full weight. Falls back to a weighted-median comparable price when floor area is unavailable.

Every response includes confidence_score (0–100, from evidence depth and agreement), dispersion_pct (how tightly the comparables agree — the lower, the better), a banded confidence (low / medium / high), and the full comparable evidence so you can audit the number. Rent estimates additionally return rent_pcm_gbp and rent_pw_gbp.

Billing: 25 calls with the comparables evidence pack bundled (default), or 10 calls for the estimate alone with ?include_comps=false. The estimate is computed from the full evidence set either way — the cheaper tier just omits the comp-level detail from the response.

Parameters

Name Type Required Validation Example
uprn int yes 8–12 digits 100023336956
type string optional sale (default) or rent rent
bedrooms int optional positive integer — falls back to the property record when omitted 3
property_type string optional Bungalow, Detached, Flat, Maisonette, Semi-Detached, Terraced — falls back to the property record when omitted Terraced
include_comps bool optional true (default) bundles the full comparables evidence pack — 25 calls. false returns the estimate alone — 10 calls. The estimate is identical either way false
View example response (sale)
{
  "uprn": 100023336956,
  "type": "sale",
  "estimate_gbp": 354000,
  "range_low_gbp": 336000,
  "range_high_gbp": 372000,
  "confidence": "high",
  "confidence_score": 84,
  "dispersion_pct": 11.2,
  "method": "weighted_median_ppsf",
  "active_listings": [ /* top 6 scored listings, each with score + distance_miles */ ],
  "sold_comparables": [
    {
      "uprn": 100022677605,
      "address": "5 EXAMPLE ROAD",
      "postcode": "SW19 1AA",
      "bedrooms": 3,
      "property_type": "Terraced",
      "epc_floor_area": 95,
      "sold_price": 410000,
      "sold_date": "2025-03-15",
      "adjusted_price": 422300,
      "time_adjustment_pct": 3.0,
      "distance_miles": 0.05,
      "price_per_sqft": 401,
      "score": 0.97,
      "tenure": "Freehold",
      "source": "sold"
    }
  ],
  "area_stats": {
    "average_price": 361250,
    "median_price": 355000,
    "median_price_per_sqft": 392,
    "sample_size": 24
  },
  "subject": { "uprn": 100023336956, "property_type": "Terraced", "bedrooms": 3, "epc_floor_area": 90 },
  "response_time_seconds": 0.61
}
View example response (rent)
{
  "uprn": 100023336956,
  "type": "rent",
  "estimate_gbp": 1875,
  "rent_pcm_gbp": 1875,
  "rent_pw_gbp": 433,
  "range_low_gbp": 1775,
  "range_high_gbp": 1975,
  "confidence": "medium",
  "confidence_score": 58,
  "dispersion_pct": 14.6,
  "method": "weighted_median_ppsf",
  "active_listings": [ /* current rental listings nearby */ ],
  "sold_comparables": [ /* let-agreed records, source: "let_agreed" */ ],
  "response_time_seconds": 0.58
}

Error codes (all returned as { "error": { "code": "…", "message": "…" } }): invalid_uprn / invalid_type / invalid_bedrooms / invalid_property_type (400 — validated before billing, no charge) · not_found (404) · valuation_failed (400 — property has no bedroom or type data and none was supplied).

GET

Listed Buildings

/listed-buildings/?postcode={postcode}
Heritage

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.

Auth: API key required — Authorization: Api-Key YOUR_KEY
Data source: Historic England — National Heritage List for England

Parameters

ParameterTypeRequiredDescription
postcodestringrequiredUK postcode. Spaces optional.
radius_kmnumberoptionalSearch radius in km. Default 1, max 5.
gradeenumoptionalFilter 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
curl "https://api.homedata.co.uk/listed-buildings/?postcode=SW1A2AA&grade=I" \
  -H "Authorization: Api-Key YOUR_API_KEY"
GET

Stamp Duty Calculator

/calculators/stamp-duty/?price={price}&buyer_type={type}
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).

Auth: API key required.
Thresholds from: 1 April 2025 (current SDLT rates)

Parameters

ParameterTypeRequiredDescription
priceinteger (£)requiredProperty purchase price in GBP. Positive integer.
buyer_typeenumrequiredstandard · first_time · additional (second home / BTL).
countryenumoptionalCurrently 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
curl "https://api.homedata.co.uk/calculators/stamp-duty/?price=350000&buyer_type=first_time" \
  -H "Authorization: Api-Key YOUR_API_KEY"
GET

Mortgage Calculator

/calculators/mortgage/?price={price}&deposit={deposit}&rate={rate}&term_years={years}
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.

Auth: API key required.

Parameters

ParameterTypeRequiredDescription
priceinteger (£)requiredProperty purchase price in GBP.
depositinteger (£)requiredUp-front deposit, GBP. Non-negative.
ratenumber (%)requiredAnnual interest rate, percent (e.g. 4.5).
term_yearsintegerrequiredMortgage 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
curl "https://api.homedata.co.uk/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 start
Homedata API Scientific, granular measurements

All 50+ 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 →