{"openapi":"3.0.0","paths":{"/v1/health":{"get":{"description":"Comprueba que la API está disponible. No requiere autenticación.","operationId":"AppController_health","parameters":[],"responses":{"200":{"description":"Servicio disponible.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"service":{"type":"string","example":"api-public"}}}}}}},"summary":"Estado del servicio","tags":["Servicio"]}},"/v1/properties":{"post":{"description":"Crea una propiedad de la corredora dueña de la API key. Queda en DRAFT y pasa sola a READY cuando tiene título, precio y al menos 3 fotos. Con una key de prueba (th_test_) se crea como sandbox: solo la ven las keys de prueba y nunca llega a portales reales. Emite el webhook PROPERTY_CREATED.\nScope requerido: properties:write.","operationId":"PublicPropertiesController_create","parameters":[{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Clave estable para reintentar sin duplicar (válida 7 días). Repetirla con el mismo body devuelve la misma respuesta; con otro body devuelve 409.","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePublicPropertyDto"}}}},"responses":{"201":{"description":"Propiedad creada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"409":{"description":"La Idempotency-Key ya se usó con otro body o sigue en proceso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Crear una propiedad","tags":["Propiedades"]},"get":{"description":"Lista paginada (más nuevas primero). Filtra por estado, operación, texto libre o externalId (el id de tu CRM). Una key de prueba solo ve propiedades sandbox y una de producción solo las reales.\nScope requerido: properties:read.","operationId":"PublicPropertiesController_list","parameters":[{"name":"page","required":false,"in":"query","description":"Página (parte en 1).","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Resultados por página.","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"$ref":"#/components/schemas/PropertyStatus"}},{"name":"operationType","required":false,"in":"query","schema":{"$ref":"#/components/schemas/OperationType"}},{"name":"search","required":false,"in":"query","description":"Búsqueda por título, comuna o región.","schema":{"type":"string"}},{"name":"externalId","required":false,"in":"query","description":"Filtra por el id de tu CRM (externalId).","schema":{"example":"crm-prop-12345","type":"string"}}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyListResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Listar propiedades","tags":["Propiedades"]}},"/v1/properties/{id}":{"get":{"description":"Devuelve el detalle completo de una propiedad de la corredora.\nScope requerido: properties:read.","operationId":"PublicPropertiesController_getOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Obtener una propiedad","tags":["Propiedades"]},"patch":{"description":"Actualiza solo los campos enviados. Si characteristics viene, reemplaza el objeto completo (la clave external se conserva). Si la propiedad está publicada, los portales donde está activa se actualizan solos.\nScope requerido: properties:write.","operationId":"PublicPropertiesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePublicPropertyDto"}}}},"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Actualizar una propiedad","tags":["Propiedades"]},"delete":{"description":"Archiva la propiedad: deja de aparecer como disponible y no se puede publicar. Antes debe estar despublicada de todos los portales (DELETE /v1/properties/{id}/publications/{portalCode} y esperar el webhook). Repetir la llamada sobre una propiedad ya archivada no hace nada. Emite PROPERTY_STATUS_CHANGED.\nScope requerido: properties:write.","operationId":"PublicPropertyActionsController_archive","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Archivar (eliminar) una propiedad","tags":["Propiedades"]}},"/v1/properties/{id}/metrics":{"get":{"description":"Último dato de visitas, contactos y clics de cada portal donde la propiedad tiene estadísticas, más los totales. Los valores son acumulados del aviso y se actualizan cuando TochiHub sincroniza con cada portal (ver sync en GET /v1/portals). Las propiedades sandbox no tienen estadísticas.\nScope requerido: properties:read.","operationId":"PublicPropertiesController_getMetrics","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyMetricsDto"},"example":{"propertyId":"clw2v8c4m0000u7w4mr9db4kn","externalId":"crm-prop-12345","totals":{"views":1890,"contacts":21,"clicks":140},"portals":[{"portalCode":"MERCADO_LIBRE","portalName":"Mercado Libre","views":1240,"contacts":12,"clicks":80,"sharedViewsWith":["PORTAL_INMOBILIARIO"],"measuredAt":"2026-10-10T06:00:00.000Z"},{"portalCode":"PORTAL_INMOBILIARIO","portalName":"Portal Inmobiliario","views":1240,"contacts":6,"clicks":45,"sharedViewsWith":["MERCADO_LIBRE"],"measuredAt":"2026-10-10T06:00:00.000Z"},{"portalCode":"TOCTOC","portalName":"TocToc","views":650,"contacts":3,"clicks":15,"sharedViewsWith":[],"measuredAt":"2026-10-10T06:00:00.000Z"}]}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Estadísticas por portal","tags":["Propiedades"]}},"/v1/properties/{id}/media":{"post":{"description":"Agrega fotos por URL pública al final de la galería (o en el sortOrder indicado). Recalcula el estado y sincroniza los portales activos.\nScope requerido: properties:write.","operationId":"PublicPropertiesController_addMedia","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddPublicPropertyMediaDto"}}}},"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Agregar fotos","tags":["Propiedades"]}},"/v1/properties/{id}/pause":{"post":{"description":"Retira los avisos activos de todos los portales y deja la propiedad en PAUSED (Mercado Libre y Portal Inmobiliario quedan pausados, no cerrados). Solo aplica a propiedades PUBLISHED. Emite PROPERTY_STATUS_CHANGED.\nScope requerido: properties:write.","operationId":"PublicPropertyActionsController_pause","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Pausar una propiedad publicada","tags":["Propiedades"]}},"/v1/properties/{id}/resume":{"post":{"description":"Vuelve a publicar en los portales donde estaba publicada al pausarse. Solo aplica a propiedades PAUSED con al menos 3 fotos. Si un portal no está listo (credenciales, datos o cupo), se omite y la propiedad se reanuda en los demás; revisa el estado por portal en la respuesta. Si ningún portal puede reanudarse, responde 400 y la propiedad sigue PAUSED. Emite PROPERTY_STATUS_CHANGED.\nScope requerido: properties:write.","operationId":"PublicPropertyActionsController_resume","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Reanudar una propiedad pausada","tags":["Propiedades"]}},"/v1/properties/{id}/media/{mediaId}":{"patch":{"description":"Cambia el orden (sortOrder) o el texto alternativo de una foto. El id viene en media[].id del detalle. Sincroniza los portales activos y emite PROPERTY_UPDATED.\nScope requerido: properties:write.","operationId":"PublicPropertyActionsController_updateMedia","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."},{"name":"mediaId","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePublicPropertyMediaDto"}}}},"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Editar una foto","tags":["Propiedades"]},"delete":{"description":"Quita la foto de la galería y recalcula el estado. En una propiedad PUBLISHED no se puede bajar de 3 fotos (páusala primero). Sincroniza los portales activos y emite PROPERTY_UPDATED.\nScope requerido: properties:write.","operationId":"PublicPropertyActionsController_deleteMedia","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."},{"name":"mediaId","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Eliminar una foto","tags":["Propiedades"]}},"/v1/portals":{"get":{"description":"Todos los portales con publicación automática, indicando si la corredora puede publicar ahora (available/status), el cupo usado y disponible, la cuenta conectada y el estado de sincronización (publicaciones en curso, con error y última lectura de estadísticas). Úsalo antes de publicar para elegir portales con cupo, o para rotar avisos. Con una key de prueba todos los portales aparecen disponibles y sin límite.\nScope requerido: properties:read.","operationId":"PublicPublicationsController_listPortals","parameters":[],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicPortalDto"}},"example":[{"code":"MERCADO_LIBRE","name":"Mercado Libre","available":true,"status":"AVAILABLE","statusDescription":"Disponible para publicar.","credentialSource":"BROKER","credentialValidatedAt":"2026-10-01T12:00:00.000Z","quota":{"active":37,"limit":100,"remaining":63},"sync":{"inProgress":2,"failed":1,"statsLastSyncedAt":"2026-10-10T06:00:00.000Z","statsLastAttemptAt":"2026-10-10T06:00:00.000Z","statsLastError":null}},{"code":"TOCTOC","name":"TocToc","available":false,"status":"QUOTA_EXHAUSTED","statusDescription":"Sin cupo: despublica otra propiedad de este portal para liberar uno.","credentialSource":"PLATFORM","credentialValidatedAt":"2026-10-02T09:30:00.000Z","quota":{"active":20,"limit":20,"remaining":0},"sync":{"inProgress":0,"failed":0,"statsLastSyncedAt":"2026-10-09T06:00:00.000Z","statsLastAttemptAt":"2026-10-10T06:00:00.000Z","statsLastError":"TocToc no respondió a tiempo"}},{"code":"YAPO","name":"Yapo","available":false,"status":"MISSING_CREDENTIALS","statusDescription":"Falta conectar la cuenta del portal en TochiHub (Configuración → Conexiones).","credentialSource":null,"credentialValidatedAt":null,"quota":{"active":0,"limit":50,"remaining":50},"sync":{"inProgress":0,"failed":0,"statsLastSyncedAt":null,"statsLastAttemptAt":null,"statsLastError":null}}]}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Listar portales y su estado","tags":["Publicaciones"]}},"/v1/properties/validate":{"post":{"description":"Corre las mismas validaciones por portal que la publicación real (fotos mínimas, título, superficie, comuna, ubicación, etc.) y devuelve cada problema con su explicación en español. No crea ni publica nada.\nScope requerido: properties:read.","operationId":"PublicPublicationsController_validate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidatePropertyDto"}}}},"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PropertyValidationResultDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Validar una propiedad contra los portales (sin publicar)","tags":["Publicaciones"]}},"/v1/properties/{id}/publications":{"get":{"description":"Un registro por portal: estado, URL del aviso y último error (original y en español).\nScope requerido: properties:read.","operationId":"PublicPublicationsController_status","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicationStatusDto"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Estado de publicación por portal","tags":["Publicaciones"]},"post":{"description":"Encola la publicación en cada portal pedido y responde de inmediato con el resultado por portal (un portal rechazado no bloquea a los demás). El resultado final llega por el webhook PROPERTY_PUBLICATION_COMPLETED o consultando el estado. Requiere al menos 3 fotos. Con una key de prueba se simula: corre las validaciones reales, nunca contacta al portal y devuelve URLs de sandbox.\nScope requerido: properties:write.","operationId":"PublicPublicationsController_publish","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishPortalsDto"}}}},"responses":{"202":{"description":"Solicitud de publicación recibida; revisa el resultado de cada portal.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PublicationRequestResultDto"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Publicar en portales","tags":["Publicaciones"]}},"/v1/properties/{id}/publications/{portalCode}":{"delete":{"description":"Encola la baja del aviso en ese portal. Solo aplica si la publicación está activa (SUCCESS).\nScope requerido: properties:write.","operationId":"PublicPublicationsController_unpublish","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."},{"name":"portalCode","required":true,"in":"path","schema":{"$ref":"#/components/schemas/PortalCode"},"description":"Código del portal destino."}],"responses":{"202":{"description":"Solicitud de publicación recibida; revisa el resultado de cada portal.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicationRequestResultDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:write","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Despublicar de un portal","tags":["Publicaciones"]}},"/v1/usage":{"get":{"description":"Cuántas propiedades cuentan para el cupo del plan, el máximo y cuántas puedes crear todavía. Crear y publicar tienen cupos distintos: el cupo de avisos por portal está en GET /v1/portals. Con una key de prueba cuenta solo propiedades sandbox, sin límite.\nScope requerido: properties:read.","operationId":"PublicUsageController_getUsage","parameters":[],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicUsageDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: properties:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Cupo de propiedades del plan","tags":["Publicaciones"]}},"/v1/leads":{"get":{"description":"Requiere leads:read. Lista los contactos de la corredora, más recientes primero, con paginación y filtros por propiedad/canal. Una key de prueba solo ve leads de propiedades sandbox.\nScope requerido: leads:read.","operationId":"PublicLeadsController_list","parameters":[{"name":"page","required":false,"in":"query","description":"Página, desde 1.","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Resultados por página.","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"propertyId","required":false,"in":"query","description":"Filtrar por el id de una propiedad.","schema":{"type":"string"}},{"name":"channel","required":false,"in":"query","description":"Canal de origen del lead.","schema":{"type":"string","enum":["MANUAL","INTERNAL_FORM","WHATSAPP","PORTAL_CONTACT"]}}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicLeadListDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"400":{"description":"Body o parámetros inválidos; error.details lista los campos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"bad_request","message":"La validación del request falló","details":["title must be a string"],"requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: leads:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Listar leads","tags":["Leads"]}},"/v1/leads/{id}":{"get":{"description":"Requiere leads:read. Devuelve el contacto, su mensaje y la propiedad consultada, dentro de la corredora y del modo de la API key.\nScope requerido: leads:read.","operationId":"PublicLeadsController_getOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"},"description":"Identificador del recurso, devuelto al crearlo o listarlo."}],"responses":{"200":{"description":"Solicitud completada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicLeadDto"}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"401":{"description":"Falta el header x-api-key, o la key es inválida o fue revocada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"unauthorized","message":"API key inválida o revocada","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"403":{"description":"La key no tiene el scope requerido, o el plan/la suscripción de la corredora no lo permite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"forbidden","message":"La API key no tiene el scope requerido: leads:read","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"404":{"description":"El recurso no existe o pertenece a otra corredora / otro modo (prueba vs producción).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"not_found","message":"La propiedad no existe o no pertenece a esta API key","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}}}},"429":{"description":"Superaste el rate limit; espera los segundos del header Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicApiErrorDto"},"example":{"error":{"code":"rate_limit_exceeded","message":"Superaste el límite de requests de la API pública; reintenta después de Retry-After segundos","requestId":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","timestamp":"2026-10-05T14:03:00.000Z"}}}},"headers":{"X-RateLimit-Limit":{"description":"Cupo de solicitudes por ventana.","schema":{"type":"integer","example":120}},"X-RateLimit-Remaining":{"description":"Solicitudes restantes de esta API key.","schema":{"type":"integer","example":119}},"X-RateLimit-Reset":{"description":"Reinicio de la ventana, epoch en segundos.","schema":{"type":"integer","example":1791209040}},"x-request-id":{"description":"Identificador de diagnóstico de la solicitud.","schema":{"type":"string","example":"solicitud-123"}},"Retry-After":{"description":"Segundos a esperar antes de reintentar.","schema":{"type":"integer","example":30}}}}},"security":[{"public-api-key":[]}],"summary":"Obtener un lead","tags":["Leads"]}}},"info":{"title":"API de TochiHub","description":"## Inicio de una integración\n\nÚltima actualización: 2026-10-20. Los cambios están en Historial de cambios, al final de este documento.\n\nURL base: https://docs.tochihub.cl/v1. Todas las rutas de este documento incluyen /v1.\nDocumentación interactiva: https://docs.tochihub.cl/v1/docs. Contrato JSON: https://docs.tochihub.cl/v1/openapi.json.\nMarkdown canónico para asistentes: https://docs.tochihub.cl/v1/docs.md.\n\nEn Configuración → Integraciones crea una API key. Guarda el secreto al crearlo o rotarlo: se muestra una sola vez.\nEnvía el header x-api-key en cada solicitud (excepto GET /v1/health y las rutas de documentación).\nScopes: properties:read (consultas y validación), properties:write (crear, editar, fotos, publicar/despublicar, pausar, reanudar y archivar), leads:read (consultar contactos).\nLa key pertenece a una corredora; nunca puede acceder a datos de otra. Debe estar activa, sin expirar, y su corredora debe estar activa con una suscripción habilitada.\n\n### Sandbox\n\nCrea una key en modo Prueba (th_test_) con properties:read y properties:write. Recibirás propiedades de ejemplo.\nUsa las mismas rutas y DTOs que en producción. Las propiedades sandbox quedan ocultas del panel, de las métricas y de las keys de producción (th_live_).\nLas publicaciones ejecutan las mismas validaciones de payload, pero se resuelven de inmediato sin jobs hacia portales reales, sin credenciales ni consumo de cupos.\nLas URLs https://sandbox.tochihub.cl/listings/... son identificadores ficticios de prueba, no avisos navegables.\nLos webhooks sí se entregan a la URL configurada; el body lleva livemode: false.\nLas keys TEST solo pueden leer leads asociados a propiedades sandbox, nunca contactos reales.\n\n### Flujo CRM\n\n1. Revisa GET /v1/usage (cupo de propiedades del plan) y GET /v1/portals: lista todos los portales con available/status, el cupo de avisos (quota.active, quota.limit, quota.remaining), la cuenta conectada y el estado de sincronización. Valida con POST /v1/properties/validate con property y portals.\n   Crear y publicar son acciones separadas con cupos distintos: puedes tener más propiedades en TochiHub que avisos en un portal y rotar cuáles se publican (despublica una para liberar cupo y publica otra).\n2. Crea POST /v1/properties con externalId del CRM y al menos 3 fotos por URL pública. Usa Idempotency-Key para reintentos.\n3. Actualiza por PATCH /v1/properties/:id; agrega fotos por POST /v1/properties/:id/media, reordénalas o cambia su texto con PATCH /v1/properties/:id/media/:mediaId y elimínalas con DELETE /v1/properties/:id/media/:mediaId (el id viene en media[].id). Guardar no publica. Los cambios de propiedades reales ya publicadas sincronizan sus portales activos.\n   GET /v1/properties/:id devuelve todo lo guardado, incluidos amenities y characteristics. PATCH con characteristics reemplaza el objeto completo: lee, combina y envía el objeto entero.\n4. Publica por POST /v1/properties/:id/publications con { \"portals\": [\"YAPO\"] }. Cada portal devuelve su propio accepted/error. Producción responde 202 y procesa en segundo plano. Si incluyes MERCADO_LIBRE y PORTAL_INMOBILIARIO en la misma llamada, ambos comparten un único aviso y un solo cupo; publicarlos en llamadas separadas crea dos avisos. Para reintentar un portal que falló, vuelve a llamar esta ruta con ese portal.\n5. Consulta GET /v1/properties/:id/publications o recibe PROPERTY_PUBLICATION_COMPLETED. DELETE /v1/properties/:id/publications/:portalCode despublica de un portal.\n6. Pausa con POST /v1/properties/:id/pause (retira los avisos de todos los portales) y reanuda con POST /v1/properties/:id/resume (vuelve a publicar donde estaba).\n7. Elimina con DELETE /v1/properties/:id: archiva la propiedad. Antes despublícala de todos los portales; si queda alguno activo responde 400.\n8. Recibe LEAD_CREATED y recupera GET /v1/leads/:id con leads:read.\n   Consulta GET /v1/properties/:id/metrics para las visitas, contactos y clics de cada portal (valores acumulados del aviso). Mercado Libre y Portal Inmobiliario muestran un único aviso: ambos portales informan las mismas visitas, cada uno lista al otro en sharedViewsWith y totals.views las suma una sola vez. Si guardas visitas por portal, no sumes las de portales que se listan en sharedViewsWith. Contactos y clics son propios de cada portal y sí se suman.\n9. Suscríbete a PROPERTY_UPDATED y PROPERTY_STATUS_CHANGED para enterarte de los cambios hechos desde el panel de TochiHub.\n   Todos los webhooks de propiedad (PROPERTY_CREATED, PROPERTY_UPDATED, PROPERTY_STATUS_CHANGED y PROPERTY_PUBLICATION_COMPLETED) incluyen externalId, el id de tu CRM, o null si la propiedad no se creó con uno.\n\nIdempotency-Key se conserva 7 días, aislada por corredora y modo. Repetirla con el mismo body devuelve la respuesta original; otro body devuelve 409. Una respuesta en curso también devuelve 409: reintenta después.\nLos estados DRAFT/READY se calculan (READY requiere título, precio positivo y 3 fotos). Los portales pueden exigir más campos: valida antes de publicar.\nLa validación comprueba el payload, sin enviar solicitudes al portal; una aceptación definitiva depende de sus credenciales, plan y respuesta externa.\n\n### Paginación y errores\n\nListados: { items: [...], total, page, limit }. page parte en 1; limit por defecto 20, máximo 100. Para recorrer todo: incrementa page hasta page * limit >= total.\nErrores: { \"error\": { \"code\": \"bad_request\", \"message\": \"La validación del request falló\", \"details\": [\"campo inválido\"], \"requestId\": \"id\", \"timestamp\": \"2026-10-05T14:03:00Z\" } }.\n400: payload inválido; 401: key ausente/inválida/revocada/expirada; 403: scope insuficiente o corredora inhabilitada; 404: recurso ausente/no accesible; 409: conflicto de idempotencia; 429: rate limit; 500: error inesperado.\nGuarda x-request-id para diagnóstico. No reintentes 400/401/403 sin corregir la causa. Para 429 espera Retry-After; para 5xx usa backoff y conserva Idempotency-Key al crear.\nRate limit por API key: por defecto 120 solicitudes por 60 segundos, compartido con MCP.\nHeaders: X-RateLimit-Limit (cupo), X-RateLimit-Remaining (restante), X-RateLimit-Reset (epoch de reinicio), Retry-After (segundos, al responder 429).\n\n## Webhooks salientes firmados\n\nConfigura URL y eventos en Configuración → Integraciones. Solo OWNER/ADMIN de la corredora pueden gestionarlos.\nCopia el secreto al crear o rotar. El listado solo muestra una vista enmascarada. Al rotar, las entregas incluyen firmas del secreto nuevo y del anterior durante 24 horas.\nHeaders: X-TochiHub-Signature: v1=<hex HMAC-SHA256>, X-TochiHub-Timestamp: <epoch segundos>, X-TochiHub-Event y X-TochiHub-Delivery.\nFirma exactamente timestamp + \".\" + body crudo en UTF-8. Nunca reserialices JSON antes de verificar. Durante la rotación puede haber varias firmas v1 separadas por coma: basta una válida.\nRechaza timestamps fuera de una tolerancia de 300 segundos y compara en tiempo constante.\nBody: { id, event, livemode, createdAt, data }. id es el identificador estable de entrega; el secreto nunca viaja en el body.\nEntrega al menos una vez: deduplica por id. Persiste el evento antes de responder 2xx y procesa tu lógica después.\nTimeout 10 segundos, hasta 5 intentos totales, backoff exponencial desde 30 segundos (30, 60, 120, 240). Un timeout o cualquier respuesta fuera de 2xx cuenta como fallo.\nCada intento firma el mismo evento con un timestamp nuevo. El historial de entregas está en el admin y en get_integration_status.\nEnviar prueba usa datos ficticios y livemode: false; también puedes probar publicaciones completas con una key TEST.\n\n### Verificar en Node.js\n\nEjemplo con Express. Define persistOnce(id, event) en tu almacenamiento: una inserción durable con id único debe ignorar duplicados. Si falla la persistencia, responde 5xx. Configura TOCHIHUB_WEBHOOK_SECRET en tu receptor, sin imprimirlo.\n\n```javascript\nimport express from 'express';\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\nconst app = express();\nconst secret = process.env.TOCHIHUB_WEBHOOK_SECRET;\nif (!secret) throw new Error('Falta TOCHIHUB_WEBHOOK_SECRET');\n\napp.post('/webhooks/tochihub', express.raw({ type: 'application/json' }), async (req, res) => {\n  const timestampText = req.get('X-TochiHub-Timestamp') ?? '';\n  const timestamp = Number(timestampText);\n  const signatures = (req.get('X-TochiHub-Signature') ?? '').split(',');\n  const fresh = /^\\d+$/.test(timestampText) &&\n    Number.isSafeInteger(timestamp) && Math.abs(Date.now() / 1000 - timestamp) <= 300;\n  const expected = createHmac('sha256', secret)\n    .update(timestampText + '.').update(req.body).digest();\n  const valid = fresh && signatures.some((part) => {\n    const match = /^v1=([a-f0-9]{64})$/.exec(part.trim());\n    return match !== null && timingSafeEqual(Buffer.from(match[1], 'hex'), expected);\n  });\n  if (!valid) return res.sendStatus(401);\n  const event = JSON.parse(req.body.toString('utf8'));\n  await persistOnce(event.id, event);\n  res.sendStatus(204);\n});\n\napp.listen(8080);\n```\n\n### LEAD_CREATED\n\nLlegó un lead nuevo (desde un portal, el sitio o cargado a mano) asociado a una propiedad.\n\n```json\n{\n  \"id\": \"delivery-ejemplo\",\n  \"event\": \"LEAD_CREATED\",\n  \"livemode\": false,\n  \"createdAt\": \"2026-10-05T14:03:00.000Z\",\n  \"data\": {\n    \"leadId\": \"cm1lead0000000000000000\",\n    \"propertyId\": \"cm1prop0000000000000000\",\n    \"channel\": \"PORTAL_CONTACT\",\n    \"contactName\": \"Camila Rojas\",\n    \"contactPhone\": \"+56912345678\",\n    \"contactEmail\": \"camila@example.com\",\n    \"message\": \"Hola, ¿sigue disponible el departamento?\",\n    \"createdAt\": \"2026-10-05T14:03:00.000Z\"\n  }\n}\n```\n\n### PROPERTY_CREATED\n\nSe creó una propiedad (en el panel, por WhatsApp o por la API).\n\n```json\n{\n  \"id\": \"delivery-ejemplo\",\n  \"event\": \"PROPERTY_CREATED\",\n  \"livemode\": false,\n  \"createdAt\": \"2026-10-05T14:03:00.000Z\",\n  \"data\": {\n    \"propertyId\": \"cm1prop0000000000000000\",\n    \"externalId\": \"crm-prop-12345\",\n    \"title\": \"Departamento 2D2B en Providencia\",\n    \"operationType\": \"SALE\",\n    \"status\": \"DRAFT\",\n    \"createdAt\": \"2026-10-05T14:03:00.000Z\"\n  }\n}\n```\n\n### PROPERTY_PUBLICATION_COMPLETED\n\nTerminó una publicación, actualización o baja en un portal (con éxito o con error definitivo; nunca en un reintento).\n\n```json\n{\n  \"id\": \"delivery-ejemplo\",\n  \"event\": \"PROPERTY_PUBLICATION_COMPLETED\",\n  \"livemode\": false,\n  \"createdAt\": \"2026-10-05T14:03:00.000Z\",\n  \"data\": {\n    \"propertyId\": \"cm1prop0000000000000000\",\n    \"externalId\": \"crm-prop-12345\",\n    \"portalCode\": \"YAPO\",\n    \"action\": \"PUBLISH\",\n    \"succeeded\": false,\n    \"errorMessage\": \"Yapo requires the built area (square, m²) on the property.\",\n    \"errorDescription\": \"Falta la superficie construida (m²).\"\n  }\n}\n```\n\n### PROPERTY_UPDATED\n\nSe editó una propiedad o su galería (en el panel o por la API). Trae el estado actual; consulta GET /v1/properties/{id} para el detalle.\n\n```json\n{\n  \"id\": \"delivery-ejemplo\",\n  \"event\": \"PROPERTY_UPDATED\",\n  \"livemode\": false,\n  \"createdAt\": \"2026-10-05T14:03:00.000Z\",\n  \"data\": {\n    \"propertyId\": \"cm1prop0000000000000000\",\n    \"externalId\": \"crm-prop-12345\",\n    \"status\": \"PUBLISHED\",\n    \"updatedAt\": \"2026-10-05T14:03:00.000Z\"\n  }\n}\n```\n\n### PROPERTY_STATUS_CHANGED\n\nUna propiedad se pausó, se reanudó o se archivó (en el panel o por la API).\n\n```json\n{\n  \"id\": \"delivery-ejemplo\",\n  \"event\": \"PROPERTY_STATUS_CHANGED\",\n  \"livemode\": false,\n  \"createdAt\": \"2026-10-05T14:03:00.000Z\",\n  \"data\": {\n    \"propertyId\": \"cm1prop0000000000000000\",\n    \"externalId\": \"crm-prop-12345\",\n    \"previousStatus\": \"PUBLISHED\",\n    \"status\": \"PAUSED\",\n    \"changedAt\": \"2026-10-05T14:03:00.000Z\"\n  }\n}\n```\n\n### INBOX_MESSAGE_RECEIVED\n\nEntró un mensaje nuevo a la bandeja de entrada.\n\n```json\n{\n  \"id\": \"delivery-ejemplo\",\n  \"event\": \"INBOX_MESSAGE_RECEIVED\",\n  \"livemode\": false,\n  \"createdAt\": \"2026-10-05T14:03:00.000Z\",\n  \"data\": {\n    \"conversationId\": \"cm1conv0000000000000000\",\n    \"messageId\": \"cm1msg00000000000000000\",\n    \"channel\": \"WHATSAPP\",\n    \"contactName\": \"Camila Rojas\",\n    \"contactPhone\": \"+56912345678\",\n    \"body\": \"¿Puedo visitar el depto el sábado?\"\n  }\n}\n```\n\n### TICKET_CREATED\n\nSe creó un ticket de seguimiento (manual o porque el asistente derivó la conversación).\n\n```json\n{\n  \"id\": \"delivery-ejemplo\",\n  \"event\": \"TICKET_CREATED\",\n  \"livemode\": false,\n  \"createdAt\": \"2026-10-05T14:03:00.000Z\",\n  \"data\": {\n    \"ticketId\": \"cm1tick0000000000000000\",\n    \"title\": \"Cliente pide visita el sábado\",\n    \"priority\": \"MEDIUM\",\n    \"source\": \"BOT_FALLBACK\",\n    \"conversationId\": \"cm1conv0000000000000000\"\n  }\n}\n```\n\n## MCP para integrar con tu asistente\n\nEndpoint: https://docs.tochihub.cl/v1/mcp. Transporte Streamable HTTP sin estado; POST con JSON-RPC, sin sesión persistente. GET/DELETE responden 405.\nAutentica con x-api-key; cada tool valida su scope. Crear propiedades con LIVE modifica datos reales; empieza con TEST.\nRecursos: tochihub://docs.md (text/markdown) y tochihub://openapi.json (application/json), requieren properties:read.\n\n### Claude Code\n\n```sh\nclaude mcp add --transport http tochihub https://docs.tochihub.cl/v1/mcp --header \"x-api-key: th_test_REEMPLAZAR\"\n```\n\n### Cursor (.cursor/mcp.json)\n\n```json\n{\n  \"mcpServers\": {\n    \"tochihub\": {\n      \"url\": \"https://docs.tochihub.cl/v1/mcp\",\n      \"headers\": {\n        \"x-api-key\": \"th_test_REEMPLAZAR\"\n      }\n    }\n  }\n}\n```\n\n### Tools y scopes\n\n- search_properties (properties:read): Buscar propiedades paginadas, incluido externalId del CRM.\n- get_property (properties:read): Leer una propiedad con sus fotos.\n- get_api_reference (properties:read): Leer docs.md u openapi.json, el contrato completo de integración.\n- validate_property_payload (properties:read): Validar un payload o propiedad existente con los mappers reales, sin publicar.\n- create_property (properties:write): Crear una propiedad, en sandbox con th_test_ o en producción con th_live_. Admite Idempotency-Key.\n- get_publication_status (properties:read): Consultar estado, URL y errores por portal.\n- list_webhook_events (properties:read): Leer catálogo y ejemplos de eventos.\n- send_test_webhook (properties:write): Enviar un evento de prueba a un webhook existente de la corredora.\n- get_integration_status (properties:read): Ver últimas 50 solicitudes de esta key (7 días), endpoints y últimas 50 entregas de su corredora.\n\n### Errores de las tools\n\nUna tool que falla responde con isError: true y el mismo cuerpo de error que la API REST, sin requestId: { \"error\": { \"code\": \"bad_request\", \"message\": \"El payload no cumple el contrato de la API\", \"details\": [\"bedrooms must be an integer number\", \"property foo should not exist\"] } }. details nombra cada campo inválido (con su ruta, por ejemplo media.0.url) para que el asistente corrija el mapeo y reintente. get_integration_status muestra las URLs de webhooks sin query string ni credenciales.\n\nPrompt sugerido: \"Lee get_api_reference, mapea los campos de mi CRM, valida una propiedad para YAPO y TOCTOC, créala con esta key sandbox y revisa get_publication_status y get_integration_status. No uses una key de producción.\"\n\n## Historial de cambios\n\n### 2026-10-20\n\n- Publicar MERCADO_LIBRE y PORTAL_INMOBILIARIO en la misma llamada crea un único aviso visible en ambos portales y consume un solo cupo del paquete. Si uno de los dos ya está publicado, el otro reutiliza ese aviso.\n- Mientras Mercado Libre asigna el cupo del paquete a un aviso nuevo, la publicación queda PENDING en vez de FAILED y PROPERTY_PUBLICATION_COMPLETED se envía cuando el aviso se activa o es rechazado.\n- Yapo y TocToc publican usefulAreaM2 como superficie construida. Antes recibían totalAreaM2 en ese campo. En casas, parcelas y terrenos, TocToc recibe totalAreaM2 como superficie de terreno.\n\n### 2026-10-19\n\n- La creación de propiedades y su evento PROPERTY_CREATED se guardan en la misma transacción, incluida la idempotencia. Las entregas pendientes se recuperan después de una caída de Redis conservando el identificador para deduplicar.\n- Si una publicación termina mientras la propiedad está pausada, se persiste una despublicación de compensación recuperable. Una reanudación cancela esa compensación antes de ejecutarla.\n\n### 2026-10-14\n\n- POST /v1/properties/{id}/resume vuelve a publicar solo en los portales donde la propiedad estaba publicada al pausarla. Si un portal no está listo, se omite y la propiedad se reanuda en los demás; el detalle devuelto muestra el estado de cada portal.\n\n### 2026-10-10\n\n- GET /v1/properties/{id}/metrics agrega sharedViewsWith: los portales que comparten el contador de visitas del mismo aviso (Mercado Libre y Portal Inmobiliario).\n- Los ejemplos de error 401, 403, 404 y 429 muestran el código y mensaje reales de cada caso; el 403 nombra el scope de la operación.\n- Los campos que pueden ser null se documentan con su tipo real (number o string) en vez de object.\n- GET /v1/portals lista todos los portales con disponibilidad, cupo de avisos y estado de sincronización.\n- Nuevo GET /v1/usage con el cupo de propiedades del plan.\n- Nuevo GET /v1/properties/{id}/metrics con vistas, contactos y clics por portal.\n- Nuevas rutas para pausar, reanudar y archivar propiedades, y para editar o eliminar fotos.\n- Nuevos webhooks PROPERTY_UPDATED y PROPERTY_STATUS_CHANGED; todos los webhooks de propiedad incluyen externalId.\n","version":"1.0","contact":{},"x-last-updated":"2026-10-20"},"tags":[],"servers":[{"url":"https://docs.tochihub.cl","description":"URL pública configurable"}],"components":{"securitySchemes":{"public-api-key":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key de la corredora (th_live_ o th_test_). Cada operación exige su scope."}},"schemas":{"OperationType":{"type":"string","enum":["SALE","RENT"],"description":"SALE = venta, RENT = arriendo."},"PriceCurrency":{"type":"string","enum":["CLP","UF"]},"PropertyMediaType":{"type":"string","enum":["IMAGE","VIDEO","TOUR_360","DOCUMENT"],"description":"Tipo de archivo. Solo las IMAGE cuentan para el mínimo de 3 fotos."},"CreatePublicPropertyMediaDto":{"type":"object","properties":{"type":{"default":"IMAGE","description":"Tipo de archivo. Solo las IMAGE cuentan para el mínimo de 3 fotos.","allOf":[{"$ref":"#/components/schemas/PropertyMediaType"}]},"url":{"type":"string","example":"https://cdn.tu-crm.cl/propiedades/apt-123/principal.jpg","description":"URL pública (HTTPS) de la foto. Los portales la descargan tal cual: debe ser accesible sin autenticación."},"sortOrder":{"type":"number","example":0,"minimum":0,"description":"Orden de la foto; la de menor orden es la portada."},"altText":{"type":"string","example":"Living comedor con vista al cerro"}},"required":["url"]},"CreatePublicPropertyDto":{"type":"object","properties":{"title":{"type":"string","example":"Departamento 2D2B a pasos del Metro Manquehue","description":"Título del aviso. Yapo exige al menos 10 caracteres; TocToc entre 10 y 70."},"description":{"type":"string","example":"Departamento luminoso con estacionamiento y bodega, orientación norte.","description":"Descripción del aviso en texto plano (si llega HTML se convierte a texto). TocToc exige al menos 50 caracteres."},"operationType":{"example":"SALE","description":"SALE = venta, RENT = arriendo.","allOf":[{"$ref":"#/components/schemas/OperationType"}]},"priceValue":{"type":"number","example":6250,"minimum":0,"description":"Precio como entero. Los precios en UF también van como entero."},"priceCurrency":{"example":"UF","allOf":[{"$ref":"#/components/schemas/PriceCurrency"}]},"propertyType":{"type":"string","example":"departamento","description":"Tipo de propiedad: departamento, casa, oficina, local, terreno, parcela, bodega, estacionamiento."},"bedrooms":{"type":"number","example":2,"minimum":0,"description":"Dormitorios."},"bathrooms":{"type":"number","example":2,"minimum":0,"description":"Baños."},"parkingSpaces":{"type":"number","example":1,"minimum":0,"description":"Estacionamientos."},"storageUnits":{"type":"number","example":1,"minimum":0,"description":"Bodegas."},"totalAreaM2":{"type":"number","example":35.2,"minimum":0,"description":"Superficie total en m². En casas, parcelas y terrenos es la superficie del terreno. Admite decimales."},"usefulAreaM2":{"type":"number","example":33.4,"minimum":0,"description":"Superficie útil en m². Yapo y TocToc la publican como superficie construida; si falta, Yapo usa la superficie total. Admite decimales."},"terraceAreaM2":{"type":"number","example":1.8,"minimum":0,"description":"Superficie de terraza en m². Admite decimales."},"commonExpenses":{"type":"number","example":120000,"nullable":true,"description":"Gastos comunes mensuales en CLP. Omitirlos o enviar 0 significa \"no informado\": los portales no muestran gastos comunes. En PATCH, null borra el valor guardado."},"yearBuilt":{"type":"number","example":2015,"description":"Año de construcción."},"lat":{"type":"number","example":-33.4072,"description":"Latitud. Varios portales exigen la ubicación en el mapa."},"lng":{"type":"number","example":-70.5681,"description":"Longitud."},"addressLine":{"type":"string","example":"Av. Apoquindo 4501"},"reference":{"type":"string","example":"A pasos del Metro Manquehue","description":"Referencia de ubicación para el aviso."},"propertyRole":{"type":"string","example":"123-45","description":"Rol de avalúo (SII). TocToc lo lee."},"unitNumber":{"type":"string","example":"1203","description":"Número de departamento u oficina."},"commune":{"type":"string","example":"Las Condes","description":"Comuna, con tildes y ñ (ej. \"Ñuñoa\")."},"region":{"type":"string","example":"Región Metropolitana"},"amenities":{"type":"object","example":{"comfort":{"pool":true,"gym":true},"security":{"elevator":true},"special":{"furnished":false}},"additionalProperties":true,"description":"Amenidades por grupo (grupo → clave → booleano). true = la propiedad la tiene; false = no la tiene, y se publica como \"No\"; omitirla = no informado, y no se publica. Claves que leen los portales: comfort (pool, gym, bbq, sauna, laundry, washerHookup, rooftop, fireplace, gamesRoom, cinemaRoom, eventsRoom, greenAreas, playground, bikeStorage, tennisCourt), security (elevator, concierge, alarmSystem, automaticGate, gatedCommunity, visitorParking, controlledAccess), services (heating, naturalGas), environments (attic, jacuzzi, dailyDining, suiteBedroom, walkInCloset, guestBathroom) y special (furnished, petsAllowed). Envía solo lo que conoces."},"characteristics":{"type":"object","example":{"orientation":"norte","floorLevel":12},"additionalProperties":true,"description":"Datos extra que algunos portales leen (orientation, floorLevel, videoTourUrl, contactName, contactPhone, contactEmail, ...). La clave \"external\" está reservada."},"externalId":{"type":"string","example":"crm-prop-12345","description":"Id estable de la propiedad en tu CRM. Úsalo para encontrarla después con GET /v1/properties?externalId=."},"clubId":{"type":"string","example":"clw2v8c4m0000u7w4mr9db4kn","description":"Id de una colección (club) de la corredora o global."},"status":{"type":"string","enum":["DRAFT","READY"],"deprecated":true,"description":"Obsoleto: se ignora. El estado se calcula solo (READY cuando tiene título, precio y al menos 3 fotos)."},"media":{"description":"Fotos por URL.","type":"array","items":{"$ref":"#/components/schemas/CreatePublicPropertyMediaDto"}}},"required":["title","operationType","priceValue","priceCurrency"]},"PropertyStatus":{"type":"string","enum":["DRAFT","READY","PUBLISHED","PAUSED","ARCHIVED"],"description":"Estado calculado: READY si ya cumple título, precio y 3 fotos."},"PublicPropertyResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"clw2v8c4m0000u7w4mr9db4kn","description":"Id de la propiedad en TochiHub."},"status":{"example":"READY","description":"Estado calculado: READY si ya cumple título, precio y 3 fotos.","allOf":[{"$ref":"#/components/schemas/PropertyStatus"}]},"mediaCount":{"type":"number","example":3,"description":"Cantidad de fotos/archivos asociados."},"sandbox":{"type":"boolean","example":false,"description":"true si se creó con una API key de prueba."},"createdAt":{"type":"string","example":"2026-10-05T14:03:00.000Z"}},"required":["id","status","mediaCount","sandbox","createdAt"]},"PublicApiErrorDetailDto":{"type":"object","properties":{"code":{"type":"string","example":"bad_request","description":"Código estable para tu código: bad_request, unauthorized, forbidden, not_found, conflict, rate_limit_exceeded, internal_error."},"message":{"type":"string","example":"La validación del request falló","description":"Mensaje legible en español."},"details":{"type":"object","example":["title must be a string"],"description":"Detalle opcional (por ejemplo, la lista de campos inválidos)."},"requestId":{"type":"string","example":"6c1b2a54-0f7e-4c55-9d0e-1f2b3c4d5e6f","description":"Igual al header x-request-id; inclúyelo al pedir soporte."},"timestamp":{"type":"string","example":"2026-10-05T14:03:00.000Z"}},"required":["code","message","requestId","timestamp"]},"PublicApiErrorDto":{"type":"object","properties":{"error":{"$ref":"#/components/schemas/PublicApiErrorDetailDto"}},"required":["error"]},"PublicPropertyMediaResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"clw2v8c4m0001u7w4abcd1234","description":"Id de la foto. Úsalo para editarla o eliminarla."},"url":{"type":"string","example":"https://cdn.tu-crm.cl/propiedades/apt-123/principal.jpg"},"type":{"type":"string","example":"IMAGE"},"sortOrder":{"type":"number","example":0},"altText":{"type":"string","nullable":true,"example":"Living comedor con vista al cerro"}},"required":["id","url","type","sortOrder"]},"PublicPropertyDetailResponseDto":{"type":"object","properties":{"id":{"type":"string","example":"clw2v8c4m0000u7w4mr9db4kn"},"externalId":{"type":"string","nullable":true,"example":"crm-prop-12345","description":"Id en tu CRM (el externalId que enviaste)."},"sandbox":{"type":"boolean","example":false,"description":"true si fue creada con una API key de prueba (nunca llega a portales reales)."},"title":{"type":"string","example":"Departamento 2D2B a pasos del Metro Manquehue"},"description":{"type":"string","nullable":true},"operationType":{"allOf":[{"$ref":"#/components/schemas/OperationType"}]},"status":{"description":"DRAFT: faltan datos o fotos. READY: lista para publicar. PUBLISHED: activa en al menos un portal. PAUSED / ARCHIVED.","allOf":[{"$ref":"#/components/schemas/PropertyStatus"}]},"priceValue":{"type":"number","example":6250},"priceCurrency":{"allOf":[{"$ref":"#/components/schemas/PriceCurrency"}]},"propertyType":{"type":"string","nullable":true,"example":"departamento"},"bedrooms":{"type":"number","nullable":true,"example":2},"bathrooms":{"type":"number","nullable":true,"example":2},"parkingSpaces":{"type":"number","nullable":true,"example":1},"storageUnits":{"type":"number","nullable":true,"example":1},"totalAreaM2":{"type":"number","nullable":true,"example":35.2},"usefulAreaM2":{"type":"number","nullable":true,"example":33.4},"terraceAreaM2":{"type":"number","nullable":true,"example":1.8},"commonExpenses":{"type":"number","nullable":true,"example":120000},"yearBuilt":{"type":"number","nullable":true,"example":2015},"lat":{"type":"number","nullable":true,"example":-33.4072},"lng":{"type":"number","nullable":true,"example":-70.5681},"addressLine":{"type":"string","nullable":true,"example":"Av. Apoquindo 4501"},"unitNumber":{"type":"string","nullable":true,"example":"1203"},"commune":{"type":"string","nullable":true,"example":"Las Condes"},"region":{"type":"string","nullable":true,"example":"Región Metropolitana"},"reference":{"type":"string","nullable":true,"example":"A pasos del Metro Manquehue"},"propertyRole":{"type":"string","nullable":true,"example":"123-45"},"clubId":{"type":"string","nullable":true,"example":"clw2v8c4m0000u7w4mr9db4kn"},"amenities":{"type":"object","additionalProperties":true,"example":{"comfort":{"pool":true},"special":{"furnished":false}},"description":"Amenidades guardadas, en el mismo formato que se envían."},"characteristics":{"type":"object","additionalProperties":true,"example":{"orientation":"norte","floorLevel":12},"description":"Características guardadas. Envíalas completas en el PATCH: el objeto se reemplaza entero."},"media":{"type":"array","items":{"$ref":"#/components/schemas/PublicPropertyMediaResponseDto"}},"createdAt":{"type":"string","example":"2026-10-05T14:03:00.000Z"},"updatedAt":{"type":"string","example":"2026-10-05T14:03:00.000Z"}},"required":["id","sandbox","title","operationType","status","priceValue","priceCurrency","amenities","characteristics","media","createdAt","updatedAt"]},"PublicPropertyListResponseDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicPropertyDetailResponseDto"}},"total":{"type":"number","example":42,"description":"Total de resultados con los filtros aplicados."},"page":{"type":"number","example":1},"limit":{"type":"number","example":20}},"required":["items","total","page","limit"]},"PublicPropertyMetricsTotalsDto":{"type":"object","properties":{"views":{"type":"number","example":1890,"description":"Suma de visitas. Un aviso compartido entre Mercado Libre y Portal Inmobiliario se cuenta una sola vez."},"contacts":{"type":"number","example":21,"description":"Suma de contactos de todos los portales."},"clicks":{"type":"number","example":140,"description":"Suma de clics de todos los portales."}},"required":["views","contacts","clicks"]},"PortalCode":{"type":"string","enum":["MERCADO_LIBRE","PORTAL_INMOBILIARIO","YAPO","TOCTOC","ENLACE_INMOBILIARIO","CHILE_DEPTOS","DOOMOS","PROPPIT","INSTAGRAM","FACEBOOK_MARKETPLACE","META_ADS","TIKTOK_ADS","TIKTOK"]},"PublicPortalMetricsDto":{"type":"object","properties":{"portalCode":{"example":"MERCADO_LIBRE","allOf":[{"$ref":"#/components/schemas/PortalCode"}]},"portalName":{"type":"string","example":"Mercado Libre"},"views":{"type":"number","nullable":true,"example":1240,"description":"Visitas acumuladas del aviso. null = el portal no la informa."},"contacts":{"type":"number","nullable":true,"example":12,"description":"Contactos acumulados. null = el portal no lo informa."},"clicks":{"type":"number","nullable":true,"example":80,"description":"Clics acumulados. null = el portal no lo informa."},"sharedViewsWith":{"type":"array","example":["PORTAL_INMOBILIARIO"],"description":"Portales que muestran este mismo aviso y comparten su contador de visitas (Mercado Libre y Portal Inmobiliario publican un único aviso). Cada portal informa el mismo valor de views, pero totals.views lo suma una sola vez. Vacío si el aviso no se comparte.","items":{"$ref":"#/components/schemas/PortalCode"}},"measuredAt":{"type":"string","example":"2026-10-10T06:00:00.000Z","description":"Momento en que se leyó este dato del portal."}},"required":["portalCode","portalName","sharedViewsWith","measuredAt"]},"PublicPropertyMetricsDto":{"type":"object","properties":{"propertyId":{"type":"string","example":"clw2v8c4m0000u7w4mr9db4kn"},"externalId":{"type":"string","nullable":true,"example":"crm-prop-12345"},"totals":{"$ref":"#/components/schemas/PublicPropertyMetricsTotalsDto"},"portals":{"description":"Último dato por portal. Un portal sin estadísticas no aparece.","type":"array","items":{"$ref":"#/components/schemas/PublicPortalMetricsDto"}}},"required":["propertyId","totals","portals"]},"UpdatePublicPropertyDto":{"type":"object","properties":{"title":{"type":"string","example":"Departamento 2D2B a pasos del Metro Manquehue","description":"Título del aviso. Yapo exige al menos 10 caracteres; TocToc entre 10 y 70."},"description":{"type":"string","example":"Departamento luminoso con estacionamiento y bodega, orientación norte.","description":"Descripción del aviso en texto plano (si llega HTML se convierte a texto). TocToc exige al menos 50 caracteres."},"operationType":{"example":"SALE","description":"SALE = venta, RENT = arriendo.","allOf":[{"$ref":"#/components/schemas/OperationType"}]},"priceValue":{"type":"number","example":6250,"minimum":0,"description":"Precio como entero. Los precios en UF también van como entero."},"priceCurrency":{"example":"UF","allOf":[{"$ref":"#/components/schemas/PriceCurrency"}]},"propertyType":{"type":"string","example":"departamento","description":"Tipo de propiedad: departamento, casa, oficina, local, terreno, parcela, bodega, estacionamiento."},"bedrooms":{"type":"number","example":2,"minimum":0,"description":"Dormitorios."},"bathrooms":{"type":"number","example":2,"minimum":0,"description":"Baños."},"parkingSpaces":{"type":"number","example":1,"minimum":0,"description":"Estacionamientos."},"storageUnits":{"type":"number","example":1,"minimum":0,"description":"Bodegas."},"totalAreaM2":{"type":"number","example":35.2,"minimum":0,"description":"Superficie total en m². En casas, parcelas y terrenos es la superficie del terreno. Admite decimales."},"usefulAreaM2":{"type":"number","example":33.4,"minimum":0,"description":"Superficie útil en m². Yapo y TocToc la publican como superficie construida; si falta, Yapo usa la superficie total. Admite decimales."},"terraceAreaM2":{"type":"number","example":1.8,"minimum":0,"description":"Superficie de terraza en m². Admite decimales."},"commonExpenses":{"type":"number","example":120000,"nullable":true,"description":"Gastos comunes mensuales en CLP. Omitirlos o enviar 0 significa \"no informado\": los portales no muestran gastos comunes. En PATCH, null borra el valor guardado."},"yearBuilt":{"type":"number","example":2015,"description":"Año de construcción."},"lat":{"type":"number","example":-33.4072,"description":"Latitud. Varios portales exigen la ubicación en el mapa."},"lng":{"type":"number","example":-70.5681,"description":"Longitud."},"addressLine":{"type":"string","example":"Av. Apoquindo 4501"},"reference":{"type":"string","example":"A pasos del Metro Manquehue","description":"Referencia de ubicación para el aviso."},"propertyRole":{"type":"string","example":"123-45","description":"Rol de avalúo (SII). TocToc lo lee."},"unitNumber":{"type":"string","example":"1203","description":"Número de departamento u oficina."},"commune":{"type":"string","example":"Las Condes","description":"Comuna, con tildes y ñ (ej. \"Ñuñoa\")."},"region":{"type":"string","example":"Región Metropolitana"},"amenities":{"type":"object","example":{"comfort":{"pool":true,"gym":true},"security":{"elevator":true},"special":{"furnished":false}},"additionalProperties":true,"description":"Amenidades por grupo (grupo → clave → booleano). true = la propiedad la tiene; false = no la tiene, y se publica como \"No\"; omitirla = no informado, y no se publica. Claves que leen los portales: comfort (pool, gym, bbq, sauna, laundry, washerHookup, rooftop, fireplace, gamesRoom, cinemaRoom, eventsRoom, greenAreas, playground, bikeStorage, tennisCourt), security (elevator, concierge, alarmSystem, automaticGate, gatedCommunity, visitorParking, controlledAccess), services (heating, naturalGas), environments (attic, jacuzzi, dailyDining, suiteBedroom, walkInCloset, guestBathroom) y special (furnished, petsAllowed). Envía solo lo que conoces."},"characteristics":{"type":"object","example":{"orientation":"norte","floorLevel":12},"additionalProperties":true,"description":"Datos extra que algunos portales leen (orientation, floorLevel, videoTourUrl, contactName, contactPhone, contactEmail, ...). La clave \"external\" está reservada."},"externalId":{"type":"string","example":"crm-prop-12345","description":"Id estable de la propiedad en tu CRM."}}},"AddPublicPropertyMediaDto":{"type":"object","properties":{"media":{"minItems":1,"maxItems":30,"type":"array","items":{"$ref":"#/components/schemas/CreatePublicPropertyMediaDto"}}},"required":["media"]},"UpdatePublicPropertyMediaDto":{"type":"object","properties":{"sortOrder":{"type":"number","example":0,"minimum":0,"description":"Nuevo orden; la de menor orden es la portada."},"altText":{"type":"string","example":"Living comedor con vista al cerro"}}},"PublicPortalQuotaDto":{"type":"object","properties":{"active":{"type":"number","example":37,"description":"Avisos activos (SUCCESS) de la corredora en este portal."},"limit":{"type":"number","nullable":true,"example":100,"description":"Máximo de avisos activos según el plan. null = sin límite; 0 = el plan no incluye el portal."},"remaining":{"type":"number","nullable":true,"example":63,"description":"Cupos libres. null = sin límite."}},"required":["active"]},"PublicPortalSyncDto":{"type":"object","properties":{"inProgress":{"type":"number","example":2,"description":"Publicaciones en cola o en proceso (QUEUED, RUNNING, RETRYING)."},"failed":{"type":"number","example":1,"description":"Publicaciones con error definitivo (FAILED). Consulta el detalle por propiedad."},"statsLastSyncedAt":{"type":"string","nullable":true,"example":"2026-10-10T06:00:00.000Z","description":"Última lectura exitosa de estadísticas de este portal. null = nunca."},"statsLastAttemptAt":{"type":"string","nullable":true,"example":"2026-10-10T06:00:00.000Z","description":"Último intento de leer estadísticas, exitoso o no."},"statsLastError":{"type":"string","nullable":true,"example":null,"description":"Error del último intento si falló; null si fue exitoso."}},"required":["inProgress","failed"]},"PublicPortalDto":{"type":"object","properties":{"code":{"example":"MERCADO_LIBRE","allOf":[{"$ref":"#/components/schemas/PortalCode"}]},"name":{"type":"string","example":"Mercado Libre"},"available":{"type":"boolean","example":true,"description":"true si se puede publicar en este portal ahora mismo."},"status":{"type":"string","enum":["AVAILABLE","QUOTA_EXHAUSTED","MISSING_CREDENTIALS","NOT_IN_PLAN","PLAN_INACTIVE"],"example":"AVAILABLE","description":"AVAILABLE: se puede publicar. QUOTA_EXHAUSTED: sin cupo; despublica otra propiedad para liberar uno. MISSING_CREDENTIALS: conecta la cuenta del portal en TochiHub. NOT_IN_PLAN: el plan no incluye el portal. PLAN_INACTIVE: el plan de la corredora no está activo."},"statusDescription":{"type":"string","example":"Disponible para publicar."},"credentialSource":{"type":"string","nullable":true,"enum":["BROKER","PLATFORM"],"description":"Cuenta que se usa para publicar: la propia de la corredora o la de TochiHub. null = ninguna."},"credentialValidatedAt":{"type":"string","nullable":true,"example":"2026-10-01T12:00:00.000Z","description":"Última validación exitosa de esa cuenta."},"quota":{"$ref":"#/components/schemas/PublicPortalQuotaDto"},"sync":{"$ref":"#/components/schemas/PublicPortalSyncDto"}},"required":["code","name","available","status","statusDescription","quota","sync"]},"ValidatePropertyDto":{"type":"object","properties":{"propertyId":{"type":"string","example":"clw2v8c4m0000u7w4mr9db4kn","description":"Valida una propiedad ya creada. Usa esto o property."},"property":{"description":"Valida un payload sin crearlo (mismo formato que POST /v1/properties).","allOf":[{"$ref":"#/components/schemas/CreatePublicPropertyDto"}]},"portals":{"type":"array","description":"Portales a validar. Por defecto, los habilitados para tu corredora.","items":{"$ref":"#/components/schemas/PortalCode"}}}},"PublicationIssueDto":{"type":"object","properties":{"message":{"type":"string","example":"Yapo requires the built area (square, m²) on the property.","description":"Mensaje original del portal o de la validación."},"description":{"type":"string","example":"Falta la superficie construida (m²).","description":"Explicación en español, lista para mostrar."}},"required":["message","description"]},"PortalValidationDto":{"type":"object","properties":{"portalCode":{"allOf":[{"$ref":"#/components/schemas/PortalCode"}]},"valid":{"type":"boolean","example":false},"errors":{"type":"array","items":{"$ref":"#/components/schemas/PublicationIssueDto"}}},"required":["portalCode","valid","errors"]},"PropertyValidationResultDto":{"type":"object","properties":{"valid":{"type":"boolean","example":false,"description":"true solo si pasa en todos los portales pedidos."},"portals":{"type":"array","items":{"$ref":"#/components/schemas/PortalValidationDto"}}},"required":["valid","portals"]},"PublicationStatus":{"type":"string","enum":["PENDING","QUEUED","RUNNING","SUCCESS","FAILED","RETRYING","CANCELED","UNPUBLISHED"],"description":"QUEUED/RUNNING/RETRYING: en curso. SUCCESS: activa. FAILED: falló (ver lastErrorDescription). UNPUBLISHED: dada de baja."},"PublicationStatusDto":{"type":"object","properties":{"portalCode":{"allOf":[{"$ref":"#/components/schemas/PortalCode"}]},"portalName":{"type":"string","example":"Yapo"},"status":{"description":"QUEUED/RUNNING/RETRYING: en curso. SUCCESS: activa. FAILED: falló (ver lastErrorDescription). UNPUBLISHED: dada de baja.","allOf":[{"$ref":"#/components/schemas/PublicationStatus"}]},"externalUrl":{"type":"string","nullable":true,"example":"https://www.yapo.cl/..."},"lastError":{"type":"string","nullable":true,"description":"Mensaje original del portal."},"lastErrorDescription":{"type":"string","nullable":true,"description":"El mismo error explicado en español."},"updatedAt":{"type":"string","example":"2026-10-05T14:03:00.000Z"}},"required":["portalCode","portalName","status","updatedAt"]},"PublishPortalsDto":{"type":"object","properties":{"portals":{"type":"array","example":["YAPO","TOCTOC"],"description":"Portales destino. Usa GET /v1/portals para ver los habilitados para tu corredora.","items":{"$ref":"#/components/schemas/PortalCode"}}},"required":["portals"]},"PublicationRequestResultDto":{"type":"object","properties":{"portalCode":{"allOf":[{"$ref":"#/components/schemas/PortalCode"}]},"accepted":{"type":"boolean","example":true,"description":"true si el portal quedó encolado (producción) o simulado con éxito (sandbox)."},"status":{"example":"QUEUED","allOf":[{"$ref":"#/components/schemas/PublicationStatus"}]},"error":{"$ref":"#/components/schemas/PublicationIssueDto"}},"required":["portalCode","accepted"]},"PublicUsagePlanDto":{"type":"object","properties":{"name":{"type":"string","example":"Growth"},"active":{"type":"boolean","example":true,"description":"false si el plan está suspendido: no se pueden crear ni publicar propiedades."}},"required":["name","active"]},"PublicUsagePropertiesDto":{"type":"object","properties":{"active":{"type":"number","example":187,"description":"Propiedades que cuentan para el cupo (todas menos las archivadas)."},"limit":{"type":"number","nullable":true,"example":200,"description":"Máximo de propiedades del plan. null = sin límite."},"remaining":{"type":"number","nullable":true,"example":13,"description":"Propiedades que aún puedes crear. null = sin límite."}},"required":["active"]},"PublicUsageDto":{"type":"object","properties":{"plan":{"$ref":"#/components/schemas/PublicUsagePlanDto"},"properties":{"$ref":"#/components/schemas/PublicUsagePropertiesDto"},"portalsNote":{"type":"string","example":"Los avisos activos y el cupo de cada portal están en GET /v1/portals."}},"required":["plan","properties","portalsNote"]},"PublicLeadDto":{"type":"object","properties":{"id":{"type":"string","example":"cm1lead0000000000000000","description":"Identificador del lead."},"propertyId":{"type":"string","example":"cm1prop0000000000000000","description":"Propiedad consultada."},"channel":{"type":"string","enum":["MANUAL","INTERNAL_FORM","WHATSAPP","PORTAL_CONTACT"],"example":"PORTAL_CONTACT"},"portalCode":{"type":"string","nullable":true,"example":"YAPO","description":"Código del portal, si corresponde."},"contactName":{"type":"string","nullable":true,"example":"Camila Rojas"},"contactPhone":{"type":"string","nullable":true,"example":"+56912345678"},"contactEmail":{"type":"string","nullable":true,"example":"camila@example.com"},"message":{"type":"string","nullable":true,"example":"¿Sigue disponible?"},"respondedAt":{"type":"string","nullable":true,"example":null,"description":"Fecha de respuesta registrada."},"createdAt":{"type":"string","example":"2026-10-05T14:03:00.000Z"}},"required":["id","propertyId","channel","portalCode","contactName","contactPhone","contactEmail","message","respondedAt","createdAt"]},"PublicLeadListDto":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/PublicLeadDto"}},"total":{"type":"number","example":1},"page":{"type":"number","example":1},"limit":{"type":"number","example":20}},"required":["items","total","page","limit"]},"Webhook_LEAD_CREATED":{"type":"object","description":"Llegó un lead nuevo (desde un portal, el sitio o cargado a mano) asociado a una propiedad.","example":{"id":"delivery-ejemplo","event":"LEAD_CREATED","livemode":false,"createdAt":"2026-10-05T14:03:00.000Z","data":{"leadId":"cm1lead0000000000000000","propertyId":"cm1prop0000000000000000","channel":"PORTAL_CONTACT","contactName":"Camila Rojas","contactPhone":"+56912345678","contactEmail":"camila@example.com","message":"Hola, ¿sigue disponible el departamento?","createdAt":"2026-10-05T14:03:00.000Z"}},"required":["id","event","livemode","createdAt","data"],"properties":{"id":{"type":"string","description":"Id estable para deduplicar."},"event":{"type":"string","enum":["LEAD_CREATED"]},"livemode":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"leadId":{"type":"string","example":"cm1lead0000000000000000","nullable":false},"propertyId":{"type":"string","example":"cm1prop0000000000000000","nullable":false},"channel":{"type":"string","example":"PORTAL_CONTACT","nullable":false},"contactName":{"type":"string","example":"Camila Rojas","nullable":true},"contactPhone":{"type":"string","example":"+56912345678","nullable":true},"contactEmail":{"type":"string","example":"camila@example.com","nullable":true},"message":{"type":"string","example":"Hola, ¿sigue disponible el departamento?","nullable":true},"createdAt":{"type":"string","example":"2026-10-05T14:03:00.000Z","nullable":false}},"required":["leadId","propertyId","channel","createdAt"]}}},"Webhook_PROPERTY_CREATED":{"type":"object","description":"Se creó una propiedad (en el panel, por WhatsApp o por la API).","example":{"id":"delivery-ejemplo","event":"PROPERTY_CREATED","livemode":false,"createdAt":"2026-10-05T14:03:00.000Z","data":{"propertyId":"cm1prop0000000000000000","externalId":"crm-prop-12345","title":"Departamento 2D2B en Providencia","operationType":"SALE","status":"DRAFT","createdAt":"2026-10-05T14:03:00.000Z"}},"required":["id","event","livemode","createdAt","data"],"properties":{"id":{"type":"string","description":"Id estable para deduplicar."},"event":{"type":"string","enum":["PROPERTY_CREATED"]},"livemode":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"propertyId":{"type":"string","example":"cm1prop0000000000000000","nullable":false},"externalId":{"type":"string","example":"crm-prop-12345","nullable":false},"title":{"type":"string","example":"Departamento 2D2B en Providencia","nullable":false},"operationType":{"type":"string","example":"SALE","nullable":false},"status":{"type":"string","example":"DRAFT","nullable":false},"createdAt":{"type":"string","example":"2026-10-05T14:03:00.000Z","nullable":false}},"required":["propertyId","externalId","title","operationType","status","createdAt"]}}},"Webhook_PROPERTY_PUBLICATION_COMPLETED":{"type":"object","description":"Terminó una publicación, actualización o baja en un portal (con éxito o con error definitivo; nunca en un reintento).","example":{"id":"delivery-ejemplo","event":"PROPERTY_PUBLICATION_COMPLETED","livemode":false,"createdAt":"2026-10-05T14:03:00.000Z","data":{"propertyId":"cm1prop0000000000000000","externalId":"crm-prop-12345","portalCode":"YAPO","action":"PUBLISH","succeeded":false,"errorMessage":"Yapo requires the built area (square, m²) on the property.","errorDescription":"Falta la superficie construida (m²)."}},"required":["id","event","livemode","createdAt","data"],"properties":{"id":{"type":"string","description":"Id estable para deduplicar."},"event":{"type":"string","enum":["PROPERTY_PUBLICATION_COMPLETED"]},"livemode":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"propertyId":{"type":"string","example":"cm1prop0000000000000000","nullable":false},"externalId":{"type":"string","example":"crm-prop-12345","nullable":false},"portalCode":{"type":"string","example":"YAPO","nullable":false},"action":{"type":"string","example":"PUBLISH","nullable":false},"succeeded":{"type":"boolean","example":false,"nullable":false},"errorMessage":{"type":"string","example":"Yapo requires the built area (square, m²) on the property.","nullable":true},"errorDescription":{"type":"string","example":"Falta la superficie construida (m²).","nullable":true}},"required":["propertyId","externalId","portalCode","action","succeeded"]}}},"Webhook_PROPERTY_UPDATED":{"type":"object","description":"Se editó una propiedad o su galería (en el panel o por la API). Trae el estado actual; consulta GET /v1/properties/{id} para el detalle.","example":{"id":"delivery-ejemplo","event":"PROPERTY_UPDATED","livemode":false,"createdAt":"2026-10-05T14:03:00.000Z","data":{"propertyId":"cm1prop0000000000000000","externalId":"crm-prop-12345","status":"PUBLISHED","updatedAt":"2026-10-05T14:03:00.000Z"}},"required":["id","event","livemode","createdAt","data"],"properties":{"id":{"type":"string","description":"Id estable para deduplicar."},"event":{"type":"string","enum":["PROPERTY_UPDATED"]},"livemode":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"propertyId":{"type":"string","example":"cm1prop0000000000000000","nullable":false},"externalId":{"type":"string","example":"crm-prop-12345","nullable":false},"status":{"type":"string","example":"PUBLISHED","nullable":false},"updatedAt":{"type":"string","example":"2026-10-05T14:03:00.000Z","nullable":false}},"required":["propertyId","externalId","status","updatedAt"]}}},"Webhook_PROPERTY_STATUS_CHANGED":{"type":"object","description":"Una propiedad se pausó, se reanudó o se archivó (en el panel o por la API).","example":{"id":"delivery-ejemplo","event":"PROPERTY_STATUS_CHANGED","livemode":false,"createdAt":"2026-10-05T14:03:00.000Z","data":{"propertyId":"cm1prop0000000000000000","externalId":"crm-prop-12345","previousStatus":"PUBLISHED","status":"PAUSED","changedAt":"2026-10-05T14:03:00.000Z"}},"required":["id","event","livemode","createdAt","data"],"properties":{"id":{"type":"string","description":"Id estable para deduplicar."},"event":{"type":"string","enum":["PROPERTY_STATUS_CHANGED"]},"livemode":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"propertyId":{"type":"string","example":"cm1prop0000000000000000","nullable":false},"externalId":{"type":"string","example":"crm-prop-12345","nullable":false},"previousStatus":{"type":"string","example":"PUBLISHED","nullable":false},"status":{"type":"string","example":"PAUSED","nullable":false},"changedAt":{"type":"string","example":"2026-10-05T14:03:00.000Z","nullable":false}},"required":["propertyId","externalId","previousStatus","status","changedAt"]}}},"Webhook_INBOX_MESSAGE_RECEIVED":{"type":"object","description":"Entró un mensaje nuevo a la bandeja de entrada.","example":{"id":"delivery-ejemplo","event":"INBOX_MESSAGE_RECEIVED","livemode":false,"createdAt":"2026-10-05T14:03:00.000Z","data":{"conversationId":"cm1conv0000000000000000","messageId":"cm1msg00000000000000000","channel":"WHATSAPP","contactName":"Camila Rojas","contactPhone":"+56912345678","body":"¿Puedo visitar el depto el sábado?"}},"required":["id","event","livemode","createdAt","data"],"properties":{"id":{"type":"string","description":"Id estable para deduplicar."},"event":{"type":"string","enum":["INBOX_MESSAGE_RECEIVED"]},"livemode":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"conversationId":{"type":"string","example":"cm1conv0000000000000000","nullable":true},"messageId":{"type":"string","example":"cm1msg00000000000000000","nullable":false},"channel":{"type":"string","example":"WHATSAPP","nullable":false},"contactName":{"type":"string","example":"Camila Rojas","nullable":true},"contactPhone":{"type":"string","example":"+56912345678","nullable":true},"body":{"type":"string","example":"¿Puedo visitar el depto el sábado?","nullable":true}},"required":["messageId","channel"]}}},"Webhook_TICKET_CREATED":{"type":"object","description":"Se creó un ticket de seguimiento (manual o porque el asistente derivó la conversación).","example":{"id":"delivery-ejemplo","event":"TICKET_CREATED","livemode":false,"createdAt":"2026-10-05T14:03:00.000Z","data":{"ticketId":"cm1tick0000000000000000","title":"Cliente pide visita el sábado","priority":"MEDIUM","source":"BOT_FALLBACK","conversationId":"cm1conv0000000000000000"}},"required":["id","event","livemode","createdAt","data"],"properties":{"id":{"type":"string","description":"Id estable para deduplicar."},"event":{"type":"string","enum":["TICKET_CREATED"]},"livemode":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"ticketId":{"type":"string","example":"cm1tick0000000000000000","nullable":false},"title":{"type":"string","example":"Cliente pide visita el sábado","nullable":false},"priority":{"type":"string","example":"MEDIUM","nullable":false},"source":{"type":"string","example":"BOT_FALLBACK","nullable":false},"conversationId":{"type":"string","example":"cm1conv0000000000000000","nullable":true}},"required":["ticketId","title","priority","source"]}}}}},"x-webhooks":{"LEAD_CREATED":{"post":{"summary":"Llegó un lead nuevo (desde un portal, el sitio o cargado a mano) asociado a una propiedad.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook_LEAD_CREATED"}}}},"responses":{"200":{"description":"Evento recibido y persistido por tu receptor."}}}},"PROPERTY_CREATED":{"post":{"summary":"Se creó una propiedad (en el panel, por WhatsApp o por la API).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook_PROPERTY_CREATED"}}}},"responses":{"200":{"description":"Evento recibido y persistido por tu receptor."}}}},"PROPERTY_PUBLICATION_COMPLETED":{"post":{"summary":"Terminó una publicación, actualización o baja en un portal (con éxito o con error definitivo; nunca en un reintento).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook_PROPERTY_PUBLICATION_COMPLETED"}}}},"responses":{"200":{"description":"Evento recibido y persistido por tu receptor."}}}},"PROPERTY_UPDATED":{"post":{"summary":"Se editó una propiedad o su galería (en el panel o por la API). Trae el estado actual; consulta GET /v1/properties/{id} para el detalle.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook_PROPERTY_UPDATED"}}}},"responses":{"200":{"description":"Evento recibido y persistido por tu receptor."}}}},"PROPERTY_STATUS_CHANGED":{"post":{"summary":"Una propiedad se pausó, se reanudó o se archivó (en el panel o por la API).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook_PROPERTY_STATUS_CHANGED"}}}},"responses":{"200":{"description":"Evento recibido y persistido por tu receptor."}}}},"INBOX_MESSAGE_RECEIVED":{"post":{"summary":"Entró un mensaje nuevo a la bandeja de entrada.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook_INBOX_MESSAGE_RECEIVED"}}}},"responses":{"200":{"description":"Evento recibido y persistido por tu receptor."}}}},"TICKET_CREATED":{"post":{"summary":"Se creó un ticket de seguimiento (manual o porque el asistente derivó la conversación).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook_TICKET_CREATED"}}}},"responses":{"200":{"description":"Evento recibido y persistido por tu receptor."}}}}},"x-mcp":{"url":"https://docs.tochihub.cl/v1/mcp","transport":"streamable-http","tools":[{"name":"search_properties","scope":"properties:read","description":"Buscar propiedades paginadas, incluido externalId del CRM."},{"name":"get_property","scope":"properties:read","description":"Leer una propiedad con sus fotos."},{"name":"get_api_reference","scope":"properties:read","description":"Leer docs.md u openapi.json, el contrato completo de integración."},{"name":"validate_property_payload","scope":"properties:read","description":"Validar un payload o propiedad existente con los mappers reales, sin publicar."},{"name":"create_property","scope":"properties:write","description":"Crear una propiedad, en sandbox con th_test_ o en producción con th_live_. Admite Idempotency-Key."},{"name":"get_publication_status","scope":"properties:read","description":"Consultar estado, URL y errores por portal."},{"name":"list_webhook_events","scope":"properties:read","description":"Leer catálogo y ejemplos de eventos."},{"name":"send_test_webhook","scope":"properties:write","description":"Enviar un evento de prueba a un webhook existente de la corredora."},{"name":"get_integration_status","scope":"properties:read","description":"Ver últimas 50 solicitudes de esta key (7 días), endpoints y últimas 50 entregas de su corredora."}]}}