Developer Portal
Access Luxembourg real estate intelligence via our public API
Getting Started
Step 1 — Get your API key
Create a free account at chathome.lu/developers to get your API key. Keys are shown once at creation — store them securely.
# Your API key looks like this:\nch_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6Step 2 — Authenticate
Pass your API key in every request using the X-API-Key header.
curl -X GET 'https://chathome.lu/api/public/v1/communes' \
-H 'X-API-Key: ch_your_api_key_here' \
-H 'Accept: application/json'Step 3 — Make your first request
Try the communes endpoint to get all Luxembourg communes with their liveability scores.
Parameters
Request
curl -X GET \
'/api/public/v1/communes?locale=en' \
-H 'Accept: application/json'Endpoints
/communes
Returns all 100 Luxembourg communes. Liveability is null and marked withheld unless every weighted dimension has complete evidence.
Parameters
| Name | Type | Description |
|---|---|---|
locale | string | Locale for commune namese.g. en |
Response
{
"communes": [
{
"slug": "luxembourg",
"name": "Luxembourg City",
"liveabilityScore": null,
"liveabilityScoreStatus": "withheld"
}
],
"total": 100,
"locale": "en"
}Error Codes
INTERNAL_ERROR
Failed to fetch communes from the server.
Parameters
Request
curl -X GET \
'/api/public/v1/communes?locale=en' \
-H 'Accept: application/json'/communes/{slug}/intelligence
Returns source-status-aware commune intelligence. Missing evidence is null, never a neutral default.
Parameters
| Name | Type | Description |
|---|---|---|
slug* | string | Commune URL sluge.g. luxembourg |
Response
{
"communeSlug": "luxembourg",
"communeName": {
"en": "Luxembourg City",
"fr": "Luxembourg-Ville",
"de": "Luxemburg-Stadt",
"lu": "Lëtzebuerg-Stad",
"pt": "Cidade do Luxemburgo"
},
"liveabilityScore": null,
"liveabilityScoreStatus": "withheld",
"dimensions": {
"price": {
"score": null,
"trend": "down",
"trendPercent": -2.1,
"sparkline": [
7100,
7200,
7050,
6980
],
"dataAvailability": "partial"
},
"safety": {
"score": null,
"trend": "flat",
"trendPercent": null,
"sparkline": [],
"dataAvailability": "partial"
}
},
"summary": {
"en": "Luxembourg City's verified commune profile is currently partial. Dimensions without full source coverage are withheld rather than estimated."
},
"lastUpdated": "2026-03-01T00:00:00Z"
}Error Codes
NOT_FOUND
No intelligence data for this commune.
UNAUTHORIZED
Invalid or missing API key.
Parameters
Request
curl -X GET \
'/api/public/v1/communes/{slug}/intelligence?slug=luxembourg' \
-H 'Accept: application/json'/market-index
Returns the latest immutable ChatHome asking-price snapshot. It is a current listing-sample median, not a transaction-price index or a momentum forecast.
Response
{
"sourceIssueId": "2026-08",
"month": "2026-08",
"saleMedianPerSqm": 8000,
"rentMedianPerSqm": 30,
"saleSampleSize": 250,
"rentSampleSize": 400,
"activeListingCount": 650,
"communeCount": 75,
"computedAt": "2026-08-31T00:00:00.000Z",
"publishedAt": "2026-08-31T01:00:00.000Z",
"methodologyVersion": "v1",
"methodologyUrl": "https://chathome.lu/en/prices/methodology",
"canonicalUrl": "https://chathome.lu/en/prices/index/2026-08",
"sources": [
"Active ChatHome listing inventory"
]
}Error Codes
INTERNAL_ERROR
Failed to compute market index.
Request
curl -X GET \
'/api/public/v1/market-index' \
-H 'Accept: application/json'MCP Agent Tools
Connect AI agents (Claude Desktop, ChatGPT, Cursor, and others) directly to chathome via MCP. Public property discovery needs no account; scopes apply when authenticating for higher limits or protected tools.
Available Scopes
listings:readRead listing access for search, interactive cards, get_listing, and get_listing_truth.
market:readRead market access for context, valuation, affordability, and commute tools.
inquiries:writeWrite access to create inquiry conversations on behalf of the authenticated user. Required for submit_inquiry.
inquiries:readRead access to inquiry conversations created by this API key. Required for get_inquiry_status.
Agent-to-agent flow
- Search listings with
search_rentalsorsearch_for_sale - Enrich with
get_listing,get_market_context, andget_commute_times - Validate price with
get_price_estimate - Contact the owner via
submit_inquiry - Poll for replies with
get_inquiry_status
listings:readNo accountPreferred natural-language search for lifestyle, proximity, mood, and other soft preferences.
Example input
{
"query": "quiet two-bedroom near Kirchberg with a balcony",
"intent": "rent"
}listings:readNo accountSearch rental properties by commune, price range, bedrooms, and more.
Example input
{
"commune": "luxembourg",
"maxPrice": 2500,
"beds": 2
}listings:readNo accountSearch properties for sale across Luxembourg and its cross-border commuter belt.
Example input
{
"commune": "esch-sur-alzette",
"propertyType": "apartment"
}listings:readNo accountRender exact results from a prior search as a cross-platform MCP Apps property carousel.
Example input
{
"listings": [
{
"id": "abc123",
"score": 91,
"matchReasons": [
"Near Kirchberg"
]
}
],
"heading": "Quiet homes near Kirchberg",
"locale": "en"
}listings:readNo accountRetrieve the full fail-closed listing-page record plus normalized costs, property checks, station frequency, and commute context.
Example input
{
"id": "abc123",
"locale": "en"
}listings:readNo accountCompare two to eight homes through one normalized response with costs, property checks, mobility, value context, and evidence.
Example input
{
"ids": [
"abc123",
"def456"
],
"locale": "en"
}listings:readInspect the full listing-page record, normalized decision facts, sources, freshness, unknowns, and privacy-safe correction summaries.
Example input
{
"id": "abc123",
"locale": "en"
}market:readNo accountGet real estate market data and liveability scores for a Luxembourg commune.
Example input
{
"commune": "kirchberg",
"locale": "en"
}market:readGet every agency with active listings in a supported Luxembourg town, including current buy/rent stock and asking-price ranges.
Example input
{
"commune": "mersch",
"locale": "en"
}market:readResolve supported place names, aliases and IDs, without guessing ambiguous names.
Example input
{
"query": "Kirchberg",
"country": "LU",
"locale": "en"
}market:readNumeric estimate with ranges, scope and limitations; no AI-written report or account.
Example input
{
"commune": "mersch",
"propertyType": "apartment",
"listingType": "sale",
"areaSqm": 85,
"hasGarage": false
}market:readAI-powered price estimate for a property using the chathome valuation model.
Example input
{
"propertyType": "apartment",
"listingType": "sale",
"commune": "luxembourg",
"areaSqm": 85,
"bedrooms": 2,
"constructionYear": 2010,
"energyClass": "B"
}market:readCalculate Luxembourg purchasing power with a complete or known-cost-only acquisition-cost basis. Bëllegen credit requires explicit residence use, eligible acquirer count, and confirmed unused balance; isFirstTimeBuyer is deprecated compatibility only.
Example input
{
"annualNetIncome": 84000,
"maxDebtToIncomeRatio": 0.35,
"monthlyDebts": 500,
"savingsAvailable": 100000,
"householdType": "couple",
"employmentType": "salaried",
"residencyType": "luxembourg",
"residenceUse": "primary",
"bellegenAktEligibleBuyers": 2,
"bellegenAktCreditAvailable": 80000,
"isFirstTimeBuyer": false
}market:readAnonymous loan payment and repayment calculation from explicit assumptions. No user profile or loan application is saved.
Example input
{
"principal": 400000,
"annualRatePct": 3,
"years": 25,
"extraMonthlyPayment": 0
}market:readAnonymous buy-versus-rent scenario from explicit price, rent and rate; the winner stays null until acquisition costs are complete.
Example input
{
"price": 650000,
"monthlyRent": 2400,
"mortgageRatePct": 3.2
}market:readAnonymous Luxembourg purchase duties and notary costs; Bëllegen Akt only when confirmed.
Example input
{
"price": 750000,
"residenceUse": "primary",
"eligibleAcquirerCount": 1
}market:readAnonymous indicative rent subsidy with dated thresholds; never an entitlement.
Example input
{
"householdSize": 2,
"monthlyNetIncome": 3500,
"monthlyRent": 1600
}market:readAnonymous legal rent ceiling (5% rule) for a rent or the owner's purchase figures.
Example input
{
"monthlyRent": 1800,
"price": 600000,
"purchaseYear": 2015,
"buildingYear": 1995
}market:readAnonymous Luxembourg plot check from a cadastral reference or precise point; information, not legal advice.
Example input
{
"lat": 49.6116,
"lng": 6.1319
}market:readAnonymous source-dated full-term fixed market observations; unavailable data never becomes a current personal bank quote.
Example input
{}market:readCommute time estimates from a commune to Luxembourg City, Kirchberg, or Belval.
Example input
{
"commune": "differdange",
"destination": "belval",
"mode": "transit"
}inquiries:writeSend an inquiry about a listing. Creates a conversation thread for chathome-hosted listings, or returns external agency contact details.
Example input
{
"listingId": "abc123",
"message": "My client is interested in this apartment. Is it still available?",
"agentName": "Acme Property AI",
"contactEmail": "ai@acme.example"
}inquiries:readPoll an MCP agent inquiry conversation for replies. Only accessible for conversations created via the MCP agent channel.
Example input
{
"conversationId": "conv_xyz789"
}Claude Agent Skill
A packaged skill teaches Claude when and how to use these tools — search workflows, budget-fit annotation, and Luxembourg market context. Upload the zip in claude.ai under Settings → Capabilities, or install the Claude Code plugin (bundles the MCP server too).
Rate Limits
Rate limits are applied per API key using a 24-hour sliding window. Limits vary by tier:
Free
100/day
Free forever
Basic
1,000/day
€49/month
Premium
10,000/day
€199/month
Note: When a rate limit is exceeded, the API returns a 429 Too Many Requests response with a Retry-After header indicating when you can retry.
Error Codes
UNAUTHORIZED
Invalid API key
RATE_LIMIT_EXCEEDED
Rate limit exceeded
NOT_FOUND
Resource not found
BAD_REQUEST
Invalid request parameters
INTERNAL_ERROR
An unexpected server error occurred
Code Examples
bash
# Install jq for JSON formatting
# List all communes
curl -X GET \
'https://chathome.lu/api/public/v1/communes?locale=en' \
-H 'X-API-Key: ch_your_api_key_here' \
-H 'Accept: application/json' | jq .javascript
// Fetch commune intelligence
const response = await fetch(
'https://chathome.lu/api/public/v1/communes/luxembourg/intelligence',
{
headers: {
'X-API-Key': 'ch_your_api_key_here',
'Accept': 'application/json',
},
}
);
const data = await response.json();
console.log(
'Liveability:',
data.liveabilityScoreStatus === 'available'
? data.liveabilityScore
: 'withheld'
);python
import requests
headers = {
'X-API-Key': 'ch_your_api_key_here',
'Accept': 'application/json',
}
# Get source-status-aware commune intelligence
response = requests.get(
'https://chathome.lu/api/public/v1/communes/luxembourg/intelligence',
headers=headers
)
data = response.json()
status = data.get('liveabilityScoreStatus', 'withheld')
print(f"Liveability evidence status: {status}")On this page