Listings
The Listing object represents a property listing in the EstatePrime system. This object is returned in JSON format, containing all available values for a listing including its details, location, photos, translations, and related contacts.
Object
The Listing object represents an individual property listing. Below are the fields included in a Listing object:
Example
{
"id": 120,
"store_id": 2,
"code": "RES-00120",
"category": "residential",
"subcategory": "apartment",
"availability": "sale",
"price": 180000,
"price_per_sqm": 2000.00,
"size": 90.00,
"floor": 2,
"levels": 1,
"rooms": 3,
"bathrooms": 1,
"year_built": 2005,
"property_condition": "good",
"status": "active",
"status_date": "2025-01-10 09:00:00",
"source_id": 1,
"created_by": 3,
"date_created": "2025-01-10 09:00:00",
"date_updated": "2025-03-05 14:30:00",
"wcs": 1,
"living_rooms": 1,
"kitchens": 1,
"master_bedrooms": 1,
"assignment": "exclusive",
"assignment_fee": 2.50,
"assignment_fee_type": "percent",
"assignment_expires": "2025-12-31",
"total_building_floors": 6,
"heating_type": "autonomous",
"heating_source": "natural_gas",
"frames": "aluminum",
"frames_glass": "double",
"parking_open_sheltered": 0,
"parking_open_unsheltered": 0,
"parking_garage": 1,
"parking_total": 1,
"construction_type": "concrete",
"year_renovated": null,
"land_size": null,
"garden": null,
"zoning": null,
"coverage_ratio": null,
"build_ratio": null,
"max_height": null,
"youtube_url": null,
"virtual_tour_url": null,
"panorama_tour_url": "https://app.example.com/virtual-tour/120/4023b130a5d8e44e9cd3d42458362de4",
"distance_sea": null,
"distance_airport": null,
"distance_city": null,
"distance_market": null,
"monthly_maintenance": 80,
"tenant_contact_id": null,
"available_from": null,
"has_keys": true,
"is_rented": false,
"has_hidden_price": false,
"orientation": "se",
"energy_class": "b",
"is_negotiable": true,
"frontage_length": null,
"land_slope": null,
"access_type": null,
"floor_configuration": null,
"shortterm_unit": null,
"shortterm_min_stay": null,
"shortterm_max_guests": null,
"auction_code": null,
"auction_date": null,
"auction_url": null,
"notes": "Owner prefers serious buyers only.",
"location": {
"area_level1": {
"id": 5,
"name_el": "Θεσσαλονίκη",
"name_en": "Thessaloniki",
"full_name_el": "Θεσσαλονίκη",
"full_name_en": "Thessaloniki"
},
"area_level2": {
"id": 12,
"name_el": "Δήμος Θεσσαλονίκης",
"name_en": "Municipality of Thessaloniki",
"full_name_el": "Θεσσαλονίκη > Δήμος Θεσσαλονίκης",
"full_name_en": "Thessaloniki > Municipality of Thessaloniki"
},
"area_level3": null,
"postal_code": "54623",
"display_address": true,
"show_circle_on_map": false,
"address_el": "Τσιμισκή 15",
"fake_address_el": null,
"longitude": 22.9444,
"latitude": 40.6401,
"fake_longitude": null,
"fake_latitude": null
},
"features": ["elevator", "storage", "alarm"],
"positioning": ["corner", "seafront"],
"view": ["sea_view", "mountain_view"],
"flooring": ["marble", "tile"],
"tags": [2, 7],
"contacts": [23, 45],
"users": [3, 8],
"photos": [
{
"original_image": "https://files.example.com/listings/120/photo1.jpg",
"watermark_image": "https://files.example.com/listings/120/photo1_wm.jpg"
},
{
"original_image": "https://files.example.com/listings/120/photo2.jpg",
"watermark_image": null
}
],
"panorama_photos": [
{
"image": "https://files.example.com/listings/virtual_tours/6a9cfcfb932c11788673275.jpg",
"thumb": "https://files.example.com/listings/virtual_tours/6a9cfcfb932c11788673275_thumb.jpg"
}
],
"translations": [
{
"language_id": 1,
"title": "Apartment in Thessaloniki",
"description": "Spacious 3-bedroom apartment in the city center."
},
{
"language_id": 2,
"title": "Διαμέρισμα στη Θεσσαλονίκη",
"description": "Ευρύχωρο τριάρι στο κέντρο της πόλης."
}
]
}Core fields
- id (int): The system id of the listing.
- store_id (int): The ID of the office/store that owns the listing.
- code (string, nullable): The human-readable listing code (e.g.,
RES-00120). - category (string): The property category. Possible values:
residential,commercial,land,other. - subcategory (string): The property subcategory. Possible values:
apartment,maisonette,detached,villa,loft,residential_building,apartment_complex,farmhouse,houseboat,other_residential,office,store,warehouse,hotel,commercial_building,hall,industrial_space,craft_space,other_commercial,plot,parcel,island,parking,business,air,other. - subtype (int, nullable): The ID of the optional specific subtype of the listing.
nullif no subtype is assigned. UseGET /api/listings/subtypesto resolve the name. - availability (string): The listing availability type. Possible values:
sale,rent,auction,shortterm. - price (int, nullable): The listing price.
- price_per_sqm (decimal, nullable): The price per square meter.
- size (decimal, nullable): The property size in square meters.
- floor (float, nullable): The floor number of the property.
- levels (int, nullable): The number of levels/floors the property spans.
- rooms (int, nullable): The number of rooms/bedrooms.
- bathrooms (int, nullable): The number of bathrooms.
- year_built (int, nullable): The year the property was built.
- property_condition (string, nullable): The condition of the property. Possible values:
under_construction,new,renovated,good,average,needs_renovation,unfinished. - status (string): The listing status. Possible values:
draft,pending,active,inactive,archived,deleted. - status_date (string, nullable): The date and time the status was last changed in
YYYY-MM-DD HH:MM:SSformat. - source_id (int, nullable): The ID of the source from which the listing originated.
- created_by (int): The user ID of the user who created the listing.
- date_created (string): The date and time the listing was created in
YYYY-MM-DD HH:MM:SSformat. - date_updated (string): The date and time the listing was last updated in
YYYY-MM-DD HH:MM:SSformat.
Detail fields (from listings_details)
- wcs (int, nullable): Number of WCs.
- living_rooms (int, nullable): Number of living rooms.
- kitchens (int, nullable): Number of kitchens.
- master_bedrooms (int, nullable): Number of master bedrooms.
- assignment (string, nullable): Assignment type. Possible values:
none,simple,exclusive. - assignment_fee (decimal, nullable): Assignment fee amount.
- assignment_fee_type (string, nullable): Whether the fee is a fixed amount or percentage. Possible values:
fixed,percent. - assignment_expires (string, nullable): Assignment expiry date in
YYYY-MM-DDformat. - total_building_floors (int, nullable): Total number of floors in the building.
- heating_type (string, nullable): Heating system type. Possible values:
individual,autonomous,central,none. - heating_source (string, nullable): Heating energy source. Possible values:
oil,natural_gas,gas,ac,heatpump,wood,pellet,fan_coil,geothermal_energy,stove,convection_heater,storage_heater,teleheating,other. - frames (string, nullable): Window frame material. Possible values:
aluminum,wood,synthetic,pvc. - frames_glass (string, nullable): Window glazing type. Possible values:
single,double,triple. - parking_open_sheltered (int, nullable): Number of open sheltered parking spaces.
- parking_open_unsheltered (int, nullable): Number of open unsheltered parking spaces.
- parking_garage (int, nullable): Number of garage parking spaces.
- parking_total (int, nullable): Total parking spaces.
- construction_type (string, nullable): Construction material. Possible values:
concrete,wood,metal,prefab,portable,stone. - year_renovated (int, nullable): Year of last renovation.
- land_size (decimal, nullable): Land/plot size in square meters.
- garden (string, nullable): Garden type. Possible values:
shared,private,roof_garden. - zoning (string, nullable): Zoning classification. Possible values:
residential,unzoned,commercial,industrial,light_industrial,agricultural,tourist,archaeological,forest,protected,redevelopment,mixed. - coverage_ratio (decimal, nullable): Coverage ratio percentage.
- build_ratio (decimal, nullable): Build ratio (floor area ratio).
- max_height (decimal, nullable): Maximum permitted building height in meters.
Extra fields (from listings_extras)
- youtube_url (string, nullable): A YouTube video URL for the listing.
- virtual_tour_url (string, nullable): A manually entered virtual tour URL (e.g. an external tool such as Matterport or Kuula). Not related to
panorama_tour_urlbelow. - distance_sea (int, nullable): Distance to the sea in meters.
- distance_airport (int, nullable): Distance to the airport in meters.
- distance_city (int, nullable): Distance to the city center in meters.
- distance_market (int, nullable): Distance to a market/supermarket in meters.
- monthly_maintenance (int, nullable): Monthly maintenance fee.
- tenant_contact_id (int, nullable): Contact ID of the current tenant (for rented properties).
- available_from (string, nullable): Date the property becomes available in
YYYY-MM-DDformat. - has_keys (boolean): Whether the agency holds the property keys.
- is_rented (boolean): Whether the property is currently rented.
- has_hidden_price (boolean): Whether the price is hidden on portals.
- orientation (string, nullable): Property orientation. Possible values:
e,ew,n,ne,w,nw,s,se,sw. - energy_class (string, nullable): Energy efficiency class. Possible values:
ap,a,bp,b,c,d,e,f,g. - is_negotiable (boolean): Whether the price is negotiable.
- frontage_length (decimal, nullable): Street frontage length in meters.
- land_slope (string, nullable): Land slope type. Possible values:
flat,sloped,amphitheatrical. - access_type (string, nullable): Property access type. Possible values:
road,dirt_road,sea,pedestrian,no_access. - floor_configuration (array, nullable): Array of objects describing multi-floor configuration details.
- shortterm_unit (string, nullable): Short-term rental pricing unit. Possible values:
per_day,per_week,per_month,per_season,per_year. - shortterm_min_stay (int, nullable): Minimum stay duration for short-term rentals.
- shortterm_max_guests (int, nullable): Maximum number of guests for short-term rentals.
- auction_code (string, nullable): Auction reference code.
- auction_date (string, nullable): Auction date in
YYYY-MM-DDformat. - auction_url (string, nullable): URL to the auction listing.
Relation fields
- notes (string, nullable): Internal notes about the listing.
- location (object): Location data. Contains the following fields:
- area_level1 (object, nullable): Region data:
id,name_el,name_en,full_name_el,full_name_en. - area_level2 (object, nullable): Municipality/district data: same fields as
area_level1. - area_level3 (object, nullable): Neighbourhood data: same fields as
area_level1. - postal_code (string, nullable): The postal code.
- display_address (boolean): Whether to display the full address publicly.
- show_circle_on_map (boolean): Whether to show a privacy circle instead of an exact pin on the map.
- address_el (string, nullable): The street address in Greek.
- fake_address_el (string, nullable): A fake/privacy address used publicly when exact address is hidden.
- longitude (float, nullable): Exact GPS longitude coordinate.
- latitude (float, nullable): Exact GPS latitude coordinate.
- fake_longitude (float, nullable): Privacy longitude used on public maps.
- fake_latitude (float, nullable): Privacy latitude used on public maps.
- area_level1 (object, nullable): Region data:
- features (array of strings): A list of general feature keys (e.g.,
elevator,storage,alarm). - positioning (array of strings): A list of positioning characteristic keys (e.g.,
corner,seafront). - view (array of strings): A list of view characteristic keys (e.g.,
sea_view,mountain_view). - flooring (array of strings): A list of flooring material keys (e.g.,
marble,tile). - tags (array of integers): A list of tag IDs associated with the listing.
- contacts (array of integers): A list of contact IDs (owners) associated with the listing.
- users (array of integers): A list of user IDs (agents) responsible for the listing.
- photos (array of objects): A list of listing photos. Each object includes:
- original_image (string, nullable): URL of the original photo.
- watermark_image (string, nullable): URL of the watermarked version, or
nullif not generated.
- panorama_photos (array of objects): A list of 360° panoramic photos uploaded for the listing's virtual tour. Each object includes:
- image (string): URL of the full-size panoramic photo.
- thumb (string): URL of a thumbnail-sized version, used for the photo switcher in the viewer. Falls back to the full-size
imageURL if no thumbnail was generated.
- panorama_tour_url (string, nullable): Auto-generated link to the built-in 360° photo viewer built from
panorama_photos.nullif the listing has no panoramic photos. Not related tovirtual_tour_urlabove, which is a manually entered link. - translations (array of objects): Listing title and description in each configured language. Each object includes:
- language_id (int): The language ID.
- title (string, nullable): The listing title in this language.
- description (string, nullable): The listing description in this language.
Get listings
/api/listings (GET)
Fetch a paginated list of listings.
Request
- Method:
GET - Headers: Include authentication headers as described in the Authentication section.
- Body: JSON object with the following optional parameters:
page(int): The page number to fetch. Defaults to1.search(string): Search by listing code or ID (exact match).availability(string or array): Filter by availability type. Accepted values:sale,rent,auction,shortterm. Pass a single string or an array for multiple values.category(string or array): Filter by property category. Accepted values:residential,commercial,land,other. Pass a single string or an array for multiple values.subcategory(string or array): Filter by property subcategory (e.g.apartment,office,plot). Pass a single string or an array for multiple values.subtype(int or array): Filter by subtype ID. Pass a single integer or an array of integers. UseGET /api/listings/subtypesto retrieve available subtype IDs.status(string or array): Filter by listing status. Accepted values:draft,pending,active,inactive,archived,deleted. Pass a single string or an array for multiple values.date_created(object): Filter by creation date range. Must include:min(string): The minimum date inYYYY-MM-DD HH:MM:SSformat, ornullfor no lower limit.max(string): The maximum date inYYYY-MM-DD HH:MM:SSformat, ornullfor no upper limit.
Example Body
{
"page": 1,
"availability": ["sale", "auction"],
"category": "residential",
"status": "active",
"date_created": {
"min": "2025-01-01 00:00:00",
"max": null
}
}Response
- 200 OK: Returns a JSON array of listing objects.
Example Response
{
"status": 200,
"page": 1,
"total_pages": 14,
"results_per_page": 50,
"total_results": 692,
"data": [
{
"id": 120,
"store_id": 2,
"code": "RES-00120",
"category": "residential",
"subcategory": "apartment",
"availability": "sale",
"price": 180000,
"size": 90.00,
"status": "active",
"date_created": "2025-01-10 09:00:00",
"date_updated": "2025-03-05 14:30:00",
"location": { },
"photos": [ ],
"contacts": [23, 45],
"users": [3, 8],
"tags": [2, 7],
"translations": [ ]
//Rest of the fields...
}
//Rest of the data...
]
}Get single listing
/api/listings/{id} (GET)
Get a single listing by its id.
Request
- Method:
GET - Headers: Include authentication headers.
- Path Params: The listing id to be fetched.
Example Response
{
"status": 200,
"data": {
"id": 120,
"store_id": 2,
"code": "RES-00120",
"category": "residential",
"subcategory": "apartment",
"availability": "sale",
"price": 180000,
"price_per_sqm": 2000.00,
"size": 90.00,
"floor": 2,
"rooms": 3,
"bathrooms": 1,
"year_built": 2005,
"property_condition": "good",
"status": "active",
"date_created": "2025-01-10 09:00:00",
"date_updated": "2025-03-05 14:30:00",
"location": {
"area_level1": {
"id": 5,
"name_el": "Θεσσαλονίκη",
"name_en": "Thessaloniki",
"full_name_el": "Θεσσαλονίκη",
"full_name_en": "Thessaloniki"
},
"area_level2": { },
"area_level3": null,
"postal_code": "54623",
"address_el": "Τσιμισκή 15",
"longitude": 22.9444,
"latitude": 40.6401
},
"features": ["elevator", "storage"],
"tags": [2, 7],
"contacts": [23, 45],
"users": [3, 8],
"photos": [
{
"original_image": "https://files.example.com/listings/120/photo1.jpg",
"watermark_image": "https://files.example.com/listings/120/photo1_wm.jpg"
}
],
"panorama_photos": [],
"panorama_tour_url": null,
"translations": [
{
"language_id": 1,
"title": "Apartment in Thessaloniki",
"description": "Spacious 3-bedroom apartment in the city center."
}
]
//Rest of the fields...
}
}Response
- 200 OK: Returns the JSON object of the listing.
Create listing
/api/listings (POST)
Create a new listing. Every listing created through the API is inserted with status = "draft", exactly like the app's own autosave before an agent finishes filling in the form. Draft listings have no code assigned; a code is generated later, when the listing is moved out of draft in the app. Use Update listing afterwards to change or add to any field.
Photos are not part of this request — see Upload listing photos below for a separate call once you have the listing id.
Request
- Method:
POST - Headers: Include authentication headers.
- Body: JSON object with the listing details to be inserted. See parameters below.
Required fields
category(string): One ofresidential,commercial,land,other.availability(string): One ofsale,rent,auction,shortterm.store_id(int): An existing office/store ID.created_by(int): An existing user ID to record as the creator.users(array of integers): At least one existing user ID to assign as an agent on the listing.
Optional fields
subcategory(string): Must belong to the chosencategory— see the subcategory list in the Object section above.subtype(int): An ID fromGET /api/listings/subtypes. Requiressubcategoryto be set, and must belong to it.price(int)size(number): Square meters.price_per_sqm(number): If omitted and bothpriceandsizeare given, it is calculated automatically (price / size, rounded to 2 decimals).floor(number),levels(int),rooms(int),bathrooms(int),year_built(int) — all ignored (stored asnull) whencategoryisland.property_condition(string): One ofunder_construction,new,renovated,good,average,needs_renovation,unfinished. Not applicable whencategoryisland.source_id(int): An ID fromGET /api/listings/sources.title/description(string): Saved as alistings_translationsrow. Requireslanguage_id, or defaults to the account's default language.language_id(int): Only used together withtitle/description.notes(string): Internal notes.tags(array of integers): IDs fromGET /api/listings/tags.contacts(array of integers): Owner contact IDs.features(array of strings): General feature keys, validated against the same list used across the app (e.g.has_elevator,has_parking,has_storage_room,is_furnished,has_private_pool,is_penthouse,golden_visa, etc.), and checked against the chosencategory.positioning(array of strings): Any ofis_corner,is_front_facing,is_side_facing,is_through,is_interior,is_three_sided,is_four_sided.flooring(array of strings): Any oftile,marble,wood,parquet,laminate,carpet,industrial,concrete,stone,epoxy_resin,cement_screed,plastic,vinyl,ceramic_tile,mosaic,granite.view(array of strings): Any ofsea,mountain,park,openspace,acropolis,city,lake,river,forest,panoramic.location(object): All keys optional.area_level1/area_level2/area_level3(int): Location IDs. Each must actually be a location at that level (level = 1/2/3respectively), and must sit inside the level above it —area_level2's parent must bearea_level1, andarea_level3's parent must bearea_level2. Giving a deeper level without the shallower one (e.g.area_level2with noarea_level1) is rejected.area_level1alone is fine on its own.postal_code(string)address(string): The Greek street address. An English transliteration is generated automatically.latitude/longitude(number): Defaults to(0, 0)when omitted.display_address(string): One ofreal,fake,none.
details(object): Extra property details (listings_details). All keys optional:wcs,living_rooms,kitchens,master_bedrooms(int)assignment(string): One ofnone,simple,exclusive.assignment_fee(number),assignment_fee_type(string:fixed,percent),assignment_expires(string,YYYY-MM-DD)total_building_floors(int)heating_type(string): One ofindividual,autonomous,central,none.heating_source(string): One ofoil,natural_gas,gas,ac,heatpump,wood,pellet,fan_coil,geothermal_energy,stove,convection_heater,storage_heater,teleheating,other.frames(string): One ofaluminum,wood,synthetic,pvc.frames_glass(string): One ofsingle,double,triple.parking_open_sheltered,parking_open_unsheltered,parking_garage,parking_total(int)construction_type(string): One ofconcrete,wood,metal,prefab,portable,stone.year_renovated(int)land_size(number)garden(string): One ofshared,private,roof_garden.zoning(string): One ofresidential,unzoned,commercial,industrial,light_industrial,agricultural,tourist,archaeological,forest,protected,redevelopment,mixed.land_use(string): One ofexclusive_residential,general_residential,commercial,industrial,tourism,agricultural,pasture,forest,mixed_use,other.coverage_ratio,build_ratio,max_height(number)thermal_break(boolean)completion_year(int)
extras(object): Additional property attributes (listings_extras). All keys optional:youtube_url,virtual_tour_url(string)distance_sea,distance_airport,distance_city,distance_market(int, meters)monthly_maintenance(int)tenant_contact_id(int): An existing contact ID.available_from(string,YYYY-MM-DD)has_keys,is_rented,has_hidden_price,is_negotiable(boolean)orientation(string): One ofe,ew,n,ne,w,nw,s,se,sw.energy_class(string): One ofapp,ap,a,bp,b,c,d,e,f,g,pending.min_price(int)frontage_length,shop_window_length,balcony_size,storage_size,garden_size,rooftop_size(number)land_slope(string): One offlat,sloped,amphitheatrical.planning_status(string): One ofwithin,outside,pending.access_type(string): One ofroad,dirt_road,sea,pedestrian,no_access.shortterm_unit(string): One ofper_day,per_week,per_month,per_season,per_year.shortterm_min_stay,shortterm_max_guests(int)auction_code,auction_url(string),auction_date(string,YYYY-MM-DD)yield(number, %),rating(int)project_unit_name(string)lease_expiry_date(string,YYYY-MM-DD)
Example Body
{
"category": "residential",
"subcategory": "apartment",
"availability": "sale",
"store_id": 2,
"created_by": 3,
"users": [3, 8],
"price": 180000,
"size": 90,
"rooms": 3,
"bathrooms": 1,
"year_built": 2005,
"property_condition": "good",
"title": "Apartment in Thessaloniki",
"description": "Spacious 3-bedroom apartment in the city center.",
"contacts": [23],
"tags": [2],
"features": ["has_elevator", "has_storage_room"],
"location": {
"area_level1": 5,
"area_level2": 12,
"address": "Τσιμισκή 15",
"latitude": 40.6401,
"longitude": 22.9444
},
"details": {
"heating_type": "autonomous",
"heating_source": "natural_gas",
"parking_total": 1,
"construction_type": "concrete"
},
"extras": {
"is_negotiable": true,
"orientation": "se",
"energy_class": "b",
"has_keys": true
}
}Response
- 200 OK: Returns the id of the newly created listing. Fetch the full object with
GET /api/listings/{id}. - 400 Bad Request: Returned when a required field is missing or a value fails validation (e.g. an unknown location/contact/tag/subtype ID, or an invalid enum value). The response body has
error_messagedescribing the problem.
Example Response
{
"status": 200,
"created_id": 121
}Example Error Response
{
"status": 400,
"error_message": "Missing store_id"
}Update listing
/api/listings/{id} (PUT)
Edit an existing listing. This is a strict partial update — whatever field you include in the JSON body is the only thing that changes. Everything you leave out is left exactly as it was, including fields nested inside location, details, and extras: only the keys you actually send inside those objects are touched, the rest of that object's existing values survive untouched. created_by cannot be changed and is ignored if sent.
Exception — list-type fields fully replace.
tags,contacts,users,features,positioning,flooring, andvieweach hold a list. Sending one of these keys replaces the whole list with what you sent (not merged/appended). Leaving the key out entirely keeps the existing list untouched. To add one tag to a listing that already has some, send the full set of tag IDs (existing + new).
Request
- Method:
PUT - Headers: Include authentication headers.
- Path Params: The listing id to be updated.
- Body: JSON object with only the fields to change. Accepts the same fields as Create listing (all optional here, including
categoryandavailability), exceptcreated_by.
Notes on partial semantics
price_per_sqmis recalculated automatically wheneverpriceorsizechanges andprice_per_sqmitself is not explicitly included in the same request.location,details, andextrasare merged key by key onto the existing row (or a new row is created if the listing never had one) — a key not present in the object you send keeps its previous value. To clear a field, send it asnull(or an empty string, for text fields).- If you change any of
location.area_level1/area_level2/area_level3, the parent-chain check runs against the final result — the value(s) you sent merged with whatever the listing already had at the level(s) you didn't touch. So editingarea_level2alone still fails if it doesn't belong to the listing's existingarea_level1. notesreplaces the listing's single notes entry; sending an empty string removes it.title/descriptionare merged perlanguage_id(or the account default language if omitted) — sending onlytitleleaves that language'sdescriptionuntouched, and vice versa.- Unlike Create listing, switching
categoryto/fromlanddoes not automatically clear now-irrelevant fields (e.g.rooms,heating_type) — per the "only what I send changes" rule, those are left as they were unless you clear them yourself.
Example Body
{
"price": 175000,
"extras": {
"is_negotiable": true
},
"tags": [2, 9]
}This example changes only price, extras.is_negotiable (leaving every other extras/details key untouched), and replaces the tag list — nothing else on the listing is affected.
Response
- 200 OK: Returns the id of the updated listing. Fetch the full object with
GET /api/listings/{id}. - 400 Bad Request: Returned when a value fails validation. The response body has
error_messagedescribing the problem. - 404 Not Found: Returned when no listing exists with the given id.
Example Response
{
"status": 200,
"updated_id": 121
}Example Error Response
{
"status": 404,
"error_message": "Listing not found"
}Upload listing photos
/api/listings/{id}/photos (POST)
Upload one or more photos to an existing listing, either by URL (fetched server-side) or as raw image bytes. This replicates the same processing the normal in-app upload does:
- The image is resized to fit within
listings_max_resizepixels (default1920, account setting; never upscaled). - JPEG photos have their EXIF rotation corrected automatically.
- The result is re-encoded as a JPEG (quality 90) and uploaded as
original_image. - If the listing's office has a watermark image configured and the account's watermark setting is enabled, a second copy with the watermark centered over the photo is generated and uploaded as
watermark_image. Both copies are always kept — the original is never overwritten.
Accepted formats: JPEG, PNG, GIF, WEBP. The MIME type is never taken on trust — a URL's Content-Type header, a data: URI prefix, or a filename are never used to decide the format. Every photo's actual bytes are sniffed (finfo) to determine its real type, and that result is cross-checked against what PHP's own image decoder (getimagesize) reports for the same bytes; the photo is rejected unless both agree it's one of the four supported formats. This also means a file that merely has a .jpg name or an image/jpeg header isn't good enough — it has to actually be a JPEG.
Photos already on the listing are preserved — new ones are appended, continuing the existing photo order (ordernum).
Request
- Method:
POST - Headers: Include authentication headers.
- Path Params: The listing id to upload photos to.
- Body:
photos(array, required): Each entry is one of:- a URL string — fetched server-side.
- an object
{"url": "..."}— same as above. - an object
{"data": "..."}— raw image bytes, base64-encoded. Adata:image/...;base64,prefix is accepted and stripped automatically if present.
Example Body (URLs)
{
"photos": [
"https://example.com/photos/apartment-1.jpg",
{ "url": "https://example.com/photos/apartment-2.jpg" }
]
}Example Body (raw data)
{
"photos": [
{ "data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//wAARCAABAAEDASIA..." }
]
}Response
- 200 OK: Returns one result entry per item given, in the same order, each with its own
successflag — a failure on one photo does not fail the others. - 404 Not Found: Returned when no listing exists with the given id.
- 400 Bad Request: Returned when
photosis missing or not an array.
Example Response
{
"status": 200,
"data": [
{
"url": "https://example.com/photos/apartment-1.jpg",
"success": true,
"ordernum": 1,
"original_image": "https://files.example.com/listings/121/6721a...jpg",
"watermark_image": "https://files.example.com/listings/121/6721b...jpg"
},
{
"url": "https://example.com/photos/apartment-2.jpg",
"success": false,
"error": "Unsupported or unrecognized image type: text/html"
}
]
}Possible per-photo error values
Invalid photo urlCould not download photoInvalid base64 image dataEach photo must be a URL string, or an object with "url" or "data" (base64-encoded image bytes)Unsupported or unrecognized image type: {sniffed mime}Could not read image dimensionsImage content does not match its detected typeCould not decode imageFailed to upload photo
Get listing sources
/api/listings/sources (GET)
Fetch the available listing sources.
Request
- Method:
GET - Headers: Include authentication headers.
Response
- 200 OK: Returns a JSON array of available listing sources.
Example Response
{
"status": 200,
"data": [
{
"id": 1,
"name": "Owner Direct"
},
{
"id": 2,
"name": "Agency Referral"
}
]
}Get listing tags
/api/listings/tags (GET)
Fetch the available listing tags.
Request
- Method:
GET - Headers: Include authentication headers.
Response
- 200 OK: Returns a JSON array of available listing tags.
Example Response
{
"status": 200,
"data": [
{
"id": 1,
"name": "Urgent Sale"
},
{
"id": 2,
"name": "Price Reduced"
}
]
}Get listing subtypes
/api/listings/subtypes (GET)
Fetch the available listing subtypes.
Request
- Method:
GET - Headers: Include authentication headers.
Response
- 200 OK: Returns a JSON array of available listing subtypes.
Example Response
{
"status": 200,
"data": [
{
"id": 1,
"subcategory": "apartment",
"translations": [
{ "language_id": 1, "name": "Στούντιο" },
{ "language_id": 2, "name": "Studio" }
]
},
{
"id": 2,
"subcategory": "apartment",
"translations": [
{ "language_id": 1, "name": "Πολυτελές διαμέρισμα" },
{ "language_id": 2, "name": "Luxury apartment" }
]
}
]
}Get listing custom fields
/api/listings/custom-fields (GET)
Fetch the available custom fields for listings.
Request
- Method:
GET - Headers: Include authentication headers.
Response
- 200 OK: Returns a JSON array of available custom fields for listings.
Example Response
{
"status": 200,
"data": [
{
"id": 1,
"name": "Pool",
"type": "checkbox"
},
{
"id": 2,
"name": "Condition Notes",
"type": "textarea"
},
{
"id": 3,
"name": "View Type",
"type": "select_multi",
"options": [
{
"id": 1,
"name": "Sea View"
},
{
"id": 2,
"name": "Mountain View"
}
]
}
]
}Available custom field types
- text: Text up to 255 characters.
- textarea: Text up to 2500 characters.
- wysiwyg: Text with HTML format.
- number: Integer or decimal.
- formatted_number: Integer or decimal that is formatted. E.g.
1,000,000.25. - select: Single select with options.
- select_multi: Multiple select with options.
- checkbox: Boolean.
- file: Single file. (As a URL)
- file_multi: Array of multiple files. (As URLs)
- image: Single image. (As a URL)
- image_multi: Array of multiple images. (As URLs)
- address: Address. (E.g.
Bellariastraße 6, 1010 Wien, Austria) - url: URL.
- date: Date in
YYYY-MM-DDformat. (E.g.2025-10-18) - datetime: Datetime in
YYYY-MM-DD HH:MM:SSformat. (E.g.2025-10-18 18:24:10) - currency: Integer or decimal formatted as a currency. E.g.
1,000,000.25€. - user: Application
user_id. - user_multi: An array of application
user_idvalues. - contact: Another contact's id.
- contact_multi: An array of multiple contact ids.

