Skip to content
UK Property Looker · Data API

API documentation

The complete v1 reference: every endpoint, its parameters, and a real request and response for each one. Generated from the same registry that serves the API, so it cannot fall behind.

https://ukpropertylooker.com/api/v1Get an API keyOpenAPI spec

Base URL

Every endpoint in this reference is relative to the base URL below. Paths in the endpoint sections are written without it, so /api/v1/usage is the whole path you request.

https://ukpropertylooker.com/api/v1

The API is HTTPS only and returns JSON on every route, including errors. A machine-readable OpenAPI 3.1 description of everything below is served at /api/v1/openapi.json, so you can generate a client rather than write one.

Authentication

Every request needs an API key, sent as a bearer token. Create one in the developer console, or create a free account first if you do not have one. Keys start with upl_live_ and are shown once, at creation: we store only a hash, so a lost key is replaced rather than recovered.

Your first request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/postcodes/AL1%202AY"
  • Send the key in the Authorization header only. There is no query-string alternative, deliberately: keys in URLs end up in access logs, browser history and referrer headers.
  • Keys belong on a server you control, never in a browser bundle or a mobile app, where anyone can read them out.
  • You can hold up to 10 active keys at once, so give each environment its own and revoke one without touching the rest. Revoking takes effect immediately.
  • Quota is counted per account, not per key, so splitting traffic across keys does not change what you can use.

Responses

A successful response is always an object with a data key. Nothing is ever returned at the top level, so adding a field later can never collide with your parsing.

Single resource
{
  "data": {
    "slug": "7-ashwood-mews-st-albans-al1-2ay",
    "postcode": "AL1 2AY"
  }
}

List endpoints put the array in data and add a meta object alongside it, carrying the count and whatever else describes the query, such as the search radius. An empty result is an empty array with a count of zero, not a 404.

List
{
  "data": [
    { "slug": "7-ashwood-mews-st-albans-al1-2ay" },
    { "slug": "18-st-julians-road-st-albans-al1-2az" }
  ],
  "meta": { "count": 2 }
}

Responses are keyed to your API key, so they are sent with Cache-Control: private, no-store and must not be held in a shared cache. Caching in your own application, against your own users, is fine and encouraged.

Errors

Errors use one envelope on every route and every status. Branch on error.code, which is stable, rather than on the message, which is written for a human and may be reworded. Some errors add a details object with machine-readable specifics.

Error body
{
  "error": {
    "code": "not_found",
    "message": "No property with that slug.",
    "status": 404
  }
}
CodeStatusWhat it means
unauthorized401No Authorization header, or it was not a Bearer token. Send the key as Authorization: Bearer upl_live_...
invalid_api_key401The key is not one of ours, or it has been revoked. Create a replacement in the console.
bad_request400A parameter is missing or malformed, for example a postcode that is not a valid UK postcode. The message names the problem.
not_found404The identifier parsed fine but we hold no published record for it. Unpublished properties are treated as missing.
rate_limited429You went over your plan's per-minute burst limit. Retry-After gives the number of seconds to wait.
quota_exceeded429You have spent this calendar month's requests. details.resetsAt gives the reset time and details.upgradeUrl links to the console.
internal_error500Something failed on our side. Safe to retry; if it persists, get in touch.

A 400 or a 404 from an endpoint counts towards your monthly quota, since the lookup ran. Requests we turn away before they reach an endpoint do not: a missing or revoked key, a burst-limit 429 and a quota 429 are all free.

Rate limits and quotas

Two limits apply, both taken from your plan. The burst limit is per rolling 60 seconds and is counted per key. The quota is per calendar month and is counted per account, across all of your keys. Quotas reset at 00:00 UTC on the 1st of each month.

PlanPriceRequests / monthBurst / minute
Free£0/month10010
Starter£19/month2,00030
Growth£79/month20,000120
Scale£299/month100,000300
Enterprise£999/month500,0001,000

Every authenticated response carries its own limit headers, so you never have to track usage yourself.

HeaderMeaning
X-RateLimit-LimitRequests your plan allows per rolling 60 seconds.
X-RateLimit-RemainingRequests left in the current 60-second window.
X-Quota-LimitRequests your plan allows this calendar month.
X-Quota-UsedRequests used this month, across every key on the account, including this one.
X-Quota-ResetISO 8601 timestamp when the monthly quota resets, always 00:00 UTC on the 1st.
Retry-AfterSeconds to wait before retrying. Sent with a burst-limit 429 only.

Going over the burst limit returns 429 with rate_limited and a Retry-After header: sleep for that many seconds and carry on. Spending the monthly quota returns 429 with quota_exceeded and no Retry-After, because waiting is not the fix; the details object carries the reset time and a link to upgrade. Plans and prices are on the API overview.

