Sold Comparables API

Get recent property sales data in any UK postcode area, enriched with EPC data including floor area and price per m²/ft²

REST API
JSON Responses
API Key Authentication
Land Registry Data

Overview

The Sold Comparables API provides comprehensive access to recent property sales data from the UK Land Registry, enriched with Energy Performance Certificate (EPC) data. This powerful combination allows you to analyse property transactions with detailed information including floor area, energy ratings, and calculated price per square metre/foot.

This API provides:

  • Recent property sales from the Land Registry (customizable time period)
  • Complete transaction details: price paid, date, property type, estate type
  • EPC data enrichment: floor area, energy ratings, estimated bedrooms
  • Calculated metrics: price per m² and price per ft² for easy comparison
  • Property characteristics: detached, semi-detached, terraced, flat, etc.
  • New build and freehold/leasehold indicators
  • Full address details for each sold property
  • Results sorted by most recent sales first

This API is ideal for:

  • Estate agents providing market analysis and property valuations
  • Property portals displaying comparable sales to buyers and sellers
  • Mortgage lenders assessing property values for lending decisions
  • Property investors analysing market trends and investment opportunities
  • Surveyors and valuers conducting professional property assessments
  • PropTech platforms building automated valuation models (AVMs)
  • Market research firms analysing local property market dynamics
  • Homeowners researching their local property market

Important Notes

  • • Data is sourced from the official UK Land Registry database
  • • EPC data may not be available for all properties (older properties or those sold before EPC requirements)
  • • Price per m²/ft² calculations are only available when EPC data includes floor area
  • • API queries are limited to a single postcode area (no radius search)
  • • Each API call costs 1 credit

Authentication

All requests to the Sold Comparables API require authentication using an API key. You can obtain your API key from your PropertyInsights dashboard after subscribing to an API plan.

Include your API key in the request header as follows:

X-API-Key: your_api_key_here

Security Warning

Never expose your API key in client-side code. Always make API calls from your server-side application to protect your credentials.

Endpoints

Base URL

https://propertyinsights.co.uk/api/v1/

Get Sold Comparables

GET
/property/sold-comparables?postcode={postcode}&months={months}

Retrieve recent property sales for a UK postcode area, enriched with EPC data. Returns properties sold within the specified time period (default 36 months), sorted by most recent sales first.

Request Parameters

GET /property/sold-comparables

Query parameters for retrieving sold property comparables by postcode.

ParameterRequiredTypeDescription
postcodeRequiredStringUK postcode (e.g., "SW1A 1AA" or "SW1A1AA"). Space is optional and will be normalized automatically.
monthsOptionalIntegerNumber of months to look back for sales (1-120). Default: 36 months (3 years).

Postcode Format: The API automatically normalises postcodes, adding the space before the last 3 characters. Both "SW1A1AA" and "SW1A 1AA" will work correctly.

Time Period: Shorter time periods (e.g., 6-12 months) provide more recent comparables but may return fewer results. Longer periods (24-36 months) provide more data points for analysis.

Billing details in the response

Successful chargeable JSON responses include a top-level billing object. The endpoint examples on this page focus on the endpoint-specific data, so this repeated block may not be shown in every example.

"billing": {
  "mode": "prepaid",
  "creditsCharged": 1,
  "creditsRemaining": 1999,
  "creditsRefreshAt": "2026-08-14T09:30:00.000Z"
}
Field or headerMeaning
billing.creditsCharged
X-Credits-Charged
Credits charged by this call. Failed and non-chargeable calls return 0 in the header.
billing.creditsRemaining
X-Credits-Remaining
The credit balance after the call.
billing.creditsRefreshAt
X-Credits-Refresh-At
The next monthly credit refresh as an ISO 8601 timestamp. Trial and non-renewing balances return null and omit the header.

All authenticated API-key calls expose the billing headers, including validation errors and zero-credit status or management requests. Only successful chargeable JSON responses add the billing object to the response body.

Response Format

All API responses are returned in JSON format. The standard response structure is as follows:

{
  "success": boolean,
  "data": {
    "postcode": string,
    "period": string,
    "totalResults": number,
    "comparables": [
      {
        "address": string,
        "postcode": string,
        "price": number,
        "transactionDate": string,
        "propertyType": string,
        "newBuild": boolean,
        "estateType": string,
        "floorArea": number | null,
        "energyRating": string | null,
        "estimatedBedrooms": number | null,
        "pricePerSqM": number | null,
        "pricePerSqFt": number | null
      }
    ]
  },
  "error": {
    "code": string,
    "message": string,
    "details": string
  } // Only present if success is false
}

Successful Response Example

{
  "success": true,
  "data": {
    "postcode": "SW1A 1AA",
    "period": "36 months",
    "totalResults": 3,
    "comparables": [
      {
        "address": "12, VICTORIA STREET, LONDON, SW1A 1AA",
        "postcode": "SW1A 1AA",
        "price": 875000,
        "transactionDate": "2024-11-15",
        "propertyType": "terraced",
        "newBuild": false,
        "estateType": "freehold",
        "floorArea": "145.0",
        "energyRating": "C",
        "estimatedBedrooms": 3,
        "pricePerSqM": 6034,
        "pricePerSqFt": 561
      },
      {
        "address": "8A, VICTORIA STREET, LONDON, SW1A 1AA",
        "postcode": "SW1A 1AA",
        "price": 1250000,
        "transactionDate": "2024-08-22",
        "propertyType": "flat",
        "newBuild": false,
        "estateType": "leasehold",
        "floorArea": "98.0",
        "energyRating": "B",
        "estimatedBedrooms": 2,
        "pricePerSqM": 12755,
        "pricePerSqFt": 1185
      },
      {
        "address": "THE COACH HOUSE, 5, VICTORIA STREET, LONDON, SW1A 1AA",
        "postcode": "SW1A 1AA",
        "price": 1850000,
        "transactionDate": "2023-05-10",
        "propertyType": "detached",
        "newBuild": false,
        "estateType": "freehold",
        "floorArea": "215.0",
        "energyRating": "D",
        "estimatedBedrooms": 4,
        "pricePerSqM": 8604,
        "pricePerSqFt": 799
      }
    ]
  }
}

