API Docs · v1.0
Public API Documentation
Display your published property listings on any website or application. Public, read-only, no authentication required.
- No Authentication
- Public endpoint, no API keys needed
- RESTful JSON
- Standard REST API returning JSON
Endpoint
https://api.habiata.lu/public-properties/by-company/{companyId}Path Parameters
companyIdThe unique identifier of the company whose published properties you want to retrieve. You can find this in your Habiata dashboard under Integrations.
Query Parameters
pagePage number for pagination (1-indexed).
limitNumber of properties per page. Maximum 100.
portalPortal to read published listings from. Defaults to habiata, the company's own website (MY_HABIATA_WEBSITE), which can also be named explicitly. Unknown values return 400.
habiataathome.luwortimmo.luimmotopnextimmofiliaimmoweltle_figarokleinanzeigenwillhabenderstandardnewhomehomegatesrealityotodomingatlanimmowebselogerleboncoinkyerogreenacresproperstarjameseditionsearchFree-text search across title, description, address, and city.
property_typeFilter by property type. Comma-separated for multiple (OR). Matched case-insensitively. See Property Types Reference below.
housedetached_housesemi_detachedterraced_housetownhousevillamansionfarmhousecountry_housechaletbungalowcottageapartmentstudiopenthouseduplextriplexloftmaisonetteattic_apartmentground_floornew_buildoff_planunder_constructionhouse_modelland_with_houseturnkey_projectinvestment_propertyrental_propertybuilding_landagricultural_landindustrial_landcommercial_landgarageparking_spacecarportunderground_parkingofficeoffice_buildingcoworking_spaceretail_spaceshopshopping_centershowroomrestaurantcafehotelbed_breakfastwarehousefactoryindustrial_unitlogistics_centerstorage_facilityhealthcareeducationalleisurereligiousutilitygas_stationcar_washworkshopcommerciallandothertransaction_typeFilter by deal direction or lifecycle. Comma-separated for multiple (OR). buy and rent are families; sold and rented are excluded unless named explicitly; pass off_market for withdrawn/paused only.
buyrentnewvaluationothersous_compromisreservedsoldrentedoff_marketmin_priceMinimum price.
max_priceMaximum price.
cityComma-separated city names; case-insensitive exact match.
cantonFilter by canton (case-insensitive).
zip_codeFilter by postal code (case-insensitive).
countryFilter by country (case-insensitive).
districtComma-separated district / quartier names (e.g. Limpertsberg,Hamm); case-insensitive exact match.
min_bedroomsMinimum number of bedrooms.
max_bedroomsMaximum number of bedrooms.
min_bathroomsMinimum number of bathrooms.
min_areaMinimum living area (in the listing's area unit, usually sqm).
max_areaMaximum living area (in the listing's area unit, usually sqm).
min_land_areaMinimum land area (in the listing's area unit, usually sqm).
max_land_areaMaximum land area (in the listing's area unit, usually sqm).
min_year_builtMinimum construction year.
max_year_builtMaximum construction year.
min_floor_levelMinimum floor level of the unit.
max_floor_levelMaximum floor level of the unit.
min_garagesMinimum number of garages (cars fitting in enclosed, lockable garages).
min_indoor_parking_spacesMinimum number of spots in a shared covered structure.
min_outdoor_parking_spacesMinimum number of open-air spaces.
min_carportsMinimum number of carport spaces (covered, open-sided).
max_monthly_chargesMaximum monthly charges (useful for rentals).
energy_classComma-separated energy classes (OR), case-insensitive. Known values: A+, A, B, C, D, E, F, G, H, I.
A+ABCDEFGHIenvironmental_classComma-separated environmental classes (OR), case-insensitive.
thermal_insulation_classComma-separated thermal insulation classes (OR), case-insensitive.
heating_typeComma-separated heating types (OR); case-insensitive substring match. Known values: gas, oil, electric, wood, pellet, solar, heat pump, geothermal, district.
gasoilelectricwoodpelletsolarheat pumpgeothermaldistrictglazing_typeComma-separated glazing types (OR); case-insensitive substring match. Known values: simple, double, triple.
simpledoubletripleconstruction_typeComma-separated construction types (OR); case-insensitive substring match.
amenitiesComma-separated amenity keys; the property must have EVERY listed amenity (AND). Values are lowercase snake_case keys, e.g. air_conditioning.
pets_allowedFilter pet-friendly listings. Boolean filters accept true/false/1/0 and match only properties where the flag is explicitly set (unknown/null never matches).
is_furnishedFilter furnished listings.
has_elevatorFilter listings with an elevator.
has_balconyFilter listings with a balcony.
has_gardenFilter listings with a garden.
has_terraceFilter listings with a terrace.
has_separate_wcFilter listings with a separate WC.
has_caveFilter listings with a basement.
has_wine_cellarFilter listings with a wine cellar.
has_atticFilter listings with an attic.
has_solar_panelsFilter listings with solar panels.
has_fireplaceFilter listings with a fireplace.
has_underfloor_heatingFilter listings with underfloor heating.
has_laundry_roomFilter listings with a laundry room.
has_swimming_poolFilter listings with a swimming pool.
has_saunaFilter listings with a sauna.
has_hammamFilter listings with a hammam.
has_alarmFilter listings with an alarm system.
has_intercomFilter listings with an intercom.
has_videophoneFilter listings with a videophone.
has_video_surveillanceFilter listings with video surveillance.
featuredFilter featured listings.
highlightFilter highlighted listings.
sortSort order. Default: the company's manual listing order.
price_ascprice_descnewestoldestCode Examples
Basic request
curl "https://api.habiata.lu/public-properties/by-company/YOUR_COMPANY_ID?page=1&limit=20"With filters
# Filter by property type
curl "https://api.habiata.lu/public-properties/by-company/YOUR_COMPANY_ID?property_type=apartment"
# Filter by transaction type (buy/rent are families; sold/rented only when named)
curl "https://api.habiata.lu/public-properties/by-company/YOUR_COMPANY_ID?transaction_type=buy"
curl "https://api.habiata.lu/public-properties/by-company/YOUR_COMPANY_ID?transaction_type=sold,rented"
# Search properties
curl "https://api.habiata.lu/public-properties/by-company/YOUR_COMPANY_ID?search=Luxembourg&limit=10"
# Filter by district / quartier
curl "https://api.habiata.lu/public-properties/by-company/YOUR_COMPANY_ID?district=Limpertsberg,Hamm"
# Filter by portal (habiata, athome.lu, wortimmo.lu, immotop, nextimmo, filia)
curl "https://api.habiata.lu/public-properties/by-company/YOUR_COMPANY_ID?portal=nextimmo&page=1&limit=20"Response
Example Response
200 OK{
"properties": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"company_id": "YOUR_COMPANY_ID",
"external_id": "REF-12345",
"project_id": "proj-uuid-residence-du-parc",
"project_name": "Résidence du Parc",
"title": "Beautiful Apartment in Kirchberg",
"titles": {
"en": "Beautiful Apartment in Kirchberg",
"fr": "Bel appartement à Kirchberg",
"de": "Schöne Wohnung in Kirchberg"
},
"description": "Spacious 3-bedroom apartment with panoramic views...",
"descriptions": {
"en": "Spacious 3-bedroom apartment with panoramic views...",
"fr": "Spacieux appartement de 3 chambres avec vue panoramique...",
"de": "Geräumige 3-Zimmer-Wohnung mit Panoramablick..."
},
"property_type": "apartment",
"transaction_type": "buy",
"status": "active",
"price": 850000,
"room_count": 4,
"bedrooms": 3,
"bathrooms": 2,
"area": 120,
"area_unit": "sqm",
"floor_level": 5,
"address": "2 Rue du Fort Thüngen",
"street": "Rue du Fort Thüngen",
"house_number": "2",
"city": "Luxembourg",
"district": "Kirchberg",
"zip_code": "1499",
"country": "Luxembourg",
"publish_address": true,
"latitude": 49.6236,
"longitude": 6.1469,
"parcel_numbers": [
"123/4567"
],
"energy_class": "B",
"indoor_parking_spaces": 1,
"has_elevator": true,
"monthly_charges": 250,
"parking_fees": 35000,
"available_from": "2026-11-01",
"pet_policy": null,
"virtual_tour_url": "https://my.matterport.com/show/?m=EXAMPLE",
"highlighted_image": "https://cdn.habiata.lu/companies/YOUR_COMPANY_ID/living-room.jpg",
"highlighted_image_128": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/128.webp",
"highlighted_image_480": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/480.webp",
"highlighted_image_1080": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/1080.webp",
"highlighted_image_1920": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/1920.webp",
"images": [
{
"url": "https://cdn.habiata.lu/companies/YOUR_COMPANY_ID/living-room.jpg",
"url_128": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/128.webp",
"url_480": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/480.webp",
"url_1080": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/1080.webp",
"url_1920": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/1920.webp",
"is_main": true,
"sort_order": 0,
"caption": "Living room",
"width": 4032,
"height": 3024,
"alt_text": "Bright living room with floor-to-ceiling windows",
"focus_point": "50% 40%"
}
],
"documents": [
{
"id": "doc-uuid",
"name": "Brochure Résidence du Parc",
"description": null,
"type": "brochure",
"type_label": "Brochure",
"source": "property",
"content_type": "application/pdf",
"file_size": 2400000,
"download_url": "https://api.habiata.com/public-properties/documents/doc-uuid",
"created_at": "2025-01-15T10:30:00Z"
}
],
"nearby_places": [
{
"name": "Luxexpo tram stop",
"category": "tram_stop",
"distance": 350,
"latitude": 49.6282,
"longitude": 6.1641
}
],
"agents": [
{
"id": "agent-uuid",
"name": "Alex Smith",
"first_name": "Alex",
"last_name": "Smith",
"email": "alex.smith@example.com",
"phone": "+352 27 12 34 56",
"mobile": "+352 691 000 000",
"language": "fr",
"avatar": "https://cdn.habiata.lu/avatars/agent-uuid.jpg"
}
],
"portal_publications": [
{
"portal_integration_id": "portal-uuid",
"portal_type": "MY_HABIATA_WEBSITE",
"status": "PUBLISHED",
"external_id": null,
"published_at": "2025-01-15T10:30:00Z",
"unpublished_at": null,
"last_error": null,
"last_error_at": null
}
],
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-06-20T14:00:00Z"
}
],
"projects": [
{
"id": "proj-uuid-residence-du-parc",
"company_id": "YOUR_COMPANY_ID",
"name": "Résidence du Parc",
"descriptions": {
"fr": "Résidence de 12 appartements au cœur de Kirchberg."
},
"external_id": null,
"cover_images": [],
"property_count": 1
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 42,
"pages": 3
}
}Error Responses
| Status | Description |
|---|---|
| 400 | Unknown portal value, or invalid page or limit |
| 404 | Company not found or no portal configured. |
Images
Every photo comes as the original upload plus four compressed WebP copies. Display a copy: originals can weigh several megabytes.
Each size is a bounding box, not a width: the photo is scaled to fit inside a square of that size and keeps its aspect ratio. A portrait photo fitted inside 480 comes out 480 px tall and narrower than 480 px. Photos smaller than a size are never enlarged.
Copies are generated shortly after upload. Until then, or if generation failed, the size field is null. Fall back to the next larger copy, then a smaller one, and use the original only when no copy exists.
Sizes
| images[] | Main photo | Size |
|---|---|---|
url_128 | highlighted_image_128 | 128 px: tiny thumbnails, map pins |
url_480 | highlighted_image_480 | 480 px: listing cards and grids |
url_1080 | highlighted_image_1080 | 1080 px: detail pages and tablets |
url_1920 | highlighted_image_1920 | 1920 px: full-screen galleries and hero images |
url | highlighted_image | Original upload: downloads and last-resort fallback |
images[] lists every photo in gallery order, main photo first. The highlighted_image fields repeat the main photo's sizes on the property itself, so a listing card needs no array lookup.
Code Examples
Listing card
// Listing card: the main photo's sizes sit on the property itself
const cardUrl =
property.highlighted_image_480 ??
property.highlighted_image_1080 ??
property.highlighted_image_1920 ??
property.highlighted_image_128 ??
property.highlighted_image;Gallery with srcset
const SIZES = [128, 480, 1080, 1920];
// Requested size first, then larger copies, then smaller ones, then the original
function pickImageUrl(image, size = 1080) {
const larger = SIZES.filter((s) => s > size);
const smaller = SIZES.filter((s) => s < size).reverse();
for (const s of [size, ...larger, ...smaller]) {
if (image[`url_${s}`]) return image[`url_${s}`];
}
return image.url;
}
// Photos are fitted inside the size and never enlarged
function copyWidth(image, size) {
if (!image.width || !image.height) return size;
return Math.round(image.width * Math.min(1, size / Math.max(image.width, image.height)));
}
function srcSet(image) {
return SIZES.filter((s) => image[`url_${s}`])
.map((s) => `${image[`url_${s}`]} ${copyWidth(image, s)}w`)
.join(", ");
}
const gallery = property.images.map((image) => `
<img
src="${pickImageUrl(image, 1080)}"
srcset="${srcSet(image)}"
sizes="(max-width: 768px) 100vw, 1080px"
alt="${image.alt_text ?? image.caption ?? property.title}"
style="object-fit: cover; object-position: ${image.focus_point ?? "50% 50%"}"
loading="lazy"
/>`);Single Property Endpoint
Returns one published property by ID, the detail-page counterpart of the by-company list.
The property must have a PUBLISHED publication on the resolved portal; otherwise the response is 404, identical to a non-existent ID.
Unlike the list endpoint, no lifecycle filtering is applied: a published listing stays reachable by its own URL whatever its transaction_type (including sold, rented and off_market), so deep links keep resolving. Read transaction_type to decide how to render a closed deal.
https://api.habiata.lu/public-properties/{propertyId}Path Parameters
propertyIdThe unique identifier of the property.
Query Parameters
portalPortal the property must be published on. Defaults to habiata, the company's own website (MY_HABIATA_WEBSITE), which can also be named explicitly. Unknown values return 400.
habiataathome.luwortimmo.luimmotopnextimmofiliaimmoweltle_figarokleinanzeigenwillhabenderstandardnewhomehomegatesrealityotodomingatlanimmowebselogerleboncoinkyerogreenacresproperstarjameseditionExample Request
curl "https://api.habiata.lu/public-properties/YOUR_PROPERTY_ID"
# With portal filter
curl "https://api.habiata.lu/public-properties/YOUR_PROPERTY_ID?portal=nextimmo"Example Response
200 OK{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"company_id": "YOUR_COMPANY_ID",
"external_id": "REF-12345",
"project_id": "proj-uuid-residence-du-parc",
"project_name": "Résidence du Parc",
"title": "Beautiful Apartment in Kirchberg",
"titles": {
"en": "Beautiful Apartment in Kirchberg",
"fr": "Bel appartement à Kirchberg",
"de": "Schöne Wohnung in Kirchberg"
},
"description": "Spacious 3-bedroom apartment with panoramic views...",
"descriptions": {
"en": "Spacious 3-bedroom apartment with panoramic views...",
"fr": "Spacieux appartement de 3 chambres avec vue panoramique...",
"de": "Geräumige 3-Zimmer-Wohnung mit Panoramablick..."
},
"property_type": "apartment",
"transaction_type": "buy",
"status": "active",
"price": 850000,
"room_count": 4,
"bedrooms": 3,
"bathrooms": 2,
"area": 120,
"area_unit": "sqm",
"floor_level": 5,
"address": "2 Rue du Fort Thüngen",
"street": "Rue du Fort Thüngen",
"house_number": "2",
"city": "Luxembourg",
"district": "Kirchberg",
"zip_code": "1499",
"country": "Luxembourg",
"publish_address": true,
"latitude": 49.6236,
"longitude": 6.1469,
"parcel_numbers": [
"123/4567"
],
"energy_class": "B",
"indoor_parking_spaces": 1,
"has_elevator": true,
"monthly_charges": 250,
"parking_fees": 35000,
"available_from": "2026-11-01",
"pet_policy": null,
"virtual_tour_url": "https://my.matterport.com/show/?m=EXAMPLE",
"highlighted_image": "https://cdn.habiata.lu/companies/YOUR_COMPANY_ID/living-room.jpg",
"highlighted_image_128": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/128.webp",
"highlighted_image_480": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/480.webp",
"highlighted_image_1080": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/1080.webp",
"highlighted_image_1920": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/1920.webp",
"images": [
{
"url": "https://cdn.habiata.lu/companies/YOUR_COMPANY_ID/living-room.jpg",
"url_128": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/128.webp",
"url_480": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/480.webp",
"url_1080": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/1080.webp",
"url_1920": "https://cdn.habiata.lu/image-variants/YOUR_COMPANY_ID/img-uuid/1920.webp",
"is_main": true,
"sort_order": 0,
"caption": "Living room",
"width": 4032,
"height": 3024,
"alt_text": "Bright living room with floor-to-ceiling windows",
"focus_point": "50% 40%"
}
],
"documents": [
{
"id": "doc-uuid",
"name": "Brochure Résidence du Parc",
"description": null,
"type": "brochure",
"type_label": "Brochure",
"source": "property",
"content_type": "application/pdf",
"file_size": 2400000,
"download_url": "https://api.habiata.com/public-properties/documents/doc-uuid",
"created_at": "2025-01-15T10:30:00Z"
}
],
"nearby_places": [
{
"name": "Luxexpo tram stop",
"category": "tram_stop",
"distance": 350,
"latitude": 49.6282,
"longitude": 6.1641
}
],
"agents": [
{
"id": "agent-uuid",
"name": "Alex Smith",
"first_name": "Alex",
"last_name": "Smith",
"email": "alex.smith@example.com",
"phone": "+352 27 12 34 56",
"mobile": "+352 691 000 000",
"language": "fr",
"avatar": "https://cdn.habiata.lu/avatars/agent-uuid.jpg"
}
],
"portal_publications": [
{
"portal_integration_id": "portal-uuid",
"portal_type": "MY_HABIATA_WEBSITE",
"status": "PUBLISHED",
"external_id": null,
"published_at": "2025-01-15T10:30:00Z",
"unpublished_at": null,
"last_error": null,
"last_error_at": null
}
],
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-06-20T14:00:00Z"
}Response is a single Property object, same fields as the list endpoint (see Property Object Schema above).
Error Responses
| Status | Description |
|---|---|
| 400 | Unknown portal value |
| 404 | Property not found, not published on this portal, or deleted |
Property Types Reference
The property_type field accepts any of the following values, organized by category. Use these values when filtering via the API or interpreting property data.
House
housedetached_housesemi_detachedterraced_housetownhousevillamansionfarmhousecountry_housechaletbungalowcottageApartment
apartmentstudiopenthouseduplextriplexloftmaisonetteattic_apartmentground_floorNew Development & Construction
new_buildoff_planunder_constructionhouse_modelland_with_houseturnkey_projectInvestment Property
investment_propertyrental_propertyLand
building_landagricultural_landindustrial_landcommercial_landGarage & Parking
garageparking_spacecarportunderground_parkingCommercial & Office
officeoffice_buildingcoworking_spaceretail_spaceshopshopping_centershowroomrestaurantcafehotelbed_breakfastIndustrial & Logistics
warehousefactoryindustrial_unitlogistics_centerstorage_facilitySpecial Use
healthcareeducationalleisurereligiousutilitygas_stationcar_washworkshopOther
commerciallandotherGrouped Projects Endpoint
Use to read entire projects and grouped properties.
https://api.habiata.lu/public-properties/projects/by-company/{companyId}Query Parameters
pagePage number for pagination (1-indexed).
limitNumber of projects per page. Maximum 100.
portalPortal to read published projects from. Defaults to habiata, the company's own website (MY_HABIATA_WEBSITE), which can also be named explicitly. Unknown values return 400.
habiataathome.luwortimmo.luimmotopnextimmofiliaimmoweltle_figarokleinanzeigenwillhabenderstandardnewhomehomegatesrealityotodomingatlanimmowebselogerleboncoinkyerogreenacresproperstarjameseditionExample Request
curl "https://api.habiata.lu/public-properties/projects/by-company/YOUR_COMPANY_ID?page=1&limit=20"Example Response
200 OK{
"projects": [
{
"id": "proj-uuid-residence-du-parc",
"company_id": "YOUR_COMPANY_ID",
"name": "Résidence du Parc",
"descriptions": { "fr": "Résidence de 12 appartements au cœur de Belair." },
"external_id": null,
"cover_images": [
{
"image_id": "img-uuid-1",
"property_id": null,
"url": "https://cdn.habiata.lu/…/residence-du-parc.jpg",
"url_128": "https://cdn.habiata.lu/…/128.webp",
"url_480": "https://cdn.habiata.lu/…/480.webp",
"url_1080": "https://cdn.habiata.lu/…/1080.webp",
"url_1920": "https://cdn.habiata.lu/…/1920.webp",
"width": 2400,
"height": 1600,
"alt_text": "Résidence du Parc — façade",
"focus_point": null
}
],
"property_count": 3,
"properties": [
{
"id": "unit-uuid-1",
"title": "Apartment 2.1 — 3 bedrooms",
"project_id": "proj-uuid-residence-du-parc",
"project_name": "Résidence du Parc",
"price": 650000,
"property_type": "apartment",
"transaction_type": "buy"
}
]
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"pages": 1
}
}Projects Reference
Projects group related properties, typically units in the same building or new-development programme.
Two ways to work with projects
| Flat properties endpoint | Grouped projects endpoint | |
|---|---|---|
| Endpoint | GET /public-properties/by-company/{companyId} | GET /public-properties/projects/by-company/{companyId} |
| Returns | All published units | Published projects with nested units under properties[] |
| Project fields | project_id and project_name on each unit | Project metadata plus nested units in properties[] |
| Publish in Habiata | Publish each property to the portal | Projects → select a named project → Publish to portals |
Publishing a property does not publish its project. Assigning units to a project in CRM is not enough for the grouped endpoint. You must publish the project separately.
Transaction Types Reference
The transaction_type field indicates deal direction and listing lifecycle. As a query filter, buy and rent are families; sold and rented are excluded unless named explicitly.
Ongoing (primary)
buyrentOngoing (secondary)
newvaluationotherOngoing (pending)
sous_compromisreservedClosed
soldrentedoff_marketFor AI Agents & Integrations
Building an integration or using an AI agent? Here's everything you need in one click.