Conventions

These hold on every endpoint, so the individual sections below do not repeat them.

camelCase fields
Every property in every payload is camelCase, including nested objects. Identifiers keep their source spelling only where that spelling is the value, such as an EPC certificate number.
ISO 8601 dates
Dates without a time are YYYY-MM-DD strings. Timestamps are full ISO 8601 in UTC, for example 2026-09-01T00:00:00.000Z.
Money in whole pounds
Prices are integers in GBP, never strings and never pence. A £452,500 sale is 452500.
Distances in metres
Every distance is an integer number of metres, so a school 1.2km away comes back as 1200.
Coordinates as numbers
Positions are { latitude, longitude } decimal degrees, WGS 84, the same reference GPS and web maps use.
Explicit nulls
A value we do not hold is null. Keys are never dropped from a response, so you can rely on the shape without guarding for undefined.

Versioning

The version is in the path. Everything documented here is v1, served under /api/v1, currently 1.0.0. Changes inside v1 are additive only: we may add an endpoint, add a field to a response or add an optional query parameter, and none of those will break a client that ignores what it does not recognise.

  • We will not remove or rename a field, change its type, or change the meaning of an existing value within v1.
  • Parse defensively: treat unknown fields as ignorable rather than as an error, and do not depend on the ordering of object keys.
  • Anything breaking would ship as v2 on its own path, with v1 kept running while you move.

The OpenAPI description at /api/v1/openapi.json is generated from the same registry as this page, so it is never behind what you are reading.

Properties

Everything we hold about a single home, keyed by its slug: attributes, sale history, EPC certificates and planning applications.

Everything we hold about one home

GET/api/v1/properties/{slug}

The full record for a single property: its postal address, where it sits, the attributes we hold, our valuation and sale summary, the environmental indicators for its postcode, and the features matched to it. features reports three states, and they are not interchangeable. true means we hold a positive signal for that feature, false an explicit negative, and null that we hold nothing either way. Treat null as unknown, never as absent. links points at this property's sub-resources and at the postcode and district it belongs to, so you can walk the API without building paths by hand.

  • latestValuation is our automated estimate in whole pounds, not an asking price and not a sale. latestSalePrice and latestSaleDate come from HM Land Registry.
  • latestFloorArea is square metres and latestEnergyRating the band, both taken from the most recent EPC. Both are denormalised summaries: the certificates themselves are on the /epc sub-resource.
  • location coordinates are the postcode centroid, not the building, and so are floodRisk and the two road-noise figures. Road noise is decibels from DEFRA's strategic noise mapping, daytime and night-time, and is null where the mapping does not reach.
  • floodRisk is the Environment Agency's Risk of Flooding from Rivers and Sea band. It says nothing about surface-water or groundwater flooding.
  • A property withdrawn at the owner's request answers 404, the same as a slug we have never held.

Parameters

NameInTypeRequiredDescriptionExample
slugpathstringYesThe property's canonical identifier, from GET /search/addresses or a previous property response.7-ashwood-mews-st-albans-al1-2ay
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/properties/7-ashwood-mews-st-albans-al1-2ay"
Example response
{
  "data": {
    "slug": "7-ashwood-mews-st-albans-al1-2ay",
    "displayName": "7 Ashwood Mews, St Albans, AL1 2AY",
    "address": {
      "buildingName": null,
      "subBuildingName": null,
      "buildingNumber": "7",
      "thoroughfare": null,
      "street": "Ashwood Mews",
      "dependentLocality": null,
      "doubleDependentLocality": null,
      "postTown": "St Albans",
      "postcode": "AL1 2AY"
    },
    "location": {
      "latitude": 51.74463,
      "longitude": -0.341275,
      "outwardCode": "AL1",
      "districtSlug": "al-1",
      "localityName": null
    },
    "attributes": {
      "type": null,
      "propertySubType": "House",
      "bedrooms": 2,
      "bathrooms": null,
      "councilTaxBand": "E",
      "latestFloorArea": null,
      "latestEnergyRating": null
    },
    "summary": {
      "latestValuation": 663000,
      "latestSalePrice": null,
      "latestSaleDate": null,
      "totalTransactions": 4,
      "totalEpc": 2
    },
    "environment": {
      "floodRisk": "none",
      "roadNoiseDayDb": 50.56,
      "roadNoiseNightDb": 42.7
    },
    "features": {
      "hasCloakroom": true,
      "hasDiningRoom": true,
      "hasDriveway": true,
      "hasPrivateGarden": true,
      "hasGarage": null,
      "isRefurbished": true,
      "isExtended": null,
      "gardenPosition": "rear",
      "parkingKind": null
    },
    "links": {
      "transactions": "/api/v1/properties/7-ashwood-mews-st-albans-al1-2ay/transactions",
      "epc": "/api/v1/properties/7-ashwood-mews-st-albans-al1-2ay/epc",
      "planning": "/api/v1/properties/7-ashwood-mews-st-albans-al1-2ay/planning",
      "postcode": "/api/v1/postcodes/AL1%202AY",
      "area": "/api/v1/areas/AL1"
    }
  }
}