Empty Results Response

{
  "success": true,
  "data": {
    "postcode": "SW1A 1AA",
    "period": "12 months",
    "totalResults": 0,
    "comparables": []
  }
}

Returned when no sales match the criteria. Note: 1 API credit is still deducted.

Response Field Descriptions

FieldTypeDescription
addressStringFull address of the sold property
postcodeStringPostcode of the property
priceNumberSale price in GBP (£)
transactionDateString (ISO 8601)Date of the property sale (YYYY-MM-DD)
propertyTypeStringType of property: detached, semi-detached, terraced, flat, or unknown
newBuildBooleanWhether the property was newly built at time of sale
estateTypeStringTenure type: freehold, leasehold, or unknown
floorAreaNumber | nullTotal floor area in m² (from EPC data). Null if EPC data unavailable.
energyRatingString | nullCurrent EPC rating (A-G). Null if EPC data unavailable.
estimatedBedroomsNumber | nullEstimated number of bedrooms (calculated from habitable rooms). Null if EPC data unavailable.
pricePerSqMNumber | nullPrice per square metre (£/m²). Null if floor area unavailable.
pricePerSqFtNumber | nullPrice per square foot (£/ft²). Null if floor area unavailable.

Code Examples

cURL

curl -X GET "https://propertyinsights.co.uk/api/v1/property/sold-comparables?postcode=SW1A1AA&months=36" \
  -H "x-api-key: YOUR_API_KEY"

JavaScript (Fetch)

const response = await fetch(
  'https://propertyinsights.co.uk/api/v1/property/sold-comparables?postcode=SW1A1AA&months=36',
  {
    headers: {
      'x-api-key': 'YOUR_API_KEY'
    }
  }
);

const data = await response.json();

if (data.success) {
  console.log(`Found ${data.data.totalResults} sales in ${data.data.postcode}`);
  data.data.comparables.forEach(property => {
    console.log(`${property.address}: £${property.price.toLocaleString()}`);
    if (property.pricePerSqM) {
      console.log(`  Price per m²: £${property.pricePerSqM}`);
    }
  });
}

Python (requests)

import requests

url = "https://propertyinsights.co.uk/api/v1/property/sold-comparables"
params = {
    "postcode": "SW1A1AA",
    "months": 36
}
headers = {
    "x-api-key": "YOUR_API_KEY"
}

response = requests.get(url, params=params, headers=headers)
data = response.json()

if data["success"]:
    print(f"Found {data['data']['totalResults']} sales in {data['data']['postcode']}")
    for property in data["data"]["comparables"]:
        print(f"{property['address']}: £{property['price']:,}")
        if property.get("pricePerSqM"):
            print(f"  Price per m²: £{property['pricePerSqM']}")

PHP

<?php
$postcode = 'SW1A1AA';
$months = 36;

$url = "https://propertyinsights.co.uk/api/v1/property/sold-comparables?postcode={$postcode}&months={$months}";

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'x-api-key: YOUR_API_KEY'
]);

$response = curl_exec($ch);
curl_close($ch);

$data = json_decode($response, true);

if ($data['success']) {
    echo "Found {$data['data']['totalResults']} sales in {$data['data']['postcode']}\n";
    foreach ($data['data']['comparables'] as $property) {
        echo "{$property['address']}: £" . number_format($property['price']) . "\n";
        if (isset($property['pricePerSqM'])) {
            echo "  Price per m²: £{$property['pricePerSqM']}\n";
        }
    }
}
?>

Error Handling

The API uses standard HTTP response codes and returns detailed error information in JSON format. All errors follow a consistent structure to help you handle them appropriately in your application.

HTTP CodeError CodeDescription
400MISSING_POSTCODEPostcode parameter is required
400INVALID_MONTHSMonths parameter must be between 1 and 120
429RATE_LIMITEDToo many requests - rate limit exceeded
500SERVER_CONFIGURATION_ERRORServer configuration error
502LAND_REGISTRY_ERRORUpstream Land Registry service error
502EPC_SERVICE_ERRORUnable to enrich data with EPC information
401AUTHENTICATION_REQUIREDValid API key is required
402INSUFFICIENT_CREDITSNot enough API credits remaining to perform operation
500DATABASE_ERRORError accessing database - please try again
500INTERNAL_SERVER_ERRORAn unexpected error occurred

Error Response Format

{
  "success": false,
  "error": {
    "code": "MISSING_POSTCODE",
    "message": "Postcode parameter is required"
  }
}

Rate Limits

API requests are subject to rate limiting based on your subscription plan. The current limits are:

PlanRequests per MinuteRequests per DayRequests per Month
Basic105005,000
Standard302,00030,000
Premium1005,000100,000
EnterpriseCustomCustomCustom

When you exceed your rate limit, the API will return a 429 Too Many Requests response. Each response includes the following headers to help you track your usage:

X-RateLimit-Limit: [requests-per-minute limit]
X-RateLimit-Remaining: [requests remaining in current window]
X-RateLimit-Reset: [timestamp when limit resets]