Skip to content

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 ​

json
{
  "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. null if no subtype is assigned. Use GET /api/listings/subtypes to 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:SS format.
  • 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:SS format.
  • date_updated (string): The date and time the listing was last updated in YYYY-MM-DD HH:MM:SS format.

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-DD format.
  • 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_url below.
  • 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-DD format.
  • 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-DD format.
  • 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.
  • 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 null if 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 image URL if no thumbnail was generated.
  • panorama_tour_url (string, nullable): Auto-generated link to the built-in 360° photo viewer built from panorama_photos. null if the listing has no panoramic photos. Not related to virtual_tour_url above, 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 to 1.
    • 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. Use GET /api/listings/subtypes to 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 in YYYY-MM-DD HH:MM:SS format, or null for no lower limit.
      • max (string): The maximum date in YYYY-MM-DD HH:MM:SS format, or null for no upper limit.

Example Body ​

json
{
  "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 ​

json
{
  "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 ​

json
{
  "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 of residential, commercial, land, other.
  • availability (string): One of sale, 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 chosen category — see the subcategory list in the Object section above.
  • subtype (int): An ID from GET /api/listings/subtypes. Requires subcategory to be set, and must belong to it.
  • price (int)
  • size (number): Square meters.
  • price_per_sqm (number): If omitted and both price and size are 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 as null) when category is land.
  • property_condition (string): One of under_construction, new, renovated, good, average, needs_renovation, unfinished. Not applicable when category is land.
  • source_id (int): An ID from GET /api/listings/sources.
  • title / description (string): Saved as a listings_translations row. Requires language_id, or defaults to the account's default language.
  • language_id (int): Only used together with title/description.
  • notes (string): Internal notes.
  • tags (array of integers): IDs from GET /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 chosen category.
  • positioning (array of strings): Any of is_corner, is_front_facing, is_side_facing, is_through, is_interior, is_three_sided, is_four_sided.
  • flooring (array of strings): Any of tile, marble, wood, parquet, laminate, carpet, industrial, concrete, stone, epoxy_resin, cement_screed, plastic, vinyl, ceramic_tile, mosaic, granite.
  • view (array of strings): Any of sea, 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/3 respectively), and must sit inside the level above it — area_level2's parent must be area_level1, and area_level3's parent must be area_level2. Giving a deeper level without the shallower one (e.g. area_level2 with no area_level1) is rejected. area_level1 alone 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 of real, fake, none.
  • details (object): Extra property details (listings_details). All keys optional:
    • wcs, living_rooms, kitchens, master_bedrooms (int)
    • assignment (string): One of none, 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 of individual, autonomous, central, none.
    • heating_source (string): One of oil, natural_gas, gas, ac, heatpump, wood, pellet, fan_coil, geothermal_energy, stove, convection_heater, storage_heater, teleheating, other.
    • frames (string): One of aluminum, wood, synthetic, pvc.
    • frames_glass (string): One of single, double, triple.
    • parking_open_sheltered, parking_open_unsheltered, parking_garage, parking_total (int)
    • construction_type (string): One of concrete, wood, metal, prefab, portable, stone.
    • year_renovated (int)
    • land_size (number)
    • garden (string): One of shared, private, roof_garden.
    • zoning (string): One of residential, unzoned, commercial, industrial, light_industrial, agricultural, tourist, archaeological, forest, protected, redevelopment, mixed.
    • land_use (string): One of exclusive_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 of e, ew, n, ne, w, nw, s, se, sw.
    • energy_class (string): One of app, 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 of flat, sloped, amphitheatrical.
    • planning_status (string): One of within, outside, pending.
    • access_type (string): One of road, dirt_road, sea, pedestrian, no_access.
    • shortterm_unit (string): One of per_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 ​

json
{
  "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_message describing the problem.

Example Response ​

json
{
  "status": 200,
  "created_id": 121
}

Example Error Response ​

json
{
  "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, and view each 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 category and availability), except created_by.
Notes on partial semantics ​
  • price_per_sqm is recalculated automatically whenever price or size changes and price_per_sqm itself is not explicitly included in the same request.
  • location, details, and extras are 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 as null (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 editing area_level2 alone still fails if it doesn't belong to the listing's existing area_level1.
  • notes replaces the listing's single notes entry; sending an empty string removes it.
  • title/description are merged per language_id (or the account default language if omitted) — sending only title leaves that language's description untouched, and vice versa.
  • Unlike Create listing, switching category to/from land does 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 ​

json
{
  "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_message describing the problem.
  • 404 Not Found: Returned when no listing exists with the given id.

Example Response ​

json
{
  "status": 200,
  "updated_id": 121
}

Example Error Response ​

json
{
  "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:

  1. The image is resized to fit within listings_max_resize pixels (default 1920, account setting; never upscaled).
  2. JPEG photos have their EXIF rotation corrected automatically.
  3. The result is re-encoded as a JPEG (quality 90) and uploaded as original_image.
  4. 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. A data:image/...;base64, prefix is accepted and stripped automatically if present.

Example Body (URLs) ​

json
{
  "photos": [
    "https://example.com/photos/apartment-1.jpg",
    { "url": "https://example.com/photos/apartment-2.jpg" }
  ]
}

Example Body (raw data) ​

json
{
  "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 success flag — 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 photos is missing or not an array.

Example Response ​

json
{
  "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 url
  • Could not download photo
  • Invalid base64 image data
  • Each 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 dimensions
  • Image content does not match its detected type
  • Could not decode image
  • Failed 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 ​

json
{
  "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 ​

json
{
  "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 ​

json
{
  "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 ​

json
{
  "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-DD format. (E.g. 2025-10-18)
  • datetime: Datetime in YYYY-MM-DD HH:MM:SS format. (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_id values.
  • contact: Another contact's id.
  • contact_multi: An array of multiple contact ids.

Last updated on September 16th, 2026.