Land Registry sale history for one home

GET/api/v1/properties/{slug}/transactions

Every sale recorded against the property in HM Land Registry's Price Paid Data, newest first. This is the complete Price Paid set rather than a sample, so an empty list means the home has not changed hands on the open market since 1995, not that we are missing the data.

  • England and Wales only. Scotland (Registers of Scotland) and Northern Ireland are not part of Price Paid Data.
  • price is the sale price in whole pounds and date the date of the deed, in UK local time.
  • propertyType is Land Registry's description of the transaction, not the built form of the house; dwellingType is the built form (Detached, Semi-detached, Terraced, Flat/maisonette or Other). ppdCategory is A for a standard full-market sale and B for the additional category (repossessions, buy-to-lets and transfers not at full market value), which is the field to filter on when you want comparable sales.
  • transactionId is Land Registry's own unique identifier for the sale, stable across their monthly updates.

Parameters

NameInTypeRequiredDescriptionExample
slugpathstringYesThe property's canonical identifier, from GET /search/addresses or a previous property response.7-ashwood-mews-st-albans-al1-2ay
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/properties/7-ashwood-mews-st-albans-al1-2ay/transactions"
Example response
{
  "data": [
    {
      "transactionId": "B32EBB13-8835-3C99-E053-6C04A8C09CA1",
      "date": "2020-09-02",
      "price": 600000,
      "propertyType": "Standard price paid transaction",
      "dwellingType": "Semi-detached",
      "newBuild": false,
      "estateType": "Freehold",
      "ppdCategory": "A"
    },
    {
      "transactionId": "9D848449-5DC3-4157-A9DC-F5EFFD5D6054",
      "date": "2010-03-25",
      "price": 332000,
      "propertyType": "Standard price paid transaction",
      "dwellingType": "Semi-detached",
      "newBuild": false,
      "estateType": "Freehold",
      "ppdCategory": "A"
    },
    {
      "transactionId": "F64B9752-2063-4082-A9D4-ED73F3A5FEDD",
      "date": "2004-12-13",
      "price": 305000,
      "propertyType": "Standard price paid transaction",
      "dwellingType": "Semi-detached",
      "newBuild": false,
      "estateType": "Freehold",
      "ppdCategory": "A"
    }
  ],
  "meta": {
    "count": 4
  }
}

Energy Performance Certificates for one home

GET/api/v1/properties/{slug}/epc

Every EPC lodged against the property, newest lodgement first, from the MHCLG register. A home usually has more than one: certificates are lodged on sale and on letting, and comparing them shows what has changed. The register's flat row is regrouped here so each element carries its description next to the band the assessor gave it, which is how the two are meant to be read. fabric covers walls, roof, windows, floor and lighting; heating covers the main system and hot water, with the fuel it burns.

  • England and Wales only. Scotland and Northern Ireland run their own registers, which this API does not carry.
  • Units: totalFloorArea square metres, costs estimated pounds per year, co2Emissions* tonnes per year, energyConsumption* kWh per square metre per year. currentEfficiency and potentialEfficiency are the 1 to 100 SAP scores behind the A to G band.
  • potential figures are what the assessor modelled after the improvements they recommended, not a forecast of the home as it stands.
  • The register replaced lmkKey with certificateNumber as its identifier, so older certificates carry only the key. Both are published; prefer whichever is present.
  • Free-text bands come from the assessor's software and are not always clean: values such as "NO DATA!" and "N/A" appear in the source and are passed through rather than silently turned into null.

Parameters

