Properties
Description
Overview
Properties represent real estate objects that users can manage. Each property has a name, description, color, type, and address integrated with Nova Poshta API.
Country
Each property is linked to a country. This determines which address format is used, currency defaults, and other regional settings.
- Country is a required field when creating or editing a property
- Address format depends on selected country (Nova Poshta API for Ukraine)
- Country is displayed in property cards, lists, and detail pages
Example Response
{
"id": 1,
"name": "My Apartment",
"country": {
"id": 1,
"code": "UA",
"name_key": "country.ua"
},
"property_type": {...},
"address": {...}
}
User Roles
Each property can have multiple users with different roles:
Owner
PROPERTY_LANDLORDFull access: view, edit, delete property and manage users. Assigned automatically when creating a property.
Owner's Representative
PROPERTY_LANDLORD_AGENTCan view and edit the property, but cannot delete or manage users.
Tenant
PROPERTY_TENANTView-only access. Can see property details but cannot modify.
Tenant's Representative
PROPERTY_TENANT_AGENTView only. Represents tenant interests.
Maintenance
PROPERTY_MAINTENANCEView only. For maintenance personnel.
User Management
The property owner (PROPERTY_LANDLORD) can add and remove other users:
- Adding users: Search by email or phone. Result is shown only if exactly 1 user is found (privacy protection).
- One role per property: Each user can have only one role within a property.
- PROPERTY_LANDLORD cannot be added manually: This role is assigned automatically when creating a property.
- Owner cannot be removed: Administration required to change owner.
REST API
All API endpoints require JWT authentication.
Service layer note
Properties API
GET /api/v1/properties # List user's properties
POST /api/v1/properties # Create property (user becomes PROPERTY_LANDLORD)
GET /api/v1/properties/{id} # Property details
PUT /api/v1/properties/{id} # Update (LANDLORD/LANDLORD_AGENT)
DELETE /api/v1/properties/{id} # Delete (LANDLORD only)
Property Users API
GET /api/v1/properties/{id}/users # List property users
POST /api/v1/properties/{id}/users # Add user
DELETE /api/v1/properties/{id}/users/{userId} # Remove user
GET /api/v1/properties/{id}/search-user?q=... # Search user
GET /api/v1/properties/{id}/available-roles # Available roles
Property Descriptions (Translations) API
GET /api/v1/properties/{id}/descriptions # List description translations
POST /api/v1/properties/{id}/descriptions # Create/update translation (locale + description)
POST /api/v1/properties/{id}/descriptions/translate # AI translate to target locale
AI Features API
POST /api/v1/properties/generate-description # Generate description via Grok AI (from form data) POST /api/v1/geo/geocode # Geocode address to lat/lng (public)
Nova Poshta Address API
GET /api/v1/nova-poshta/areas # List areas (oblasts) GET /api/v1/nova-poshta/cities?area_ref=... # Cities in area GET /api/v1/nova-poshta/streets?city_ref=...&search=... # Search streets (min 1 char) GET /api/v1/nova-poshta/search-by-zip?zip=... # Find city by postal code (5 digits)
Example: Adding a User
POST /api/v1/properties/1/users
Content-Type: application/json
Authorization: Bearer <token>
{
"user_id": 5,
"role_id": 12
}
Example Response
{
"message": "User added successfully",
"data": {
"id": 3,
"user_id": 5,
"email": "[email protected]",
"name": "John Smith",
"role": {
"id": 12,
"code": "PROPERTY_TENANT",
"name_key": "role.property_tenant"
},
"created_at": "2026-01-05T14:30:00+00:00"
}
}
Example: Property Response
{
"id": 1,
"name": "My Apartment",
"description": "Apartment in the city center",
"color": "var(--color-primary)",
"property_type": {
"id": 2,
"code": "APARTMENT",
"name_key": "property_type.apartment.name"
},
"address": {
"area_ref": "71508128-9b87-11de-822f-000c2965ae0e",
"area_name": "Kyiv Oblast",
"city_ref": "e221d627-391c-11dd-90d9-001a92567626",
"city_name": "Kyiv",
"street_ref": "18e2ffc8-d68d-11e3-9937-003048d2b473",
"street_name": "Khreschatyk",
"building_number": "1A",
"apartment_number": "42",
"full_address": "Kyiv Oblast, Kyiv, Khreschatyk, bld. 1A, apt. 42"
},
"living_area": "45.50",
"total_area": "57.80",
"latitude": "50.4500336",
"longitude": "30.5241361",
"descriptions": [
{"locale": "en", "description": "<p>Spacious apartment in the city center...</p>"},
{"locale": "de", "description": "<p>Geräumige Wohnung im Stadtzentrum...</p>"}
],
"user_role": "PROPERTY_LANDLORD",
"users": [
{
"id": 1,
"user_id": 2,
"email": "[email protected]",
"name": "Property Owner",
"role": {"id": 10, "code": "PROPERTY_LANDLORD", "name_key": "role.property_landlord"},
"created_at": "2026-01-05T12:00:00+00:00"
}
],
"created_at": "2026-01-05T12:00:00+00:00",
"updated_at": "2026-01-05T14:30:00+00:00"
}
Multilingual Descriptions
Property descriptions can be translated to multiple languages. The main description is stored on the Property entity, translations are stored in PropertyDescription entity (one per locale).
- Entity: PropertyDescription (property_id + locale + HTML description)
- Supported locales: uk, en, ru, pl, de
- AI translation: Grok AI translates HTML description preserving tags. Available via API and in the property form.
- Form UX: Translation editors appear when main description has 20+ characters. Each language has a WYSIWYG editor + AI translate button.
Save translation example
POST /api/v1/properties/1/descriptions
Content-Type: application/json
Authorization: Bearer <token>
{
"locale": "en",
"description": "<p>Spacious apartment in the city center with a great view.</p>"
}
AI translate example
POST /api/v1/properties/1/descriptions/translate
Content-Type: application/json
Authorization: Bearer <token>
{
"target_locale": "de",
"source_html": "<p>Простора квартира в центрі міста.</p>"
}
// Response:
{
"html": "<p>Geräumige Wohnung im Stadtzentrum.</p>",
"locale": "de"
}
Property Data Values (Characteristics)
Each property can have additional characteristics such as room count, floor number, building type, etc. These values are stored in PropertyDataValue entity and linked to PropertyDataType.
Data Structure
- PropertyDataType: Defines the characteristic type (code, name, data type, group, unit, icon)
- PropertyDataValue: Stores the actual value for a property + data type combination
Data Type Groups
Building characteristics: floor count, year built, wall material, etc.
Apartment: rooms, area, floor, layout, condition, etc.
Infrastructure: elevators, distance to metro, schools, etc.
Utilities: heating, gas, water, electricity, internet, etc.
Security: alarm, video surveillance, concierge, etc.
Parking: type, spaces count, garage, etc.
Land: area, purpose, category, soil type, etc.
Other: furniture, appliances, pets allowed, etc.
Value Types
| Type | Description | Example |
|---|---|---|
bool |
Boolean value | 0, 1, true, false, yes, no |
int |
Integer with min/max constraints | 3, 25, 2024 |
float |
Decimal number with min/max constraints | 45.5, 2.8 |
string |
Text, often with allowed values list | brick, panoramic, euro_repair |
Property Data Values API
GET /api/v1/properties/{id}/data-values # List all values
GET /api/v1/properties/{id}/data-values/grouped # Values grouped by category
GET /api/v1/properties/{id}/data-values/{code} # Get single value by code
POST /api/v1/properties/{id}/data-values # Set/update a value
PUT /api/v1/properties/{id}/data-values/batch # Batch update multiple values
DELETE /api/v1/properties/{id}/data-values/{code} # Delete a value
Property Data Types API (Reference)
GET /api/v1/property-data-types # List all active types
GET /api/v1/property-data-types/grouped # Types grouped by category
GET /api/v1/property-data-types/{code} # Get type by code
GET /api/v1/property-data-types/meta/groups # List available groups
GET /api/v1/property-data-types/meta/data-types # List available data types
Example: Set a Data Value
POST /api/v1/properties/1/data-values
Content-Type: application/json
Authorization: Bearer <token>
{
"code": "ROOM_COUNT",
"value": "3"
}
Example Response
{
"message": "Value set successfully",
"data": {
"id": 42,
"code": "ROOM_COUNT",
"name_key": "property_data_type.room_count.name",
"data_type": "int",
"group_code": "apartment",
"value": "3",
"formatted_value": "3",
"unit": null,
"icon_url": "https://s3.example.com/property_data_type/room_count.svg",
"created_at": "2026-01-17T12:00:00",
"updated_at": "2026-01-17T12:00:00"
}
}
Example: Batch Update Values
PUT /api/v1/properties/1/data-values/batch
Content-Type: application/json
Authorization: Bearer <token>
{
"values": {
"ROOM_COUNT": "3",
"FLOOR_NUMBER": "5",
"HAS_BALCONY": "1",
"BUILDING_TYPE": "brick",
"WINDOW_VIEW": "park",
"APARTMENT_CONDITION": ""
}
}
Example Response
{
"message": "Values updated successfully",
"updated": 5,
"removed": 1,
"errors": []
}
UI Integration
Property data values are displayed in:
- Property form: Collapsible section with grouped inputs for setting values
- Property view page: Grouped display of all set values with icons
- Property list: Icons preview of first 8 values in property cards
Validation
Values are validated according to their data type:
- bool: Must be 0, 1, true, false, yes, or no
- int: Must be integer within defined min/max range (e.g., ROOM_COUNT: 1-30)
- float: Must be numeric within defined min/max range (e.g., CEILING_HEIGHT: 1.5-10.0)
- string: Must match allowed values if defined (e.g., BUILDING_TYPE: panel, brick, monolith, etc.)
Swagger / OpenAPI
Full API documentation is available in Swagger UI: /api/v1/doc
- 03. Properties / Data Values - Property characteristics CRUD API
- 05. References / Property Data Types - Reference data for property data types