DEVELOPING

The property JSON object

This is the reference for what you send: which fields the property object has, which ones are required, what values each one accepts, and how to say "I don't have this data".

It is a reference for the object, not for an endpoint. To understand how a property is identified —why type and operation are stable keys and where their values come from— read The property model first.

The object you send

This is the complete object. Below is what is required, what is optional and what values each field accepts.

{
  "code": "DEV-V3-909181",
  "type": 6,
  "operation": 2,
  "title": "Hermoso departamento luminoso con excelente ubicación y amenities completos",
  "address": "Av. Santa Fe 4271",
  "mapLatitude": -34.5828,
  "mapLongitude": -58.4206,
  "zone0": 1,
  "zone1": 2,
  "zone2": 189,
  "description": "Excelente propiedad ubicada en zona premium con fácil acceso a transporte público, comercios y servicios. Ideal para vivir o invertir.\n\nCuenta con todos los servicios y amenities modernos. Perfecta para familias o inversión.\n\nUbicación estratégica con fácil acceso a centros comerciales, escuelas y transporte público.",
  "descriptionFormatted": "Excelente propiedad ubicada en zona premium con fácil acceso a transporte público, comercios y servicios. Ideal para vivir o invertir.\n\nCuenta con todos los servicios y amenities modernos. Perfecta para familias o inversión.\n\nUbicación estratégica con fácil acceso a centros comerciales, escuelas y transporte público.",
  "zipcode": "1684",
  "betweenStreets": "Entre Av. Pueyrredón y Av. Coronel Díaz",
  "urlWebExternal": "https://ejemplo-inmobiliaria.com/propiedad-dev",
  "conditions": "Contado",
  "yearsOld": 16,
  "totalFloors": 16,
  "apartmentsPerFloor": 3,
  "floors": 2,
  "buildingArea": 126,
  "landArea": 189,
  "ambiences": 2,
  "rooms": 3,
  "dependencies": 1,
  "bathrooms": 1,
  "toilettes": 2,
  "garage": 2,
  "currency": "USD",
  "price": 142410,
  "zone3": 973,
  "rented": false,
  "sold": false,
  "reserved": false,
  "suspended": false,
  "occupancy": null,
  "images": [
    {
      "url": "https://cdn.ejemplo.com/propiedades/909181/foto-1.jpg",
      "description": "Imagen principal",
      "main": true
    },
    {
      "url": "https://cdn.ejemplo.com/propiedades/909181/foto-2.jpg",
      "description": "Imagen 2",
      "main": false
    },
    {
      "url": "https://cdn.ejemplo.com/propiedades/909181/foto-3.jpg",
      "description": "Imagen 3",
      "main": false
    }
  ],
  "blueprint": {
    "url": "https://cdn.ejemplo.com/propiedades/909181/plano.pdf"
  },
  "videos": [
    {
      "source": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
      "description": "Recorrido"
    }
  ],
  "prices": {
    "expensesCurrency": "ARS",
    "expensesPrice": 500,
    "taxCurrency": "ARS",
    "taxPrice": 200,
    "paymentPeriod": 1
  },
  "altPrices": [
    {
      "description": "Alquiler por semana",
      "currency": "ARS",
      "price": 100000
    }
  ],
  "attributes": [
    {
      "locale": "es_AR",
      "country": "ar",
      "id": "accessible",
      "label": "Accesible",
      "group": "propertyAttribute",
      "group_sub": "label",
      "group_subtype": "ammenities",
      "type": "bool",
      "key_legacy": "accessible",
      "selected": true,
      "status": true
    },
    {
      "locale": "es_AR",
      "country": "ar",
      "id": "statusAverage",
      "label": "Estado Regular",
      "group": "propertyStatus",
      "group_sub": "status",
      "type": "list",
      "key_legacy": "8",
      "value": 8
    },
    // … and 42 more entries, one per property attribute
  ],
  "publication": { … }  // per-portal publishing configuration — see its own page
}

Photos, floor plan, videos and additional prices

They travel in the same JSON: you send a single object.

BlockShapeNote
imageslist of {url, description, main}the URL, not the file: binaries don't travel in a JSON
blueprint{url}only one per property
videoslist of {source, description}source is the YouTube or Matterport URL
prices{expensesCurrency, expensesPrice, taxCurrency, taxPrice, paymentPeriod}maintenance fees and taxes, amounts as numbers
altPriceslist of {description, currency, price}alternative prices

⚠️ The property's price and currency do not go here: they are fields of the property itself and are already listed above.

The attributes array

Each entry describes one piece of data. There are two families: the property's status (propertyStatus) and the attributes — amenities, orientation, heating type and so on (propertyAttribute).

[
  {
    "locale": "es_AR",
    "country": "ar",
    "id": "accessible",
    "label": "Accesible",
    "group": "propertyAttribute",
    "group_sub": "label",
    "group_subtype": "ammenities",
    "type": "bool",
    "key_legacy": "accessible",
    "selected": true,
    "status": true
  },
  {
    "locale": "es_AR",
    "country": "ar",
    "id": "statusAverage",
    "label": "Estado Regular",
    "group": "propertyStatus",
    "group_sub": "status",
    "type": "list",
    "key_legacy": "8",
    "value": 8
  }
]

The value you send is key_legacy: it is the same in every country. The id, the label and the value come from your country's catalog — where to get them is explained further down.