NameInTypeRequiredDescriptionExample
slugpathstringYesThe property's canonical identifier, from GET /search/addresses or a previous property response.7-ashwood-mews-st-albans-al1-2ay
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/properties/7-ashwood-mews-st-albans-al1-2ay/epc"
Example response
{
  "data": [
    {
      "certificateNumber": null,
      "lmkKey": "182051449262018102315005603478298",
      "lodgementDate": "2018-10-23",
      "inspectionDate": "2018-10-23",
      "localAuthority": "E07000240",
      "constituency": "E14000960",
      "rating": {
        "current": "E",
        "potential": "C",
        "currentEfficiency": 40,
        "potentialEfficiency": 78
      },
      "building": {
        "propertyType": "House",
        "builtForm": "Semi-Detached",
        "constructionAgeBand": "England and Wales: before 1900",
        "totalFloorArea": 72,
        "numberHabitableRooms": 3,
        "numberHeatedRooms": 3,
        "tenure": "rental (private)",
        "transactionType": "rental (private)"
      },
      "fabric": {
        "walls": {
          "description": "Solid brick, as built, no insulation (assumed)",
          "energyEfficiency": "Poor"
        },
        "roof": {
          "description": "Pitched, 200 mm loft insulation",
          "energyEfficiency": "Good"
        },
        "windows": {
          "description": "Fully double glazed",
          "energyEfficiency": "Average"
        },
        "floor": {
          "description": "Solid, no insulation (assumed)",
          "energyEfficiency": "NO DATA!"
        },
        "lighting": {
          "description": "Low energy lighting in 75% of fixed outlets",
          "energyEfficiency": "Very Good"
        }
      },
      "heating": {
        "mainFuel": "mains gas (not community)",
        "mainsGasFlag": "Y",
        "main": {
          "description": "Boiler and radiators, mains gas",
          "energyEfficiency": "Good"
        },
        "hotWater": {
          "description": "From main system, no cylinder thermostat",
          "energyEfficiency": "Average"
        }
      },
      "emissions": {
        "co2EmissionsCurrent": 5.8,
        "co2EmissionsPotential": 1.8,
        "energyConsumptionCurrent": 463,
        "energyConsumptionPotential": 144
      },
      "costs": {
        "heatingCurrent": 947,
        "heatingPotential": 569,
        "hotWaterCurrent": 263,
        "hotWaterPotential": 69,
        "lightingCurrent": 65,
        "lightingPotential": 52
      }
    }
  ],
  "meta": {
    "count": 2
  }
}

Planning applications matched to one home

GET/api/v1/properties/{slug}/planning

Planning applications we have matched to this address, newest decision first, collected from local planning authority portals. description is the council's own wording in full and is never truncated: it is the only field that says what was actually proposed. classification is our model's reading of that description, one flag per kind of work. Use it to filter, and read the description before you act on it.

  • Coverage varies by council: some publish decades of decisions, others only recent years, so an empty list is not proof that nothing was ever applied for.
  • reference is the council's own application number and is unique only within that council. decision and status are their raw wording, which differs between authorities.
  • matchConfidence runs from 0 to 1 and is how sure we are that the application belongs to this address rather than a neighbour. 1 is an exact address match.
  • extension.storeys and extension.position are only meaningful when the scheme is an extension; extension.summary reads them back as a phrase such as "single-storey rear extension".
  • startDate is when the council registered the application and decidedDate when they determined it. Either can be null on an application still in progress.

Parameters

NameInTypeRequiredDescriptionExample
slugpathstringYesThe property's canonical identifier, from GET /search/addresses or a previous property response.7-ashwood-mews-st-albans-al1-2ay
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/properties/7-ashwood-mews-st-albans-al1-2ay/planning"
Example response
{
  "data": [
    {
      "reference": "5/2021/2507",
      "description": "Alterations to conservatory and replacement conservatory roof with roof lights",
      "decision": "DC3 Conditional Permission",
      "decidedDate": "2021-12-20",
      "startDate": "2021-09-01",
      "appType": "Full",
      "status": "Approved",
      "link": "https://www.planit.org.uk/planapplic/StAlbans/5/2021/2507/",
      "developmentType": null,
      "extension": {
        "storeys": null,
        "position": null,
        "summary": null
      },
      "classification": {
        "isExtension": true,
        "isLoftConversion": null,
        "isGarageConversion": null,
        "isBasementExcavation": null,
        "isPorch": null,
        "isConservatory": true,
        "isAnnex": null,
        "hasSolarPanels": null,
        "hasNewWindows": null,
        "hasDemolition": null,
        "isSubdivision": null,
        "isHmoConversion": null,
        "isListedBuilding": null,
        "isConservationArea": null,
        "isRetrospective": null,
        "isTreeWorks": null,
        "changeOfUseToResidential": null
      },
      "matchConfidence": 1
    }
  ],
  "meta": {
    "count": 1
  }
}

Postcodes

A full postcode and what surrounds it: the properties in it, nearby schools and transport, flood and noise indicators.

Look up a postcode

GET/api/v1/postcodes/{postcode}

