Skip to main content

Payload v1

The listing object field by field — every object, type, bound and rule the API checks before anything is stored.

One JSON object describes one listing, for sale or for rent. PUT /connections/{id}/listings/{external_id} takes it as the body; POST …/batches takes { "listings": [ … ] }; POST /validate takes { "listing": … } or { "listings": [ … ] }.

A complete sale listing#

json
{
  "external_id": "REAA-12345",
  "transaction": "sale",
  "category": "apartment",
  "state": "active",
  "title": {
    "sr": "Trosoban stan, Vračar",
    "en": "Three-room flat, Vračar"
  },
  "description": {
    "sr": "Svetao trosoban stan na Vračaru, renoviran 2024, na pet minuta od Hrama Svetog Save.",
    "en": "A bright three-room flat in Vračar, renovated in 2024, five minutes from the Temple of Saint Sava."
  },
  "price": {
    "amount": 245000,
    "currency": "EUR",
    "negotiable": false
  },
  "location": {
    "place_id": "b2c0d6a4-3f1e-4d2a-9c8b-7e6f5a4b3c2d",
    "address_line": "Njegoševa 10",
    "neighbourhood": "Crveni krst",
    "lat": 44.8012,
    "lng": 20.4722
  },
  "structure": {
    "area_sqm": 78.5,
    "rooms": 3,
    "bedrooms": 2,
    "bathrooms": 1,
    "floor": 3,
    "total_floors": 5,
    "levels": 1,
    "year_built": 1968,
    "building_group": "old",
    "condition": "renovated",
    "furnished": "semi_furnished",
    "heating": "district",
    "elevator": true,
    "parking": false,
    "garage": false,
    "balcony": true,
    "terrace": false,
    "air_conditioning": true,
    "basement": false
  },
  "legal": {
    "ownership_status": "uknjizen",
    "legalization_status": "legalizovan",
    "mortgage_eligible": true,
    "mandate_attested": true,
    "exclusive": false,
    "broker_license_no": null,
    "tapija_note": null
  },
  "commission": {
    "buyer_pct": 2,
    "seller_pct": 2
  },
  "amenities": [
    "built_in_wardrobes",
    "intercom"
  ],
  "attributes": {},
  "photos": [
    {
      "url": "https://cdn.reaa.rs/listings/12345/1.jpg",
      "caption": null,
      "room_type": "living_room",
      "digest": null
    },
    {
      "url": "https://cdn.reaa.rs/listings/12345/2.jpg",
      "caption": null,
      "room_type": "kitchen",
      "digest": null
    },
    {
      "url": "https://cdn.reaa.rs/listings/12345/3.jpg",
      "caption": null,
      "room_type": "bedroom",
      "digest": null
    }
  ],
  "video_url": null,
  "virtual_tour_url": null,
  "agent": {
    "email": "milan@agencija.rs",
    "name": "Milan Petrović",
    "phone": "+381601234567"
  },
  "source": {
    "updated_at": "2026-10-12T08:00:00Z",
    "url": "https://agencija.rs/nekretnine/12345"
  },
  "digest": null
}

The rent shape is on Sale versus rent shapes.

General rules#

  • Every object is strict. An unknown key is 422 validation_failed with the detail code unknown_field at its pointer, so a typo never passes silently.
  • Strings are trimmed. An empty string is an error where a value is required and reads as absent where the field is optional. Send null for an empty URL (an empty URL string is invalid_format).
  • Text lengths count Unicode code points (an emoji is one, a combining mark is one), like the JSON Schema maxLength in the reference. Titles are also capped at 120 UTF-16 units, where an emoji counts as two — so a title of 120 characters with emoji in it can be too long.
  • external_id matches ^[A-Za-z0-9._:-]{1,64}$ and is your stable id for the listing. On a PUT it must equal the {external_id} in the path.
  • Optional fields accept null or may be left out.

Top level#

Field Type Required Rules
external_id string Yes 1–64 of A–Z a–z 0–9 . _ : -; equal to the path on PUT
transaction "sale" | "rent" Yes picks the shape
category string Yes one of the 21 categories (Serbian specifics)
state "active" | "inactive" Yes active publishes, inactive keeps the listing but not live (States)
title object Yes below
description object Yes below
price object sale only below
rent object rent only Sale versus rent shapes
location object Yes below
structure object Yes below; rentals take fewer fields
legal object Yes below; a rental's is { mandate_attested }
commission object No below
amenities string[] No at most 40 keys from GET /vocabularies
attributes object No the per-category attributes listed by GET /vocabularies
photos object[] No 0–64; below and Photos and the fetcher
video_url string | null No a public https:// URL, up to 2,048 characters
virtual_tour_url string | null No as video_url; needs the agency's plan (Mapping notes)
agent object No below
source object Yes below
house_rules object rent only {} allowed
digest string | null No up to 128 characters; your own hash, echoed back, never interpreted

