Public Property model
Source-reviewed draft; deployment and release verification pending.
Draft — source-reviewed on 22 October 2026. These are implemented DTOs, not a verified live deployment contract.
The public DTOs are allowlists. Do not use an internal CRM property type as the website TypeScript model.
Required summary fields
| Field | Wire type and meaning |
|---|---|
public_id | String public identifier, such as synthetic P9001; use it unchanged in detail/image URLs. It is not a database UUID. |
operation | SALES or RENTAL, matching the search context. |
view_types | Array of supported view values; can be empty. |
catalogs | Array of active catalog membership keys; can be empty. |
location | Object with numeric lat, lng and precision (EXACT or APPROXIMATE). Required on search summaries. |
Optional summary fields
| Fields | Type and use |
|---|---|
name | Nullable string when present. Use an intentional UI fallback if absent. There is no title field. |
price | Nullable object with amount, currency, kind and period. See pricing below. |
asking_price_per_m2 | Nullable decimal string for qualifying sales. |
property_type, features_type, property_detail_type | Nullable controlled classification strings. |
bedrooms, bathrooms | Nullable integer counts. |
total_area_m2 | Nullable number, in square metres. |
city, region | Nullable strings. |
ubicacion | Nullable {key,label,city} LocalArea object. |
location_facts | Nullable object of public contextual facts. |
thumbnail | Nullable {asset_id,url,caption?} object. |
The schemas allow null for these optional fields, but the current projection normally omits unpopulated fields rather than inserting null. Responses exclude unset values. A client should accept both missing and allowed-null values; neither means zero or false. Populated false, 0 and empty arrays must remain distinct from unknown values.
The public response does not include free-text area, complex_name, rental_type, updated_at or publication status, even though some of these concepts are accepted as search filters or used internally.
Detail fields
Detail requires public_id, operation, operations, prices, view_types, catalogs, characteristics and gallery. operations contains the supported contexts; prices contains available valid prices, each with an additional operation field. Arrays may be empty and characteristics may be {}.
Detail supports the optional summary fields except thumbnail. Its location is optional and nullable. It also supports:
description: nullable string.description_translations: nullable language-to-string map; current projection accepts keys such asenoren-GBand drops invalid keys/non-string values.characteristics: public characteristic object; see Marketing and characteristics.gallery: up to 100 public images, each withasset_id,url,is_primary,display_orderand optional nullablecaption.agent: optional nullable public agent card.address_line: optional nullable string, supplied only when full address visibility permits a populated street/house-number line.
Detail selects SALES first when available if no operation query is supplied; otherwise it selects the supported context. Supplying an unsupported context returns 422. Preserve the selected context when navigating from cards.
Pricing rules
amount and asking_price_per_m2 are JSON strings, rounded to two decimal places; do not model them as floating-point financial values. Currency is EUR. A missing/invalid price omits price, and its context is absent from prices; it is not returned as zero.
| Context | kind | period |
|---|---|---|
| Sale | SALE | ONE_OFF |
| Transfer, when sale is not selected | TRANSFER | ONE_OFF |
RENTAL with SHORT_TERM source type | RENT | DAY |
RENTAL with TEMPORAL source type | RENT | MONTH |
RENTAL with LONG_TERM source type | RENT | YEAR |
If both sale and transfer are enabled, sale pricing takes precedence. asking_price_per_m2 appears only for a positive sale amount and positive total area; it uses source sale precision divided by area, rounded half up to cents. It is not a rental or investment return metric.
Rental period must be displayed explicitly. Do not convert an annual value to monthly without a separately approved UI calculation, or claim booking-date availability from operation eligibility. There is no availability calendar or availability field here.
Synthetic summary example
{
"public_id": "P9001",
"name": "Example coastal apartment",
"operation": "SALES",
"price": {"amount": "310000.00", "currency": "EUR", "kind": "SALE", "period": "ONE_OFF"},
"property_type": "HOMES",
"features_type": "FLAT",
"property_detail_type": "PENTHOUSE_DUPLEX",
"bedrooms": 2,
"bathrooms": 2,
"total_area_m2": 95,
"city": "Example municipality",
"view_types": ["SEA_AND_COAST"],
"catalogs": [],
"location": {"lat": 28.2, "lng": -16.6, "precision": "APPROXIMATE"}
}This invented fixture is for design only; the location is not a derivation claim about a real property. Do not add private coordinates or investment values to examples.
Related operations
POST /api/v1/public/properties/search returns summary items. GET /api/v1/public/properties/{public_id} returns detail. Read Location and LocalAreas and Publication and privacy before displaying addresses or persistence controls.
Updated 1 day ago