# Anuncios y sincronización

Sincroniza anuncios y edita sus campos de contenido compatibles.

## Operaciones REST y permisos de las claves

| Tarea | Permisos de la clave | Empieza aquí |
| --- | --- | --- |
| Consultar anuncios publicados y no publicados; sincronizar anuncios | `read:properties`; `write:properties` para la modificación correspondiente | `GET /api/v1/landlord/listings`, `GET /api/v1/landlord/listings/changes`, `PATCH /api/v1/landlord/listings/{unitId}/content`, `POST /api/v1/landlord/listings/{unitId}/media/uploads`, `POST /api/v1/landlord/listings/{unitId}/media/uploads/{uploadId}/complete`, `PATCH /api/v1/landlord/listings/{unitId}/media`, `PATCH /api/v1/landlord/listings/{unitId}/publication` |

## Inicia la sincronización y reproduce los cambios de anuncios

Para una sincronización completa de anuncios, conserva sin cambios el `syncCursor` de la **primera página de sincronización inicial** hasta aplicar todas sus páginas a un conjunto de datos temporal. Sigue el `nextCursor` inicial por todas las páginas; solo entonces inicia `/api/v1/landlord/listings/changes` desde ese primer cursor conservado. Aplica cada página de cambios de forma atómica con su `nextCursor`; continúa mientras `hasMore=true`. Sustituye la caché anterior solo cuando terminen correctamente la sincronización inicial completa y la primera reproducción de cambios. Los webhooks activan ese lector de cambios; las consultas periódicas recuperan las notificaciones perdidas.

## Edita el nombre o el texto de una unidad en un anuncio existente

Usa un ID de unidad devuelto por el feed de anuncios de la empresa. Con `write:properties`, envía `PATCH /api/v1/landlord/listings/{unitId}/content` con un `Idempotency-Key` y este cuerpo JSON:

```json
{"name":"Bright two-room apartment","otherFacts":"Two rooms and a kitchen with a balcony."}
```

La respuesta es la misma proyección `{"listing": ...}` que la consulta del detalle del anuncio. `name` y `otherFacts` son los únicos campos aceptados; ambos son cadenas opcionales que se recortan, y debe proporcionarse al menos uno. Sus límites respectivos son 200 y 10000 caracteres, con un máximo de 64 KiB para el cuerpo de la solicitud. Los campos omitidos no cambian. Un `name` vacío elimina el nombre opcional de la unidad. Un `otherFacts` vacío borra el texto de la unidad, de modo que la `description` pública recurre al campo heredado `facts` de la unidad y después a la descripción del inmueble. No borra esas fuentes alternativas. Se rechazan `null` y los campos desconocidos.

Consulta el resultado y aplica los eventos de cambios de anuncios del modo habitual. Las repeticiones siguen requiriendo el permiso y la titularidad actuales de la clave; una denegación posterior no revierte una operación correcta anterior. Si claves de operación distintas modifican el mismo campo, prevalece la última escritura; `listingVersion` no es aquí una condición previa de escritura.

Esta operación de contenido no permite acceder a medios, publicación, disponibilidad ni campos privados de inquilinos. Siguen aplicándose sus límites de administración independientes. La escritura de contenido, la auditoría semántica obligatoria y el resultado de repetición se confirman atómicamente. La auditoría registra los ID de clave y operación y los nombres de los campos modificados, sin guardar tu credencial ni el texto del anuncio en ese registro.

## Sube imágenes y publica anuncios mediante la API

Activa una delegación explícita para la clave exacta de integración en **Configuración → API y agentes**. El administrador vuelve a iniciar sesión con contraseña, passkey o un método de eID habilitado en Homito y concede `media` y/o `publication` con vencimiento. La activación usa la pertenencia real a la empresa y los requisitos actuales de publicación de esa misma persona. `createdBy`, un permiso comodín, una clave de reemplazo o un ID de persona enviado por el cliente no sustituyen la delegación. Se consulta o revoca mediante el control de sesión de la aplicación web `/api/v1/settings/api-keys/{keyId}/listing-grant`, no mediante el origen externo de la API.

Cada operación requiere `write:properties`, la capacidad delegada correspondiente y un `Idempotency-Key` distinto. Tras perder una respuesta, conserva el cuerpo y la clave idénticos; la repetición comprueba la autorización actual antes de devolver el recibo.

