Replacing getAddress.io? Free drop-in replacement →
← Back to Blog
Tutorials Mar 17, 2026 · 11 min read min read

Tracking UK Property Market Activity via API: Listing Events, Price Reductions, and Deal Flow

The Land Registry only records completions. The Homedata Market Activity API gives you everything in between — Added, Reduced, Sold STC, Withdrawn — for every UK property going back 30 years. Here's how to use it.

What Land Registry doesn't tell you

Land Registry is the canonical source for UK property transactions. If a property sold, it's in there — eventually. The problem is "eventually." The average gap between completion and Land Registry registration is two to four months. By then, the market has moved.

And Land Registry only records completions. It tells you nothing about the journey from listing to sale: when a property was first listed, how many times the price was cut before an offer was accepted, how long it sat as Sold STC before the deal fell through. That's the data estate agents use to price properly and investors use to find deals — and it's data that Home.co.uk has been collecting since 1996, now available via API for the first time.

The Homedata Market Activity API covers the full listing event timeline for every UK property: Added, Reduced, Under Offer, Sold STC, Withdrawn, and Completed. Thirty years of history, UPRN-linked, available via a single REST call.

What the API returns

There are two related endpoints:

  • GET /api/property_sale_events/?uprn={uprn} — full event history for a specific property
  • GET /api/property_sales/?uprn={uprn} — the Land Registry sale records, for cross-referencing completions

Each event in the response has an event_type, event_date, price (where relevant), and metadata linking back to the listing cycle it belongs to. A listing cycle is a single stretch of market activity — from first listing to either withdrawal or completion.

The six event types:

  • Added — first listed, with asking price and listing agent
  • Reduced — price cut, with the new price and date
  • Under Offer — an offer accepted, but not yet exchanged
  • Sold STC — sold subject to contract (offer accepted, solicitors instructed)
  • Withdrawn — removed from the market before sale
  • Completed — exchanged and completed (cross-references Land Registry)

Getting a property's full listing history

You'll need a UPRN. If you have an address, use Address Find + Retrieve first. Once you have the UPRN, the event history call is straightforward:

curl "https://api.homedata.co.uk/api/property_sale_events/?uprn=100023336956" \
  -H "Authorization: Api-Key YOUR_API_KEY"

Response (abbreviated):

{
  "count": 8,
  "results": [
    {
      "uprn": "100023336956",
      "event_type": "Added",
      "event_date": "2024-01-12",
      "price": 595000,
      "listing_id": "RM-12345678",
      "branch_name": "Savills Bristol"
    },
    {
      "uprn": "100023336956",
      "event_type": "Reduced",
      "event_date": "2024-02-28",
      "price": 575000,
      "listing_id": "RM-12345678",
      "branch_name": "Savills Bristol"
    },
    {
      "uprn": "100023336956",
      "event_type": "Sold STC",
      "event_date": "2024-03-15",
      "price": 575000,
      "listing_id": "RM-12345678",
      "branch_name": "Savills Bristol"
    }
  ]
}

From this response you can immediately answer: how long was it on market before it sold? How much was the price cut? How many times has this property been listed in the past ten years?


Python: build a listing history analyser

This script takes a UPRN and prints a formatted listing timeline with days-on-market and price change calculations:

import requests
from datetime import datetime, date

API_KEY = "your_api_key_here"
UPRN    = "100023336956"

