Property Schema
Complete reference for the JSON format your API must return for each property. This document defines the standard contract for new Spot2 Ingestion integrations.
Conventions
- Field names use
snake_case. - Dates use ISO 8601 with timezone when available, for example
2026-07-24T15:40:43Z. - Text is UTF-8.
- Numeric fields use decimal point and no thousands separators.
- Empty arrays use
[], notnull. - Null fields (
null) are equivalent to missing fields. - Unknown fields are ignored. Only fields documented in this schema are processed.
JSON Structure
Each property is represented as a JSON object:
{
"external_id": "PROP-001",
"property_type": "office",
"modality": "rent",
"title": "Oficina corporativa en Polanco",
"description": "Oficina acondicionada con estacionamiento y aire acondicionado.",
"updated_at": "2026-07-24T15:40:43Z",
"surface_m2": 250.5,
"land_m2": null,
"bedrooms": 0,
"bathrooms": 2.5,
"parking_spots": 4,
"price": {
"currency": "MXN",
"rent_price": 120000,
"sale_price": null
},
"location": {
"latitude": 19.4326,
"longitude": -99.1937,
"street": "Avenida Presidente Masaryk",
"ext_number": "123",
"int_number": "4B",
"neighborhood": "Polanco",
"city": "Ciudad de México",
"state": "Ciudad de México",
"postal_code": "11560"
},
"contact": {
"name": "Broker CRM",
"phone": "525512345678",
"email": "broker@example.com"
},
"office": {
"floor_level": 6,
"floor_level_number": "4"
},
"industrial": {},
"retail": {},
"terrain": {},
"photos": [
"https://cdn.your-crm.com/photo-1.jpg",
"https://cdn.your-crm.com/photo-2.jpg"
],
"amenities": [
"aire acondicionado",
"elevador"
]
}
Identity And Classification
| Field | Location | Type | Requirement |
|---|---|---|---|
external_id | root | string | Required. Unique and immutable identifier in your system. id is also accepted as fallback, but always sending external_id is recommended. |
property_type | root | string | Required. One of office, retail, industrial, terrain. |
modality | root | string | Required. One of rent, sale, rent_and_sale. If missing or unrecognized, it is interpreted as rent; always send it explicitly. |
title | root | string | Optional. If missing, an operational title is generated from external_id. |
description | root | string | Optional, but recommended. Preserved as external description for audit and content improvement. |
updated_at | root | string | Recommended. Last modification in your CRM. Used for incremental sync and to detect potentially inactive inventory. |
property_type Catalog
Spot2 Ingestion processes these 4 commercial families:
| Value | Use |
|---|---|
office | Offices, corporate suites, private offices, medical offices, and coworking. |
retail | Retail spaces, shops, restaurants, showrooms, and shopping-center spaces. |
industrial | Warehouses, industrial units, distribution centers, factories, and industrial parks. |
terrain | Commercial or industrial land and lots. |
Do not send residential properties. Houses, apartments, housing, and mainly residential uses are rejected automatically.
Normalization Examples
If your CRM has internal subtypes, normalize them before exposing the feed:
| Internal CRM subtype | Send as property_type |
|---|---|
| oficina, edificio, corporate, private office, medical office, coworking | office |
| local, retail space, shop, restaurant, showroom, shopping center, hotel, bar, cafeteria, pharmacy, gym, spa, boutique | retail |
| bodega, industrial warehouse, industrial unit, warehouse, galpón, depósito, industrial park | industrial |
| terreno, commercial land, industrial land, lot, land, plot | terrain |
modality Catalog
| Value | Meaning |
|---|---|
rent | Rent only. |
sale | Sale only. |
rent_and_sale | Available for both rent and sale. Send both prices. |
Price
The price object groups prices and currency:
| Field | Type | Requirement |
|---|---|---|
rent_price | number or null | Required with value greater than 0 when modality is rent or rent_and_sale. |
sale_price | number or null | Required with value greater than 0 when modality is sale or rent_and_sale. |
currency | string | Recommended. Public allowed values: MXN, USD. If missing, it is interpreted as MXN. |
Example for rent and sale:
{
"external_id": "PROP-002",
"property_type": "retail",
"modality": "rent_and_sale",
"price": {
"rent_price": 35000,
"sale_price": 4500000,
"currency": "MXN"
}
}
Supported Currencies
| Code | Currency |
|---|---|
MXN | Mexican peso. |
USD | US dollar. |
We recommend sending prices in MXN. If you send USD, Spot2 applies validations on the converted MXN value when applicable.
Location
The location object describes address and coordinates:
| Field | Type | Requirement |
|---|---|---|
city | string | Required for publishing. |
state | string | Required for publishing. |
postal_code | string | Required. Must resolve during enrichment. |
street | string | Required. Required together with coordinates. |
ext_number | string | Optional. Maximum 6 characters. |
int_number | string | Optional. Maximum 6 characters if sent. |
neighborhood | string | Optional. Neighborhood, borough, or area. |
latitude | number | Required. Must be different from 0. |
longitude | number | Required. Must be different from 0. |
If coordinates are confidently outside Mexico, the property may publish as draft or with reduced visibility.
Contact
The contact object contains agent or commercial contact data:
| Field | Type | Requirement |
|---|---|---|
name | string | Required. Commercial contact name. |
email | string | Required. Contact email address. |
phone | string | Required. Contact phone number. |
If the contact is blocked by quality or security policies, the property is not published.
Physical Characteristics
| Field | Location | Type | Requirement |
|---|---|---|---|
surface_m2 | root | number or null | Recommended. Built surface in m². If missing or non-positive, it is treated as unknown. |
land_m2 | root | number or null | Recommended for land. For terrain, used as surface fallback when surface_m2 is missing or non-positive. |
bedrooms | root | integer or null | Optional. Maximum 20 if sent. |
bathrooms | root | number or null | Optional. Decimals are accepted, for example 2.5. |
parking_spots | root | integer or null | Optional. 0 is valid and means no parking spaces. If missing, it is omitted from the publish payload. |
Photos
| Field | Type | Requirement |
|---|---|---|
photos | string[] | Recommended. Without photos, or with fewer than 3 photos, the property may publish as draft or with reduced visibility. We recommend 3 or more. |
Rules:
- Send public
httporhttpsURLs;httpsis recommended. - Array order defines visual priority; the first image is used as main image when applicable.
- Spot2 may cap the final photo payload to 20 URLs.
Amenities
amenities is an array of text labels. Spanish or English labels are accepted and mapped to the internal catalog when they match a known amenity. Unknown amenities are ignored and do not cause rejection.
Some amenities are also inferred from numeric fields: bathrooms > 0 adds bathrooms, and parking_spots > 0 adds parking.
Recommended values:
| Recommended value | Amenity |
|---|---|
bathrooms or baños | Bathrooms |
wifi | Wi-Fi |
air_conditioning or aire acondicionado | Air conditioning |
parking or estacionamiento | Parking |
warehouse or bodega | Warehouse / storage |
accessibility or accesibilidad | Accessibility |
electricity or luz | Electricity |
security_system or sistema de seguridad | Security system |
forklift or montacargas | Forklift |
whiteboard or pizarrón | Whiteboard |
elevator or elevador | Elevator |
terrace or terraza | Terrace |
cleaning_area or zona de limpieza | Cleaning area |
divisible | Divisible |
mezzanine | Mezzanine |
equipped_kitchen or cocina equipada | Equipped kitchen |
backup_generator or planta de luz | Backup generator |
kitchen or cocina | Kitchen |
loft or tapanco | Loft |
Type-Specific Fields
The office, industrial, retail, and terrain objects are optional, but some fields have validations when sent.
Office ("property_type": "office")
| Field | Location | Type | Validation |
|---|---|---|---|
floor_level | office | integer | Optional. If 6, floor_level_number is required. |
floor_level_number | office | string or number | Required when floor_level = 6. |
{
"property_type": "office",
"office": {
"floor_level": 6,
"floor_level_number": "4"
}
}
Industrial ("property_type": "industrial")
| Field | Location | Type | Validation |
|---|---|---|---|
min_height_m | industrial | number or null | Minimum clear height. If missing, interpreted as 0. |
max_height_m | industrial | number or null | Maximum clear height. If sent, min_height_m must not be greater than this value. |
min_area_divisible_m2 | industrial | number or null | Minimum divisible area. Must be less than or equal to max_area_divisible_m2 when both exist. |
max_area_divisible_m2 | industrial | number or null | Maximum divisible area. Must be greater than or equal to min_area_divisible_m2 when both exist. |
luminaries | industrial | integer or null | If greater than 0, luminary_specs is required. |
luminary_specs | industrial | string or null | Luminary specifications. Required when luminaries > 0. |
{
"property_type": "industrial",
"industrial": {
"min_height_m": 4.5,
"max_height_m": 9.2,
"min_area_divisible_m2": 200,
"max_area_divisible_m2": 2000,
"luminaries": 20,
"luminary_specs": "LED industrial 200W"
}
}
Retail ("property_type": "retail")
| Field | Location | Type | Validation |
|---|---|---|---|
min_height_m | retail | number or null | Minimum clear height. If missing, interpreted as 0. |
price_per_sqm_min | retail | number or null | Minimum price per m². Must be less than or equal to price_per_sqm_max when both exist. |
price_per_sqm_max | retail | number or null | Maximum price per m². Must be greater than or equal to price_per_sqm_min when both exist. |
{
"property_type": "retail",
"retail": {
"min_height_m": 3.8,
"price_per_sqm_min": 200,
"price_per_sqm_max": 500
}
}
Terrain ("property_type": "terrain")
| Field | Location | Type | Validation |
|---|---|---|---|
land_use | terrain | string | Required for land when the field is present in the mapped payload. We recommend always sending it. |
{
"property_type": "terrain",
"surface_m2": 0,
"land_m2": 5000,
"terrain": {
"land_use": "industrial"
}
}
Publishing Rules
The property is evaluated with three severities:
| Severity | Result |
|---|---|
BLOCK | Not published. You must fix the data in your CRM. |
DRAFT | Published as draft or with reduced internal visibility. |
WARN | Published normally, but missing amenities are recorded. |
Summary of critical requirements to avoid BLOCK:
external_idpresent.- Commercial and recognizable
property_type. - Valid
modality. - At least one price greater than 0.
location.city,location.state,location.street,location.latitude, andlocation.longitudepresent.postal_coderesolvable after enrichment.- Exterior and interior numbers with maximum 6 characters when sent.
contact.name,contact.email, andcontact.phonepresent.- Valid type-specific rules.
- Contact must not be blocked.
- Description must not indicate a residential property.
For the full rules catalog, see Validation Rules.
Custom Integrations
If your CRM cannot expose this exact contract, the integration requires a custom adapter outside this document.