1. Envía `POST /api/v1/landlord/listings/{unitId}/media/uploads` con `{"images":[{"bytes":12345,"sha256":"<64 lowercase hexadecimal characters>","mimeType":"image/png"}]}`. Calcula tamaño y SHA-256 a partir de los bytes originales reales. Límite: diez imágenes por reserva y cinco MiB por imagen. La reserva vence a los quince minutos; la URL PUT dura como máximo cinco minutos.
2. Envía esos bytes exactos mediante PUT a `upload.url`, con **todos** los valores devueltos en `upload.headers` y sin la cabecera Authorization de Homito. Usa carga HTTP binaria, rechaza redirecciones y comprueba el resultado HTTP antes de completar. El objeto privado temporal todavía no es una imagen del anuncio. Repetir la reserva no prolonga sus URL; después del vencimiento crea otra reserva con una clave de operación nueva.
3. Envía `POST /api/v1/landlord/listings/{unitId}/media/uploads/{uploadId}/complete` con `{}` o `{"setAsFront":true}`. El servidor comprueba longitud, SHA-256, MIME, descodificación y límites de píxeles; escribe otra imagen pública inmutable y confirma atómicamente galería, auditoría, diario, intención duradera de webhook y recibo. Consulta el anuncio resultante. GIF y WebP animado pueden conservar metadatos incrustados; no se promete eliminarlos todos.
4. Envía `PATCH /api/v1/landlord/listings/{unitId}/publication` con `{"isPublic":true,"allocationMethod":"individual_assessment","creditCheckMode":"without_credit_check"}` para publicar, o `{"isPublic":false}` para retirar. El método también puede ser `first_come`. Se mantienen mantenimiento, bloqueo de empresa, reglas de convocatoria y requisitos actuales de publicación de la persona delegante. Retirar conserva su exención existente de confianza de publicación, pero exige clave, delegación, persona, pertenencia y titularidad vigentes. No se aceptan slugs arbitrarios, consultas de crédito ni campos privados de inquilinos.

Procesa `listing.changed`/`listing.unpublished` mediante el feed ordenado de cambios. Las cargas temporales abandonadas y los objetos derivados no adjuntos tienen limpieza programada duradera. Un recibo confirma la modificación y la intención de entrega; comprueba aparte la entrega real del webhook.

Cuando una distribución MCP exacta y aprobada los anuncie, `homito.reserve_listing_media`, `homito.complete_listing_media` y `homito.set_listing_publication` llaman a las mismas operaciones REST con `reservation`, `completion` y `publication`. También exigen `unitId` e `idempotencyKey`; completar exige `uploadId`. Activa el control local habitual de escritura; apruebas cada llamada en tu cliente MCP antes de que se envíe. El PUT binario sigue siendo una carga HTTP separada con las instrucciones devueltas.

Gestiona imágenes existentes con `PATCH /api/v1/landlord/listings/{unitId}/media`: `{"removeUrls":["<exact URL from the current gallery>"],"frontImageUrl":"<exact retained gallery URL>"}`. Puedes enviar cada campo por separado; `frontImageUrl:null` borra la selección explícita de portada. La operación solo elimina o selecciona imágenes existentes, nunca importa una URL nueva. Las imágenes gestionadas retiradas pueden pasar a limpieza física protegida por la base de datos. La herramienta MCP aprobada correspondiente es `homito.update_listing_gallery`, con un objeto `gallery` y los controles habituales de escritura.

## Continúa las consultas de forma segura

Sigue `nextCursor` hasta que sea `null`, manteniendo la misma operación de listado y los mismos filtros. Utiliza los cursores solo con la misma empresa y operación de listado. Las previsualizaciones de importación, los trabajos y su historial pertenecen a la clave API que los creó, incluido el acceso mediante ID de trabajo. Una respuesta correcta del `/health` público, por sí sola, no verifica tu clave ni el acceso a la empresa.

## Mantén los datos privados fuera de las cachés públicas

Mantén los datos personales, los recibos y las capacidades de carga fuera de las cachés públicas de anuncios. Las consultas de inquilinos y solicitudes devuelven deliberadamente proyecciones operativas mínimas; no deduzcas campos privados ausentes ni conclusiones de evaluación. Distingue los valores null o desconocidos de cero o de un resultado completado.

## Usa la versión publicada del contrato

Usa la versión de API y el ciclo de vida indicados en la referencia, los esquemas de cada operación y cualquier versión de formulario o recurso requerida al actualizar una integración. Conserva las versiones opacas sin cambios y fija una versión MCP aprobada. Los nombres de evento proceden del mismo catálogo que la API; el orden de llegada y una versión de producto no sustituyen la consulta actual del recurso.
