Ireland Property Analytics API

Programmatic access to Irish property market data — county prices, trends, rental yields, planning permissions and crime statistics across all 26 counties.

Get API Key Interactive Docs (Swagger)

Authentication

All endpoints (except /api/v1/health) require an API key passed in the X-API-Key HTTP header.

curl https://property.fanyang.me/api/v1/counties \
  -H "X-API-Key: YOUR_API_KEY"

Subscribe at pricing.html to receive an API key by email. Keys are prefixed ip_.

Base URL

https://property.fanyang.me

All endpoints are served over HTTPS. The API follows REST conventions — all responses are JSON, all methods are GET.

Endpoints

GET /api/v1/health No auth API health check

Returns API status and version. No authentication required. Useful for uptime monitoring.

Response

{
  "status": "ok",
  "version": "1.0.0"
}
GET /api/v1/counties Auth required All counties — latest stats

Returns the latest market statistics for all 26 Irish counties, including median sale price, rental yield, 2-bed rent, and price percentiles.

Response

{
  "data": [
    {
      "county": "Dublin",
      "median_price": 465000,
      "rent_2bed": 2347,
      "gross_yield_pct": 6.06,
      "price_growth_5yr_pct": 34.2,
      "sample_count": 18420,
      "price_percentiles": {
        "p10": 245000, "p25": 330000, "p50": 465000,
        "p75": 620000, "p90": 850000
      },
      "crime": { ... },
      "planning": { ... }
    },
    ...
  ],
  "count": 26
}
GET /api/v1/counties/{county} Auth required Single county — full detail

Full data for one county: prices, rents, yield, price percentiles, planning permissions and crime statistics. County name is case-insensitive.

Path parameters

ParameterTypeExampleDescription
countystringDublinCounty name (case-insensitive). One of the 26 counties.

Example

curl https://property.fanyang.me/api/v1/counties/Cork \
  -H "X-API-Key: YOUR_API_KEY"

Response

{
  "county": "Cork",
  "median_price": 340000,
  "rent_2bed": 1650,
  "gross_yield_pct": 5.82,
  "price_growth_5yr_pct": 28.4,
  "sample_count": 6210,
  "price_percentiles": {
    "p10": 165000, "p25": 235000, "p50": 340000,
    "p75": 480000, "p90": 680000
  },
  "crime": {
    "theft_offences": 4820,
    "public_order": 1340,
    "drug_offences": 890,
    ...
  },
  "planning": {
    "units_granted": 2840,
    "year": 2023
  }
}
GET /api/v1/counties/{county}/towns Auth required Town/area price breakdown

Town and area-level median prices within a county, extracted from Property Price Register address data. Areas with fewer than 15 transactions are excluded.

Example

curl https://property.fanyang.me/api/v1/counties/Wicklow/towns \
  -H "X-API-Key: YOUR_API_KEY"

Response

{
  "county": "Wicklow",
  "data": [
    {"area": "Bray", "median": 420000, "count": 312},
    {"area": "Greystones", "median": 510000, "count": 248},
    {"area": "Wicklow Town", "median": 295000, "count": 186},
    ...
  ]
}
GET /api/v1/counties/{county}/percentiles Auth required Price distribution (p10–p90)

Price distribution for a county (2022–present): p10, p25, p50, p75, p90. Useful for determining whether a given price is above or below market.

Response

{
  "county": "Limerick",
  "p10": 130000,
  "p25": 185000,
  "p50": 265000,
  "p75": 385000,
  "p90": 520000
}
GET /api/v1/mortgage-rates Auth required ECB and Irish mortgage rates

Latest ECB main refinancing rate and Irish retail mortgage rates, sourced from the ECB SDMX API and Central Bank of Ireland.

Response

{
  "ecb_rate_pct": 2.65,
  "ecb_as_of": "2025-09",
  "ecb_history": {
    "2022-07": 0.0,
    "2023-09": 4.5,
    ...
  },
  "ie_mortgage_rate": 3.84,
  "last_updated": "2025-12-01T00:00:00"
}

Errors

StatusMeaning
403Missing, invalid or inactive API key
404County not found or no data available for the requested resource
500Database error (rare — contact support)
// 403 example
{
  "detail": "Invalid or inactive API key. Subscribe at https://property.fanyang.me/pricing.html"
}

// 404 example
{
  "detail": "County 'Atlantis' not found. Valid values: Carlow, Cavan, Clare, ..."
}

Code examples

cURL

export API_KEY="ip_your_key_here"

# All counties
curl -s https://property.fanyang.me/api/v1/counties \
  -H "X-API-Key: $API_KEY" | jq '.data[] | {county, median_price}'

# Price trends for Dublin
curl -s https://property.fanyang.me/api/v1/counties/Dublin/trends \
  -H "X-API-Key: $API_KEY"

Python

import requests

API_KEY = "ip_your_key_here"
BASE = "https://property.fanyang.me/api/v1"
HEADERS = {"X-API-Key": API_KEY}

# Fetch all counties
r = requests.get(f"{BASE}/counties", headers=HEADERS)
r.raise_for_status()
counties = r.json()["data"]

# Print top 5 by median price
for c in sorted(counties, key=lambda x: x["median_price"], reverse=True)[:5]:
    print(f"{c['county']:12} €{c['median_price']:,}")

# Price trends for a specific county
r = requests.get(f"{BASE}/counties/Cork/trends", headers=HEADERS)
trends = r.json()["data"]
print(trends[-1])  # Most recent year

JavaScript (fetch)

const API_KEY = "ip_your_key_here";
const BASE = "https://property.fanyang.me/api/v1";

async function getCounties() {
  const res = await fetch(`${BASE}/counties`, {
    headers: { "X-API-Key": API_KEY }
  });
  if (!res.ok) throw new Error(`API error: ${res.status}`);
  const { data } = await res.json();
  return data;
}

// Example: get yield sorted counties
getCounties().then(counties => {
  const sorted = [...counties].sort((a, b) => b.gross_yield_pct - a.gross_yield_pct);
  console.table(sorted.map(c => ({
    county: c.county,
    yield: c.gross_yield_pct + "%",
    median: "€" + c.median_price.toLocaleString()
  })));
});

R

library(httr2)
library(dplyr)

api_key <- "ip_your_key_here"

req <- request("https://property.fanyang.me/api/v1/counties") |>
  req_headers("X-API-Key" = api_key)

resp <- req_perform(req)
counties <- resp_body_json(resp)$data

df <- bind_rows(lapply(counties, as.data.frame))
df |> select(county, median_price, gross_yield_pct) |>
  arrange(desc(gross_yield_pct)) |> head(10)

Rate limits

PlanDaily limitPer-minute
Pro1,000 requestsNo limit
EnterpriseUnlimitedNo limit

If you exceed the daily limit, requests return 429 Too Many Requests. Limits reset at midnight UTC. Contact imfan.yang@gmail.com for higher limits.