Where a postcode sits, which district, post town and locality it belongs to, the environmental indicators we hold against it, and how many published properties we hold in it. The links are paths relative to the API base, ready to append to https://ukpropertylooker.com/api/v1.

  • floodRisk is the Environment Agency's Risk of Flooding from Rivers and Sea band (none, very low, low, medium, high). It says nothing about surface water or groundwater flooding, which are assessed separately.
  • roadNoise is modelled road traffic noise in A-weighted decibels: dayDb is the 16-hour daytime average and nightDb the 8-hour night average. Both are null outside the mapped areas.
  • propertyCount counts published properties only, so a home taken down at its owner's request drops out of it.
  • Coordinates are the postcode centroid, not any individual building.

Parameters

NameInTypeRequiredDescriptionExample
postcodepathstringYesA full UK postcode in any spelling. Spaces, hyphens and case are ignored, so AL1 2AY, al1-2ay and AL12AY all resolve to the same postcode.AL1 2AY
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/postcodes/AL1%202AY"
Example response
{
  "data": {
    "postcode": "AL1 2AY",
    "outward": "AL1",
    "inward": "2AY",
    "districtSlug": "al-1",
    "latitude": 51.74463,
    "longitude": -0.341275,
    "postTown": {
      "slug": "st-albans",
      "name": "St Albans"
    },
    "localityName": null,
    "floodRisk": "none",
    "roadNoise": {
      "dayDb": 50.56,
      "nightDb": 42.7
    },
    "propertyCount": 8,
    "links": {
      "properties": "/postcodes/AL1%202AY/properties",
      "schools": "/postcodes/AL1%202AY/schools",
      "transport": "/postcodes/AL1%202AY/transport",
      "area": "/areas/AL1"
    }
  }
}

Properties in a postcode

GET/api/v1/postcodes/{postcode}/properties

Every published property we hold in a postcode, in address order, with the slug to call /properties/{slug} with for the full record. This is the usual way to turn a postcode into property identifiers when you do not have an exact address to search for.

  • Unpublished properties are never returned, on this or any other endpoint.
  • Ordering is by building number, then building name, then sub-building name, then slug. Building numbers are text, so 10 sorts before 2.
  • The latest... fields are summaries denormalised onto the property row. They are null wherever the summary has not been computed for that property, which is common. Use /properties/{slug}/transactions and /properties/{slug}/epc for the authoritative sale and certificate history.
  • Prices are whole pounds and floor areas are square metres.

Parameters

NameInTypeRequiredDescriptionExample
postcodepathstringYesA full UK postcode in any spelling. Spaces, hyphens and case are ignored, so AL1 2AY, al1-2ay and AL12AY all resolve to the same postcode.AL1 2AY
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/postcodes/AL1%202AY/properties"
Example response
{
  "data": [
    {
      "slug": "1-ashwood-mews-st-albans-al1-2ay",
      "displayName": "1 Ashwood Mews",
      "buildingNumber": "1",
      "buildingName": null,
      "subBuildingName": null,
      "thoroughfare": null,
      "street": "Ashwood Mews",
      "type": null,
      "bedrooms": 4,
      "bathrooms": null,
      "latestValuation": 717000,
      "latestSalePrice": null,
      "latestSaleDate": null,
      "latestEnergyRating": null,
      "latestFloorArea": null
    },
    {
      "slug": "2-ashwood-mews-st-albans-al1-2ay",
      "displayName": "2 Ashwood Mews",
      "buildingNumber": "2",
      "buildingName": null,
      "subBuildingName": null,
      "thoroughfare": null,
      "street": "Ashwood Mews",
      "type": null,
      "bedrooms": 4,
      "bathrooms": null,
      "latestValuation": 650000,
      "latestSalePrice": null,
      "latestSaleDate": null,
      "latestEnergyRating": null,
      "latestFloorArea": null
    },
    {
      "slug": "3-ashwood-mews-st-albans-al1-2ay",
      "displayName": "3 Ashwood Mews",
      "buildingNumber": "3",
      "buildingName": null,
      "subBuildingName": null,
      "thoroughfare": null,
      "street": "Ashwood Mews",
      "type": null,
      "bedrooms": 4,
      "bathrooms": null,
      "latestValuation": 801000,
      "latestSalePrice": null,
      "latestSaleDate": null,
      "latestEnergyRating": null,
      "latestFloorArea": null
    }
  ],
  "meta": {
    "postcode": "AL1 2AY",
    "count": 8
  }
}

Schools near a postcode

GET/api/v1/postcodes/{postcode}/schools

