Skip to content

Propiedades

Las propiedades son el núcleo de la plataforma. Pueden ser publicadas por agency_admin, agent, broker o developer, y asignadas a un agente específico.

Estados de una propiedad

Estado (propertyStatus)Descripción
draftBorrador, no visible públicamente
publishedPublicada y visible
soldVendida / arrendada
inactiveDesactivada temporalmente
Estado (listingStatus)Descripción
activeDisponible para compradores/arrendatarios
inactiveNo disponible actualmente
rentedArrendada

Listar propiedades (público)

Solo devuelve propiedades con propertyStatus = published y listingStatus = active.

http
GET /api/properties

Query params opcionales:

ParámetroTipoDescripción
pagenumberPágina (default: 1)
limitnumberResultados por página (default: 10)
listing_typestringsale o rent
categorystringValor exacto del catálogo de categorías, ej. Houses, Apartments
citystringFiltrar por ciudad
min_pricenumberPrecio mínimo
max_pricenumberPrecio máximo
bedroomsnumberNúmero de recámaras
bathroomsnumberNúmero de baños
featuredbooleanSolo propiedades destacadas
agent_iduuidPropiedades de un agente específico
agency_iduuidPropiedades de una agencia específica

Respuesta 200:

json
{
  "success": true,
  "data": {
    "data": [
      {
        "id": "uuid-propiedad",
        "title": "Departamento en Polanco",
        "price": 4500000,
        "currency": "MXN",
        "listingType": "sale",
        "categories": ["Apartments"],
        "bedrooms": 3,
        "bathrooms": 2,
        "constructionArea": 120,
        "city": "Ciudad de México",
        "state": "CDMX",
        "address": "Calle Masaryk 45, Polanco",
        "propertyStatus": "published",
        "listingStatus": "active",
        "isFeatured": false,
        "viewsCount": 148,
        "agentId": "uuid-agente",
        "agencyId": "uuid-agencia",
        "user": { "firstName": "Carlos", "lastName": "Mendoza" },
        "agent": { "company": "Inmobiliaria Centro MX" },
        "assets": [
          {
            "id": "uuid-asset",
            "url": "https://cdn.havi.app/properties/foto1.jpg",
            "type": "image",
            "sortOrder": 1
          }
        ],
        "createdAt": "2026-05-13T10:00:00.000Z"
      }
    ],
    "meta": {
      "total": 250,
      "perPage": 10,
      "currentPage": 1,
      "lastPage": 25
    }
  }
}

Buscar propiedades

http
GET /api/properties/search

Acepta los mismos parámetros que el listado.


Detalle de propiedad

http
GET /api/properties/:id

Incrementa el contador de vistas (viewsCount) en cada llamada.


Propiedades similares

http
GET /api/properties/:id/similar

Devuelve hasta 6 propiedades similares en la misma ciudad y categoría.


Crear propiedad

Requiere autenticación

agency_admin, agent, broker o developer.

http
POST /api/properties
Authorization: Bearer {token}
Content-Type: application/json

Body:

json
{
  "title": "Departamento en Polanco",
  "description": "Hermoso departamento de 3 recámaras con vista a Masaryk. Acabados de lujo, cocina integral, 2 cajones de estacionamiento.",
  "price": 4500000,
  "currency": "MXN",
  "listingType": "sale",
  "categories": ["Apartments"],
  "bedrooms": 3,
  "bathrooms": 2,
  "halfBaths": 1,
  "parkingSpaces": 2,
  "constructionArea": 120,
  "landArea": 0,
  "yearBuilt": 2021,
  "floors": 1,
  "city": "Ciudad de México",
  "state": "CDMX",
  "zipCode": "11560",
  "address": "Calle Masaryk 45, Polanco",
  "latitude": 19.4313,
  "longitude": -99.1893,
  "amenities": ["Gimnasio", "Roof Garden Común", "Caseta de Vigilancia 24h", "Área de Mascotas"],
  "agentId": "uuid-del-agente",
  "propertyStatus": "draft",
  "listingStatus": "inactive",
  "isFeatured": false
}

Comportamiento al asignar agente:

  • Si incluyes agentId, la propiedad queda asignada a ese agente y a su agencia automáticamente.
  • Si el usuario autenticado tiene rol agent y no especificas agentId, se asigna a sí mismo.

Respuesta 201:

json
{
  "success": true,
  "data": {
    "id": "uuid-propiedad",
    "title": "Departamento en Polanco",
    "propertyStatus": "draft",
    "listingStatus": "inactive",
    "agentId": "uuid-agente",
    "agencyId": "uuid-agencia",
    "userId": "uuid-usuario"
  }
}

Subir imágenes (URL pre-firmada S3)

El proceso de subida de imágenes se hace en dos pasos: obtener URLs pre-firmadas y subir directamente a S3.

Paso 1 — Solicitar URLs pre-firmadas:

