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
Returns API status and version. No authentication required. Useful for uptime monitoring.
Response
{
"status": "ok",
"version": "1.0.0"
}
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
}
Full data for one county: prices, rents, yield, price percentiles, planning permissions and crime statistics. County name is case-insensitive.
Path parameters
| Parameter | Type | Example | Description |
|---|---|---|---|
| county | string | Dublin | County 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
}
}
Year-by-year median sale price for a county from 2010 to the present. Each data point includes the year, transaction count and median price.
Example
curl https://property.fanyang.me/api/v1/counties/Galway/trends \
-H "X-API-Key: YOUR_API_KEY"
Response
{
"county": "Galway",
"data": [
{"year": 2010, "count": 892, "median": 195000},
{"year": 2011, "count": 780, "median": 172000},
...
{"year": 2025, "count": 2140, "median": 328000}
]
}
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},
...
]
}
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
}
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
| Status | Meaning |
|---|---|
| 403 | Missing, invalid or inactive API key |
| 404 | County not found or no data available for the requested resource |
| 500 | Database 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
| Plan | Daily limit | Per-minute |
|---|---|---|
| Pro | 1,000 requests | No limit |
| Enterprise | Unlimited | No 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.