title and description#

Field Required Rules
title.sr Yes 5–120 characters (and at most 120 UTF-16 units)
title.en, title.tr, title.de, title.ru No up to 120 characters (and 120 UTF-16 units)
description.sr Yes 20–8,000 characters
description.en, .tr, .de, .ru No up to 8,000 characters

The Serbian text is required: Novi Kvadrat's source language is Serbian.

price (sale)#

Field Type Required Rules
amount number Yes greater than 0
currency "EUR" | "RSD" Yes
negotiable boolean No

We store the price in RSD too, derived as amount × 117 (rounded) for EUR. That value must fit our integer column, so a sale price is refused with too_big at /price/amount when it would exceed 2,147,483,647 RSD — about 18,354,561 EUR.

location#

Field Type Required Rules
place_id uuid Yes a city or municipality id from GET /places; unknown → unknown_place
address_line string Yes 3–200 characters
neighbourhood string No up to 120 characters, free text
lat number No −90 to 90
lng number No −180 to 180

structure#

Field Type Rules
area_sqm number greater than 0, at most 99,999.99
rooms number sale only; 0–99
bedrooms, bathrooms number 0–99
floor integer −5 to 60
total_floors integer sale only; 0–60
levels integer 1–6
year_built integer sale only; 1800–2035
building_group "new" | "old" sale only
condition lux, renovated, original, renovation_required sale only
furnished furnished, semi_furnished, unfurnished
heating string one of the heating values (Serbian specifics)
elevator, parking, balcony, terrace, air_conditioning boolean
garage, basement boolean sale only

Every structure field is optional in the schema; what a category needs before it can publish is checked when the listing is imported (missing_required, States).

Field Type Required Rules
mandate_attested boolean Yes must be true when state is active: you confirm a signed brokerage contract for this listing (Legal)
ownership_status uknjizen, nije_uknjizen, u_postupku No sale only
legalization_status legalizovan, u_postupku, nelegalizovan No sale only
mortgage_eligible boolean No sale only
exclusive boolean No sale only
broker_license_no string No sale only; up to 64 characters; defaults to the agency's Register of Brokers number
tapija_note string No sale only; up to 500 characters

commission#

Field Shape Rules
buyer_pct, seller_pct sale 0–100
landlord_pct, agency_fee_pct rent 0–100

Accepted for agencies and solo agents; for a bank it is dropped with the warning commission_dropped.

photos[]#

Field Type Required Rules
url string Yes a public https:// URL: no IP address, no local host name, no port other than 443, no credentials, up to 2,048 characters; listed once (duplicate_photo_url)
caption string No up to 500 characters
room_type string No exterior, living_room, kitchen, bedroom, bathroom, balcony, hallway, view, garage, other
digest string No your SHA-256 of the image, 64 lower-case hex characters

The first photo is the cover. See Photos and the fetcher.

agent#

Field Type Required Rules
email string Yes (when agent is sent) a valid email, up to 254 characters; must be an active member of the agency, else the warning agent_not_member
name string No up to 120 characters; not stored
phone string No up to 32 characters; not stored

source#

Field Type Required Rules
updated_at string Yes RFC 3339 date-time with an offset, e.g. 2026-10-12T08:00:00Z; an older value than the one we hold answers unchanged
url string | null No the listing on your or the agency's site; a public https:// URL

Detail codes#

A 422 validation_failed (or a rejected item in a batch) lists details: { pointer, code, message }, one per problem.

Code Meaning Example pointer
unknown_field a key the schema doesn't know /structure/balcon
required a required field is missing /title/sr
invalid_type the wrong JSON type /structure/rooms
too_small below a minimum (length or value) /description/sr
too_big above a maximum (length or value) /price/amount
invalid_enum a value outside the vocabulary /structure/heating
invalid_format a malformed id, URL, date or pattern /photos/0/url
unknown_place place_id is not a city or municipality we know /location/place_id
duplicate_external_id one external_id twice in one batch /listings/3/external_id
duplicate_photo_url one photo URL listed twice /photos/2/url

Warnings do not stop an item; they arrive in the item result and in webhooks:

Warning Meaning
agent_not_member agent.email is not an active member of the agency; the listing has no agent
virtual_tour_dropped the agency's plan has no virtual tours; virtual_tour_url was not stored
commission_dropped the agency is a bank; commission was not stored
field_not_applicable a field that does not apply to the category was ignored
coordinates_outside_place lat / lng fall outside the place's boundary (kept; boundaries are imperfect)
photo_cap_applied more photos than the agency's plan allows; the extra ones were dropped

Last updated