http
POST /api/upload/presigned
Authorization: Bearer {token}
Content-Type: application/json
json
{
  "files": [
    { "filename": "fachada.jpg", "contentType": "image/jpeg" },
    { "filename": "sala.jpg",    "contentType": "image/jpeg" },
    { "filename": "recamara.jpg","contentType": "image/jpeg" }
  ],
  "propertyId": "uuid-propiedad"
}

Respuesta:

json
{
  "success": true,
  "data": [
    {
      "filename": "fachada.jpg",
      "uploadUrl": "https://s3.amazonaws.com/bucket/...",
      "publicUrl": "https://cdn.havi.app/properties/fachada.jpg"
    }
  ]
}

Paso 2 — Subir cada archivo directamente a S3:

javascript
await fetch(uploadUrl, {
  method: 'PUT',
  headers: { 'Content-Type': 'image/jpeg' },
  body: fileBlob
})

Agregar imágenes por URL (CDN propio)

Si tus imágenes ya viven en tu propio CDN, no necesitas subirlas a nuestro S3. Basta con enviar las URLs públicas en el campo images al actualizar (o crear) la propiedad:

http
PUT /api/properties/:id
Authorization: Bearer {token}
Content-Type: application/json
json
{
  "images": [
    "https://cdn.tuempresa.com/propiedades/123/fachada.jpg",
    { "url": "https://cdn.tuempresa.com/propiedades/123/sala.jpg", "floorLabel": "ground-floor" }
  ]
}

Reglas importantes:

  • :id es el UUID de la propiedad que devolvió la API al crearla (formato xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx). No uses tu customId ni mlsNumber — recibirás INVALID_PROPERTY_ID.
  • Cada elemento de images debe ser un string con la URL o un objeto { "url": "...", "floorLabel": "..." }. Cualquier otra forma (ej. { "src": ... } o { "imageUrl": ... }) se rechaza con INVALID_IMAGE_FORMAT.
  • Las URLs deben empezar con http:// o https:// y ser públicamente accesibles.
  • Enviar images reemplaza el set completo de imágenes de la propiedad. Si quieres agregar una imagen, envía la lista completa (las existentes + la nueva). Si omites el campo images, las imágenes actuales se conservan.
  • La primera imagen válida queda como destacada (isFeatured).
  • El campo videos funciona igual, con un array de URLs (strings).

Respuesta 200 — incluye un reporte media que indica cuántas imágenes se aceptaron y cuáles se omitieron y por qué:

json
{
  "success": true,
  "message": "Property updated successfully",
  "data": { "id": "uuid-propiedad", "assets": [ /* ... */ ] },
  "media": {
    "images": {
      "received": 3,
      "created": 2,
      "skipped": [
        {
          "index": 2,
          "code": "INVALID_IMAGE_FORMAT",
          "message": "Each image must be a URL string or an object { url, floorLabel? }",
          "received": { "src": "https://cdn.tuempresa.com/foto.jpg" }
        }
      ]
    },
    "videos": null
  }
}

Si created es 0 y no ves imágenes en la propiedad, revisa el array skipped: ahí está la razón exacta por cada imagen rechazada.

Códigos de error:

HTTPcodeCausa
400INVALID_PROPERTY_IDEl :id no es un UUID válido
404PROPERTY_NOT_FOUNDNo existe propiedad con ese UUID
403NOT_AUTHORIZEDEl token no pertenece al dueño, agente asignado ni admin de la agencia de la propiedad
422VALIDATION_ERRORCampos inválidos en el body (detalle en errors)
200 con media.images.skipped[].codeINVALID_IMAGE_FORMAT, BLOB_URL_NOT_ALLOWED, INVALID_URL_SCHEMEImágenes individuales rechazadas (la propiedad sí se actualiza)

Publicar propiedad

Cambia el estado de borrador a publicado:

http
PUT /api/properties/:id
Authorization: Bearer {token}
Content-Type: application/json

{
  "propertyStatus": "published",
  "listingStatus": "active"
}

Actualizar propiedad

http
PUT /api/properties/:id
Authorization: Bearer {token}
Content-Type: application/json

Acepta los mismos campos que la creación. Todos son opcionales.


Asignar agente a propiedad

http
PUT /api/properties/:id/assign-agent
Authorization: Bearer {token}
Content-Type: application/json

{
  "agentId": "uuid-del-agente"
}

Respuesta 200:

json
{
  "success": true,
  "message": "Agent assigned successfully",
  "data": {
    "id": "uuid-propiedad",
    "agentId": "uuid-agente",
    "agencyId": "uuid-agencia"
  }
}

Eliminar propiedad

http
DELETE /api/properties/:id
Authorization: Bearer {token}

Mis propiedades

http
GET /api/my-properties
Authorization: Bearer {token}

Incluye propiedades en todos los estados (drafts, publicadas, inactivas).


Campos de propiedad