Open schools within the search radius of the postcode centroid, nearest first, from the Department for Education's Get Information about Schools register. urn is the department's own identifier, so results join cleanly to anything else built on GIAS.

  • Distances are straight-line metres from the postcode centroid to the school's recorded location, not walking or driving distance.
  • Closed schools are excluded. Independent schools are included and carry no Ofsted rating.
  • ofstedRating and lastInspectionDate come from the register's inspection columns and are sparse; treat null as unknown, not as unrated.
  • phase is normalised to Primary, Secondary, All-through, 16 plus or Other.
  • England only. Scotland, Wales and Northern Ireland run separate registers we do not hold.
  • A postcode we hold no coordinates for answers 404 rather than an empty list, so you can tell the two apart.

Parameters

NameInTypeRequiredDescriptionExample
postcodepathstringYesA full UK postcode in any spelling. Spaces, hyphens and case are ignored, so AL1 2AY, al1-2ay and AL12AY all resolve to the same postcode.AL1 2AY
radiusqueryintegerNoSearch radius in metres from the postcode centroid. Values outside the supported range are clamped to it.Defaults to 3000.Minimum 250. Maximum 5000.1500
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/postcodes/AL1%202AY/schools?radius=1500"
Example response
{
  "data": [
    {
      "urn": 117449,
      "name": "The Abbey Church of England Voluntary Aided Primary School, St Albans",
      "phase": "Primary",
      "type": "Voluntary aided school",
      "gender": "Mixed",
      "religiousCharacter": "Church of England",
      "ofstedRating": null,
      "lastInspectionDate": null,
      "ageRange": {
        "low": 4,
        "high": 11
      },
      "numberOfPupils": 177,
      "postcode": "AL1 1DQ",
      "website": "http://www.abbey.herts.sch.uk",
      "latitude": 51.747635,
      "longitude": -0.3424914,
      "distanceMeters": 344
    },
    {
      "urn": 117140,
      "name": "St Peter's School",
      "phase": "Primary",
      "type": "Community school",
      "gender": "Mixed",
      "religiousCharacter": "Does not apply",
      "ofstedRating": null,
      "lastInspectionDate": null,
      "ageRange": {
        "low": 3,
        "high": 11
      },
      "numberOfPupils": 365,
      "postcode": "AL1 1HL",
      "website": "www.stpeters.herts.sch.uk/",
      "latitude": 51.7464068,
      "longitude": -0.3351196,
      "distanceMeters": 468
    },
    {
      "urn": 117638,
      "name": "St Columba's College",
      "phase": "Other",
      "type": "Other independent school",
      "gender": "Mixed",
      "religiousCharacter": "Roman Catholic",
      "ofstedRating": null,
      "lastInspectionDate": null,
      "ageRange": {
        "low": 4,
        "high": 18
      },
      "numberOfPupils": 830,
      "postcode": "AL3 4AW",
      "website": "stcolumbascollege.org",
      "latitude": 51.7433958,
      "longitude": -0.3505118,
      "distanceMeters": 651
    }
  ],
  "meta": {
    "postcode": "AL1 2AY",
    "radiusMeters": 1500,
    "count": 15
  }
}

Transport stops near a postcode

GET/api/v1/postcodes/{postcode}/transport

Public transport stops within the search radius of the postcode centroid, nearest first, from NaPTAN. atcoCode is the national stop identifier, stopType NaPTAN's own code (BCT for a bus stop, RLY for a rail station) and stationType our grouping of it.

  • Distances are straight-line metres from the postcode centroid.
  • At most 30 stops are returned, nearest first. type is applied before that cap, so asking for railway_station in a bus-stop-dense area still finds the station.
  • Stops sharing a name, street and locality are deduplicated, so a pair of bus stops facing each other appears once.
  • Only stops NaPTAN marks active are included.

Parameters

NameInTypeRequiredDescriptionExample
postcodepathstringYesA full UK postcode in any spelling. Spaces, hyphens and case are ignored, so AL1 2AY, al1-2ay and AL12AY all resolve to the same postcode.AL1 2AY
radiusqueryintegerNoSearch radius in metres from the postcode centroid. Values outside the supported range are clamped to it.Defaults to 3000.Minimum 250. Maximum 5000.1500
typequerystringone of railway_station, subway_entrance, tram_stop, bus_station, bus_stop, ferry_terminal, airportNoReturn only stops of this kind. Omit for every kind. An unrecognised value is refused rather than returning nothing.railway_station
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/postcodes/AL1%202AY/transport?radius=1500"
Example response
{
  "data": [
    {
      "atcoCode": "2100STALBNA0",
      "name": "St Albans Abbey Rail Station",
      "stationType": "railway_station",
      "stopType": "RSE",
      "street": "Entrance",
      "indicator": "entrance",
      "localityName": "St Albans",
      "town": "St Albans",
      "latitude": 51.7446847,
      "longitude": -0.3424255,
      "distanceMeters": 79
    },
    {
      "atcoCode": "9100STALBNA",
      "name": "St Albans Abbey Rail Station",
      "stationType": "railway_station",
      "stopType": "RLY",
      "street": "-",
      "indicator": null,
      "localityName": "St Albans",
      "town": null,
      "latitude": 51.7447334,
      "longitude": -0.3425686,
      "distanceMeters": 90
    },
    {
      "atcoCode": "210021503323",
      "name": "Griffiths Way",
      "stationType": "bus_stop",
      "stopType": "BCT",
      "street": "Griffiths Way",
      "indicator": "SE-bound",
      "localityName": "Cottonmill",
      "town": "St Albans",
      "latitude": 51.7438146,
      "longitude": -0.3432106,
      "distanceMeters": 161
    }
  ],
  "meta": {
    "postcode": "AL1 2AY",
    "radiusMeters": 1500,
    "count": 30
  }
}