def get_listing_history(uprn: str) -> list[dict]:
    resp = requests.get(
        "https://api.homedata.co.uk/api/property_sale_events/",
        params={"uprn": uprn},
        headers={"Authorization": f"Api-Key {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json()["results"]

def parse_date(s: str | None):
    return datetime.strptime(s, "%Y-%m-%d").date() if s else None

events = get_listing_history(UPRN)

# Group by listing cycle
cycles: dict[str, list] = {}
for e in events:
    key = e.get("listing_id", "unknown")
    cycles.setdefault(key, []).append(e)

for listing_id, cycle_events in cycles.items():
    cycle_events.sort(key=lambda e: e["event_date"] or "")
    added   = next((e for e in cycle_events if e["event_type"] == "Added"), None)
    closed  = next((e for e in cycle_events if e["event_type"] in ("Sold STC", "Withdrawn", "Completed")), None)

    print(f"\n── Listing {listing_id} ──")
    for e in cycle_events:
        price_str = f"  £{e['price']:,}" if e.get("price") else ""
        print(f"  {e['event_date']}  {e['event_type']:<16}{price_str}")

    if added and closed:
        days = (parse_date(closed["event_date"]) - parse_date(added["event_date"])).days
        print(f"  → {days} days on market")

    if added and added.get("price"):
        reductions = [e for e in cycle_events if e["event_type"] == "Reduced"]
        if reductions:
            final_price = reductions[-1]["price"]
            drop_pct = (1 - final_price / added["price"]) * 100
            print(f"  → {len(reductions)} price cut(s), total reduction {drop_pct:.1f}%")

Sample output for a property that sold after two reductions:

── Listing RM-12345678 ──
  2024-01-12  Added              £595,000
  2024-02-28  Reduced            £575,000
  2024-03-05  Reduced            £565,000
  2024-03-15  Sold STC           £565,000
  → 63 days on market
  → 2 price cut(s), total reduction 5.0%

JavaScript: monitoring new price reductions

If you're building a deal-monitoring tool, you'll want to watch specific properties for state changes. This snippet fetches events for a list of UPRNs and filters for recent Reduced events:

const API_KEY = 'your_api_key_here';
const UPRNS   = ['100023336956', '10093066437', '200003497125'];

async function getRecentReductions(uprns, sinceDays = 7) {
  const since = new Date();
  since.setDate(since.getDate() - sinceDays);
  const sinceStr = since.toISOString().slice(0, 10);

  const results = await Promise.all(
    uprns.map(async (uprn) => {
      const url = `https://api.homedata.co.uk/api/property_sale_events/?uprn=${uprn}`;
      const res = await fetch(url, {
        headers: { 'Authorization': `Api-Key ${API_KEY}` },
      });
      const data = await res.json();
      return data.results.filter(
        e => e.event_type === 'Reduced' && e.event_date >= sinceStr
      ).map(e => ({ uprn, ...e }));
    })
  );

  return results.flat();
}

const reductions = await getRecentReductions(UPRNS);
reductions.forEach(e => {
  console.log(`${e.uprn}: Reduced to £${e.price.toLocaleString()} on ${e.event_date}`);
});

Practical use cases

1. AVM enrichment — time-on-market as a value signal

A property that sold in 14 days at asking price is a different market signal to one that sat for 180 days and took three reductions. Incorporating days-on-market and reduction history as features in an automated valuation model gives you a quality-of-demand signal that comparable sold prices alone can't provide.

2. Estate agent CRM — vendor pricing alerts

When a vendor instructs you after listing with a competitor, pulling the event history shows you exactly how long they've been on market and where the price has moved. Walk in knowing the data instead of asking for it.

3. Investment deal flow — finding motivated sellers

Properties that have been Reduced more than once, or that came back to market after a withdrawal, often represent motivated sellers. Tracking these systematically — by area, property type, and price band — surfaces deals before they hit the forums.

4. Conveyancing due diligence — fall-through history

A property that went Sold STC and then came back to market twice is worth scrutinising. That pattern — Sold STC → returned as Active — shows up in the event timeline and is worth flagging to buyers before they commit to survey costs.

5. Mortgage/lending — LTV recalculations on refinance

For a property being refinanced, the listing event history gives you recent price discovery: if it was listed and reduced 8 months ago, that's evidence of market value that an AVM alone can miss.


Combining listing events with sold prices

The listing event history tells you the journey. Land Registry tells you the outcome. Together they let you verify that a sale completed at the agreed price — or spot cases where it didn't.

def get_sold_prices(uprn: str) -> list[dict]:
    resp = requests.get(
        "https://api.homedata.co.uk/api/property_sales/",
        params={"uprn": uprn},
        headers={"Authorization": f"Api-Key {API_KEY}"},
    )
    resp.raise_for_status()
    return resp.json()["results"]

events     = get_listing_history(UPRN)
sales      = get_sold_prices(UPRN)

sold_stc   = [e for e in events if e["event_type"] == "Sold STC"]
completed  = [s for s in sales]

# Match STC events to Land Registry records by approximate date
for stc in sold_stc:
    stc_date = parse_date(stc["event_date"])
    match = next(
        (s for s in completed
         if abs((parse_date(s.get("deed_date")) - stc_date).days) < 120),
        None,
    )
    if match:
        agreed  = stc["price"] or 0
        actual  = match.get("price", 0) or 0
        diff    = actual - agreed
        print(f"  STC: £{agreed:,} → Completed: £{actual:,}  (diff: £{diff:+,})")
    else:
        print(f"  STC at £{stc['price']:,} on {stc['event_date']} — no Land Registry match (yet)")

Rate limits and authentication

The Market Activity endpoints require an API key. The free tier (100 calls/month) is enough to evaluate the data — each call to /api/property_sale_events/ counts as one call against your quota.

The standard Authorization: Api-Key YOUR_KEY header applies. If you haven't already:

  1. Register for a free API key — no credit card, takes 30 seconds
  2. Test with the interactive playground in the docs
  3. Check the Getting Started guide for the full authentication setup

For bulk UPRN lookups or high-frequency monitoring, the Growth plan (£149/month, 10,000 calls) removes the per-call constraint and adds access to the listing events feed.

Start tracking UK property market activity

Free API key. 100 calls/month. No credit card required. Listing event history for every UPRN in the UK going back 30 years.