attributes is required, and an empty list is valid. If the property has no attributes at all, send "attributes": []; what you cannot do is omit the key.

customerSource — where the client came from

Every response that carries the customer block also carries, at the root, where it came from:

ValueWhat it means
accountIt is your record, read with your clientRef. The normal case
placeholderYou have not declared a record and this is filler. It only happens on /verify — an upload with no record responds 400, it does not fill in. Fix it with POST /customers
frozenThe snapshot that property was created with (returned by GET and PUT). It is not your record as of today, and that is deliberate: it lets the GET say what data that property was published with

It sits at the root and not inside customer on purpose: inside, it would mix with the fields you declared yourself.

The client is NOT part of this object

Until 2026-09-30 the customer block travelled in here. Not any more: the client is declared once per client and the properties inherit it.

👉 Clients — the POST /property-v1/customers, its fields, the customerId we return and the branch.

⚠️ If you send customer inside this object it is ignored — like propertyId, customerId and branchId. And with no client declared, the upload responds 400 with rule: account_required.

publication — how it gets published

Inside the same object travels a publication key with what each portal needs from your account and from your publishing choices. It is not a field of the property: it is how you publish it.

{
  "publication": {
    "api": {
      "argenprop": {
        "advertiserId": 99999,
        "visible": true,
        "token": "<tu-token-de-argenprop>"
      },
      "zonaprop": {
        "plan": {
          "plan": "SUPERDESTACADO"
        },
        "token": "<tu-token-de-zonaprop>"
      },
      "cabaprop": {
        "branchOfficeId": 42,
        "token": "<tu-token-de-cabaprop>"
      },
      "mercadolibre": {
        "listingTypeId": "gold_special",
        "condition": "used",
        "token": "<tu-token-de-mercadolibre>"
      }
    }
  }
}

The full reference is on The publication key.

Required fields

There are 26, plus the attributes array. Everything else is optional.

Most of them are individual fields:

FieldTypeRule
codestring^[A-Za-z0-9._-]{1,30}$
titlestring1–150 caracteres
descriptionstringal menos 1 carácter
priceinteger1 o más
currencystringUSD o ARS
typeinteger—the type id — pa_key_legacy of the catalog's type group
operationinteger—the operation id — pa_key_legacy of the operation group
zone0integer—country
zone1integer—province
zone2integer—district or department
addressstringal menos 1 carácter
zipcodestring^[A-Za-z0-9-]{1,10}$
mapLatitudenumber-90 – 90see the warning below
mapLongitudenumber-180 – 180see the warning below
buildingAreainteger0 – 100.000built area, in m²
landAreainteger1 – 10.000.000TOTAL area of the property, in m² — also for an apartment
ambiencesinteger0 – 50the rooms
roomsinteger0 – 50⚠️ these are bedrooms, not rooms in general
bathroomsinteger0 – 50
toilettesinteger0 – 10
garageinteger0 – 100
floorsinteger0 – 10floors of the unit
totalFloorsinteger0 – 200floors of the building
apartmentsPerFloorinteger0 – 50
dependenciesinteger0 – 10
yearsOldinteger0 – 300age, in years

The number for the type and the one for the operation are the same in every country — what changes from one country to another is the label. They are listed in Constants.

The two areas have different floors, and it is on purpose. landArea goes from 1 upwards because every property occupies land; buildingArea admits 0, because a lot has no construction and declaring it as zero is correct.

Optional fields

FieldTypeRule
zone3integer—locality or neighborhood
betweenStreetsstring—
occupancyinteger1 – 50
soldboolean—sold
rentedboolean—rented
reservedboolean—reserved
suspendedboolean—listing suspended
descriptionFormattedstring—the description with its line breaks; if you omit it, description is used
conditionsstring—terms of the operation — "Cash", "Mortgage-ready"…
urlWebExternalstring—the property's URL on your own site

mapLatitude and mapLongitude are required, and they go as numbers, not as text. They are in the table above: if you omit them or send them as null, the property fails validation. Geocode the address before posting.

And 0 is not "no coordinate": it is a real point in the Gulf of Guinea, so a property with 0, 0 gets published there. Validation accepts it —it is a valid number— but the listing comes out wrong.

How to say "I don't have this data"

An optional field you don't have is sent as null or not sent at all: for us it is the same thing.

What is not the same is sending 0. A 0 in an area, in the age, in the number of occupants or in a coordinate is stored as the number zero — that is, as data.

Where the values come from

The enumerated fields —type, operation, status, orientations, amenities— deliberately have no fixed list on this page: they depend on the country and change whenever a new one is added.

You request them here:

GET /property-attributes?country=AR

See the full endpoint reference

It returns, for that country, everything it accepts: the text key (pa_key), the value you send (pa_key_legacy), the translated label (pa_label) and the family (pa_group_subtype).

Request the catalog for the property's country, not just one: a type may be enabled in Argentina and not in Peru.

And keep this in mind: we do not validate values against the catalog. A value that the country does not use is not rejected: it is stored, and the property ends up published with the wrong data. The catalog is not a suggestion — it is the only way to know what to send.

Verify before publishing

You can send your object and see what it produces, without creating anything:

POST /property-v1/properties/verify

It tells you whether the object is valid, which rules it breaks field by field, and what would happen on each portal. It is the same body as the creation call, without the write.

Your token needs the property-api-verify scope. Without it, the response is 403. Request it together with your access credentials.

See also