Areas

A postcode district (the outward code, such as SW1A): house-price statistics by year, crime and air quality.

Look up a postcode district

GET/api/v1/areas/{outward}

A postcode district in one call: where it is, how many properties we hold in it, the post towns and localities it covers, and its headline air quality, crime and house-price figures. Every block that depends on a source we do not hold everywhere is explicitly null rather than absent.

  • Coordinates are the mean of the postcodes in the district, so they land near its centre rather than on any landmark.
  • population is the resident count we hold for the district, and is the denominator behind crimeRate.ratePer1000.
  • airQuality figures are averages over a fixed observation window, not live readings. ozone, nitrogenDioxide, sulphurDioxide and carbonMonoxide are concentrations in micrograms per cubic metre; europeanAqi is the European Air Quality Index, on which lower is cleaner. rating is a 1 to 5 summary band computed alongside those averages.
  • crimeRate is recorded crimes per 1,000 residents over the rolling window ending at windowEnd, with months giving the window length. It is null for districts whose force we hold no Police.uk coverage for.
  • housePrices summarises the most recent year in /areas/{outward}/house-prices. The newest year is usually partial: the Price Paid Data lands in monthly batches, so its saleCount keeps rising for months.
  • postTowns is a list because districts and post towns are many-to-many: SK9 covers both Wilmslow and Alderley Edge.

Parameters

NameInTypeRequiredDescriptionExample
outwardpathstringYesA postcode district, which is the outward half of a postcode: SK9, AL1, SW1A. Case is ignored.SK9
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/areas/SK9"
Example response
{
  "data": {
    "outward": "SK9",
    "districtSlug": "sk-9",
    "latitude": 53.328270181153556,
    "longitude": -2.2302287311129168,
    "population": 37930,
    "propertyCount": 18995,
    "postTowns": [
      "alderley-edge",
      "wilmslow"
    ],
    "localities": [
      {
        "name": "Handforth, Wilmslow",
        "slug": "handforth-wilmslow"
      },
      {
        "name": "Styal, Wilmslow",
        "slug": "styal-wilmslow"
      }
    ],
    "airQuality": {
      "rating": 3,
      "europeanAqi": 19.3125,
      "ozone": 42.52777777777778,
      "nitrogenDioxide": 15.624305555555559,
      "sulphurDioxide": 1.4576388888888894,
      "carbonMonoxide": 152.65972222222223
    },
    "crimeRate": {
      "ratePer1000": 63.880833113630366,
      "totalCrimes": 2423,
      "months": 12,
      "windowEnd": "2026-03-31T23:00:00.000Z"
    },
    "housePrices": {
      "latestYear": 2025,
      "averagePrice": 560580,
      "medianPrice": 467500,
      "saleCount": 521
    },
    "links": {
      "housePrices": "/areas/SK9/house-prices",
      "crime": "/areas/SK9/crime"
    }
  }
}

House prices by year

GET/api/v1/areas/{outward}/house-prices

Mean price, median price and sale count for every year we hold for a postcode district, oldest first. Computed from HM Land Registry Price Paid Data, which starts in 1995, so a full series is three decades of transactions. Narrow it with from and to.

  • Prices are whole pounds. averagePrice is the mean and medianPrice the median of every recorded sale in the district that year, so a handful of very large sales moves the mean and leaves the median alone.
  • The newest year is partial until the Land Registry finishes publishing it. Compare like for like before quoting year-on-year growth.
  • England and Wales only. The Price Paid Data does not cover Scotland or Northern Ireland.
  • Sales are counted where the Land Registry recorded them, which includes new-build and non-residential transfers.
  • Years with no recorded sales are absent from the series rather than present with a zero.

Parameters