CampoTipoRequeridoDescripción
titlestringTítulo de la propiedad
descriptionstringNoDescripción detallada
pricenumberPrecio
currencystringNoMXN (default), USD, COP, PEN, CLP
listingTypestringsale o rent
categoriesarrayValores del catálogo de categorías, ej. ["Apartments"]
bedroomsnumberNoNúmero de recámaras
bathroomsnumberNoBaños completos
halfBathsnumberNoMedios baños
parkingSpacesnumberNoCajones de estacionamiento
constructionAreanumberNoÁrea construida en m²
landAreanumberNoÁrea de terreno en m²
yearBuiltnumberNoAño de construcción
floorsnumberNoNúmero de pisos
citystringNoCiudad
statestringNoEstado/Departamento/Provincia
zipCodestringNoCódigo postal
addressstringNoDirección completa
latitudenumberNoLatitud para mapa
longitudenumberNoLongitud para mapa
amenitiesarrayNoLista de amenidades — ver catálogo de amenidades
agentIduuidNoAsignar a un agente
propertyStatusstringNodraft, published, sold, inactive
listingStatusstringNoactive, inactive, rented
isFeaturedbooleanNoMarcar como propiedad destacada

Catálogo de categorías

El campo categories acepta un array con uno o más de estos valores. Envía el valor exacto en inglés (columna value); la plataforma lo muestra con su etiqueta en español. Los filtros públicos (?category=) comparan contra estos mismos valores, así que una categoría fuera de catálogo hará que la propiedad no aparezca en los resultados filtrados.

value (enviar este)Etiqueta mostrada
Adult CommunityComunidad para Adultos
AgricultureAgrícola
ApartmentsApartamentos / Departamentos
Boat SlipAmarre para Embarcación
BungalowBungalow
BusinessNegocio
CabinCabaña
CondominiumCondominio
Deeded ParkingEstacionamiento con Escritura
DuplexDúplex
FarmGranja
Hotel-MotelHotel / Motel
HousesCasas
IndustrialIndustrial
LoftLoft
Manufactured HomeCasa Prefabricada
Manufactured On LandCasa Prefabricada en Terreno Propio
Mixed UseUso Mixto
Mobile HomeCasa Móvil
Multi-FamilyMultifamiliar
OfficeOficina
OtherOtro
Own Your OwnPropiedad Individual (Own Your Own)
QuadruplexCuádruplex
RanchRancho
RetailLocal Comercial
Single Family AttachedCasa Unifamiliar Adosada
Single Family DetachedCasa Unifamiliar Independiente
Stock CooperativeCooperativa de Vivienda
TimeshareTiempo Compartido
TownhomeCasa Adosada
TriplexTríplex
Unimproved LandTerreno sin Desarrollar
Vacation HomeCasa Vacacional
VillaVilla
WarehouseBodega

Equivalencias

Si tu sistema maneja Apartment o Townhouse (nomenclatura RESO), envía sus equivalentes del catálogo: Apartments y Townhome respectivamente.

json
{ "categories": ["Houses"] }

Catálogo de amenidades

El campo amenities acepta un array de strings. Usa los valores exactamente como aparecen aquí (con mayúsculas y acentos); se muestran tal cual en el detalle de la propiedad y en los filtros.

De la vivienda:

Aire Acondicionado, Calefacción, Cisterna, Filtro de Agua, Boiler, Gas Natural, Paneles Solares, Cocina Integral, Línea Blanca, Lavadora, Secadora, Refrigerador, Microondas, Lavavajillas, Closets, Vestidor, Bodega Interior, Cuarto de Servicio, Estudio / Oficina, Chimenea, Jacuzzi Privado, Piscina Privada, Terraza / Balcón, Roof Garden Privado, Jardín Privado, Parrilla / BBQ, WiFi, TV Cable / Satélite, Sistema de Seguridad, Domótica, Cava de Vinos

Del condominio / desarrollo:

Caseta de Vigilancia 24h, Acceso Controlado, Cámaras de Seguridad, Elevador, Generador Eléctrico, Estacionamiento de Visitas, Lobby / Recepción, Alberca Común, Jacuzzi Común, Gimnasio, Cancha de Tenis, Cancha de Pádel, Cancha de Basketball, Cancha de Fútbol, Área de Juegos Infantiles, Área de Mascotas, Jardines y Áreas Verdes, Asadores Comunes, Roof Garden Común, Salón de Eventos, Salón de Usos Múltiples, Business Center / Coworking, Lavandería Común, Bodega Común, Administración en sitio

json
{ "amenities": ["Cocina Integral", "Terraza / Balcón", "Gimnasio", "Alberca Común"] }

Valores fuera de catálogo

La API no rechaza strings fuera de estos catálogos (se guardan tal cual), pero no harán match con los filtros de la plataforma y se mostrarán sin traducción. Para una integración correcta, usa siempre los valores listados.

HAVI API · Documentación Oficial