Property Schema
Complete reference for the JSON format your API must return for each property. This document is the data contract between your CRM and Spot2 Ingestion.
Conventions
- Field names in snake_case.
- Dates in ISO 8601 format with timezone (e.g.
2026-06-29T14:30:00Z). - Text in UTF-8.
- Numeric fields: decimal point, no thousands separator.
- Empty arrays:
[], notnull. - Null fields (
null): treated as absent. - Unknown fields: ignored. Only fields documented in this schema are processed.
JSON structure
Each property is represented as a JSON object with this structure:
{
"external_id": "prop-12345",
"property_type": "oficina",
"modality": "rent",
"title": "Oficina ejecutiva en Polanco",
"description": "Amplia oficina con vista panorámica...",
"updated_at": "2026-06-29T14:30:00Z",
"surface_m2": 120.5,
"land_m2": null,
"bedrooms": 0,
"bathrooms": 2.0,
"parking_spots": 3,
"photos": [
"https://cdn.your-crm.com/01.jpg",
"https://cdn.your-crm.com/02.jpg"
],
"price": {
"rent_price": 45000.00,
"sale_price": null,
"currency": "MXN"
},
"location": {
"latitude": 19.4326,
"longitude": -99.1332,
"street": "Av. Presidente Masaryk",
"ext_number": "123",
"int_number": "4A",
"neighborhood": "Polanco",
"city": "Ciudad de México",
"state": "Ciudad de México",
"postal_code": "11560"
},
"agent": {
"name": "Juan Pérez",
"email": "juan@broker.com",
"phone": "+525512345678"
},
"amenities": ["aire acondicionado", "elevador", "estacionamiento"],
"office": {
"floor_level": 5,
"floor_level_number": "Piso 5"
}
}
price object structure
| Field | Type | Description |
|---|---|---|
rent_price | number or null | Monthly rent price. Required if modality is rent or rent_and_sale. |
sale_price | number or null | Sale price. Required if modality is sale or rent_and_sale. |
currency | string | ISO 4217 code. Default MXN. See currency catalog. |
location object structure
| Field | Type | Description |
|---|---|---|
latitude | number or null | Decimal latitude. Recommended. |
longitude | number or null | Decimal longitude. Recommended. |
street | string | Street. Required if sending coordinates. |
ext_number | string | Street number. Max 6 characters. |
int_number | string | Unit or apartment number. |
neighborhood | string | Neighborhood or district. |
city | string | City. Required. |
state | string | State. Required. |
postal_code | string | Postal code. |
agent object structure
| Field | Type | Description |
|---|---|---|
name | string | Agent or broker name. |
email | string | Email address. Recommended. |
phone | string | Phone number. Recommended. |
Properties with rent and sale
When a property is available for both operations, send both prices and set modality to rent_and_sale:
{
"external_id": "prop-67890",
"property_type": "local",
"modality": "rent_and_sale",
"price": {
"rent_price": 35000.00,
"sale_price": 4500000.00,
"currency": "MXN"
},
"location": {
"city": "Monterrey",
"state": "Nuevo León"
},
"updated_at": "2026-06-29T10:00:00Z"
}
If you don't specify modality, it is determined automatically: only rent_price → rent, only sale_price → sale, both → rent_and_sale.
Required fields
Without these fields, the property will not be published.
| Field | Location | Type | Description |
|---|---|---|---|
external_id | root | string | Unique, immutable identifier. Max 255 characters. |
property_type | root | string | One of the 7 canonical values. See catalog. |
location.city | location | string | City. Not empty. |
location.state | location | string | State. Not empty. |
price.rent_price or price.sale_price | price | number | At least one must be greater than 0. |
updated_at | root | string | Last modified in ISO 8601. |
Catalog of property_type
Only these 7 values are accepted. Variants are recognized (e.g. "oficina virtual" is classified as office), but we recommend using the exact values.
| Value | Description |
|---|---|
oficina | Office, corporate suite |
local | Retail space, shop |
bodega | Storage warehouse |
nave_industrial | Industrial building, factory |
terreno | Land, lot |
edificio | Full building |
local_en_centro_comercial | Shopping center unit |
Residential properties (house, apartment, home) are automatically rejected.
Catalog of modality
| Value | Meaning |
|---|---|
rent | Rent only |
sale | Sale only |
rent_and_sale | Both operations |
Catalog of currency
ISO 4217 codes. Default MXN. Prices are converted to MXN using the day's exchange rate.
| Code | Currency |
|---|---|
MXN | Mexican Peso |
USD | US Dollar |
If you send prices in a currency other than MXN and the exchange rate is unavailable, the property will not be published. We recommend sending prices in MXN.
Recommended fields
If missing, the property is published but with reduced visibility.
| Field | Location | Type | Description |
|---|---|---|---|
photos | root | string[] | Photo URLs. Minimum 1 for public visibility. |
location.latitude + location.longitude | location | number | Coordinates. Without them the property doesn't appear on the map. |
agent.email or agent.phone | agent | string | At least one contact method. |
Optional fields
Identity
| Field | Location | Type | Description |
|---|---|---|---|
title | root | string | Listing title. |
description | root | string | Free-form description. |
Physical characteristics
| Field | Location | Type | Validation |
|---|---|---|---|
surface_m2 | root | number or null | Built area in m². If > 0, minimum 3 m². |
land_m2 | root | number or null | Land area in m². |
bedrooms | root | integer or null | Bedrooms. Max 20. |
bathrooms | root | number or null | Bathrooms. Decimals accepted (e.g. 1.5). |
parking_spots | root | integer or null | Parking spaces. |
Catalog of amenities
List of amenities we recognize. Each string you send is matched by keyword against this table (ignoring articles like "de", "la", "el"). Non-matching strings are ignored.
| Amenity | Terms that trigger it |
|---|---|
| Baños | baño, baños, bathroom |
| Wifi | wifi, internet |
| A/C | aire acondicionado, climatización |
| Estacionamiento | estacionamiento, parking, cochera |
| Bodega | bodega, almacén |
| Accesibilidad | accesibilidad, rampa |
| Luz | luz, electricidad |
| Sistema de seguridad | seguridad, vigilancia, cámaras |
| Montacargas | montacargas |
| Pizarrón | pizarrón, whiteboard |
| Elevador | elevador, ascensor |
| Terraza | terraza |
| Zona de limpieza | limpieza, cleaning |
| Divisible | divisible |
| Mezzanine | mezzanine, entrepiso |
| Cocina equipada | cocina equipada, kitchenette |
| Planta de luz | planta de luz, generador |
| Cocina | cocina |
| Loft | loft |
Examples:
"aire acondicionado"→ A/C"estacionamiento para visitas"→ Estacionamiento"vigilancia 24/7"→ Sistema de seguridad"jardín"→ ignored (no match)
Fields by property type
Some types require additional fields within an object named after the type.
Office ("property_type": "oficina" or "edificio")
The office object is optional but its fields are validated if sent.
| Field | Location | Type | Validation |
|---|---|---|---|
floor_level | office | integer | Floor number (1 = ground floor). If 6, floor_level_number is required. |
floor_level_number | office | string | Floor label (e.g. "Piso 5"). Required if floor_level is 6. |
Example:
{
"property_type": "oficina",
"office": {
"floor_level": 5,
"floor_level_number": "Piso 5"
}
}
Industrial ("property_type": "nave_industrial" or "bodega")
| Field | Location | Type | Validation |
|---|---|---|---|
max_height_m | industrial | number | Maximum interior height. Max 30 meters. |
min_area_divisible_m2 | industrial | number | Minimum divisible area. Must be ≤ max_area_divisible_m2. |
max_area_divisible_m2 | industrial | number | Maximum divisible area. Must be ≥ min_area_divisible_m2. |
luminaries | industrial | integer | Number of light fixtures. If > 0, luminary_specs is required. |
luminary_specs | industrial | string | Light fixture specifications. Required if luminaries > 0. |
Example:
{
"property_type": "nave_industrial",
"industrial": {
"max_height_m": 12,
"min_area_divisible_m2": 200,
"max_area_divisible_m2": 2000,
"luminaries": 20,
"luminary_specs": "LED industrial 200W"
}
}
Retail ("property_type": "local" or "local_en_centro_comercial")
| Field | Location | Type | Validation |
|---|---|---|---|
price_per_sqm_min | retail | number | Minimum price per m². Must be ≤ price_per_sqm_max. |
price_per_sqm_max | retail | number | Maximum price per m². Must be ≥ price_per_sqm_min. |
Example:
{
"property_type": "local",
"retail": {
"price_per_sqm_min": 200,
"price_per_sqm_max": 500
}
}
Land ("property_type": "terreno")
| Field | Location | Type | Validation |
|---|---|---|---|
land_use | terrain | string | Land use (e.g. comercial, industrial, mixto). Required for land. |
Example:
{
"property_type": "terreno",
"terrain": {
"land_use": "industrial"
}
}
Price validations
- Minimum price: monthly rent ≥ $10,000 MXN. Sale ≥ $100,000 MXN. Lower prices are rejected.
- Price per m²: validated against statistical ranges by property type and modality. Out of range → reduced visibility.
- Surface area: validated against statistical ranges by property type. Out of range → reduced visibility.
Currency conversion
If you send prices in a currency other than MXN:
- The day's exchange rate is queried.
- The price is converted to MXN.
- Validations are applied on the converted value.
- If the exchange rate is unavailable, the property is rejected.
The price shown on Spot2 is always in MXN. We recommend converting prices to MXN on your CRM side before sending.
Canonical schema vs CRM schema
The schema documented here is the canonical format Spot2 ingests after mapping. Your CRM may use different field names. Spot2 adapts via configuration during integration.
Example: Tokko → Spot2
| Spot2 (canonical) | Tokko (native) |
|---|---|
property_type | operation_category (mapped via TokkoOperationType) |
price.rent_price | operation_amount when operation_type = "Alquiler" |
price.sale_price | operation_amount when operation_type = "Venta" |
price.currency | operation_currency |
location.city | Derived from operation_full_location |
location.latitude | geo_lat |
location.longitude | geo_long |
photos | photos[].url |
modality | Derived from operation_type values of the publication_ids_map |