NameInTypeRequiredDescriptionExample
outwardpathstringYesA postcode district, which is the outward half of a postcode: SK9, AL1, SW1A. Case is ignored.SK9
fromqueryintegerNoEarliest year to include, as four digits. Omit for the whole series.2023
toqueryintegerNoLatest year to include, as four digits. Omit for the whole series.2025
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/areas/SK9/house-prices?from=2023"
Example response
{
  "data": [
    {
      "year": 2023,
      "averagePrice": 531626,
      "medianPrice": 430625,
      "saleCount": 736
    },
    {
      "year": 2024,
      "averagePrice": 544675,
      "medianPrice": 422475,
      "saleCount": 808
    },
    {
      "year": 2025,
      "averagePrice": 560580,
      "medianPrice": 467500,
      "saleCount": 521
    }
  ],
  "meta": {
    "outward": "SK9",
    "count": 3,
    "source": "HM Land Registry Price Paid Data"
  }
}

Crime in a district

GET/api/v1/areas/{outward}/crime

Police.uk street-level crime for a postcode district, summed by category and by month, alongside the precomputed rate per 1,000 residents. Categories keep the Police.uk slug and gain a display label; months are YYYY-MM, newest first.

  • Source is the Police.uk street-level crime feed. Coverage is uneven: some forces publish sparsely or late, so a low totalCrimes can mean a quiet district or a quiet force. Read monthsOfData before comparing two districts.
  • Street-level crimes are snapped by Police.uk to anonymised map points near, not at, the location of the offence.
  • trend compares the last six months to the six before them and stays stable until there are twelve months to compare and the change exceeds 10 percent. trendPercentage is that change, positive for a rise.
  • ratePer1000 comes from the same rolling window as /areas/{outward}, not from the months in byMonth, so the two counts differ. It is null where no rate has been computed.
  • England, Wales and Northern Ireland. Police Scotland does not publish to this feed.
  • The first call for a district we hold no cached crime for fetches Police.uk and is slower than the rest.
  • byCategory and byMonth are shown trimmed here; a real response carries every category and month.

Parameters

NameInTypeRequiredDescriptionExample
outwardpathstringYesA postcode district, which is the outward half of a postcode: SK9, AL1, SW1A. Case is ignored.SK9
Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/areas/SK9/crime"
Example response
{
  "data": {
    "totalCrimes": 2450,
    "monthsOfData": 13,
    "averageMonthly": 188,
    "trend": "stable",
    "trendPercentage": -10,
    "byCategory": [
      {
        "category": "violent-crime",
        "label": "Violence & Sexual Offences",
        "count": 1038
      },
      {
        "category": "public-order",
        "label": "Public Order",
        "count": 259
      },
      {
        "category": "shoplifting",
        "label": "Shoplifting",
        "count": 219
      }
    ],
    "byMonth": [
      {
        "month": "2026-04",
        "count": 202
      },
      {
        "month": "2026-03",
        "count": 189
      },
      {
        "month": "2026-02",
        "count": 163
      }
    ],
    "ratePer1000": 63.880833113630366
  }
}

Account

Your plan, quota and usage for the key you are calling with.

Your plan and usage

GET/api/v1/usage

The plan, quota and month-to-date usage of the key you are calling with. Quotas run on calendar months in UTC on every plan, so period.end is the first instant of next month and the moment used resets to zero. used counts every request the account made in the period, and this call is not in it yet: the gateway records a request after it has answered, so the count you get back is the one taken just before this call. The X-Quota-Used header on the same response does include it, which is why the two differ by one.

  • Usage is summed across every key on the account, not just the one you called with, because the quota belongs to the account.
  • key.id identifies the key you authenticated with. The key itself is never returned by any endpoint: it is shown once, when you create it.
  • This endpoint costs a request like every other one.
  • remaining is floored at zero. Once the quota is spent, every endpoint answers 429 with code quota_exceeded until the period rolls over.
  • perMinute is the burst limit, applied per key over a rolling 60 seconds, and is reported by the X-RateLimit-Limit and X-RateLimit-Remaining headers on every response.

This endpoint takes no parameters.

Example request
curl -H "Authorization: Bearer upl_live_Ab12Cd34EfGhIjKlMnOpQrStUvWxYz01" \
  "https://ukpropertylooker.com/api/v1/usage"
Example response
{
  "data": {
    "plan": {
      "id": "free",
      "name": "Free",
      "monthlyQuota": 100,
      "perMinute": 10
    },
    "period": {
      "start": "2026-09-01T00:00:00.000Z",
      "end": "2026-10-01T00:00:00.000Z"
    },
    "usage": {
      "used": 37,
      "remaining": 63
    },
    "key": {
      "id": "0f6b2d1e-9c47-4a8b-b0d5-3e71c2a94f68"
    }
  }
}