Mantener acompasada una copia
La mayoría de las integraciones acaban teniendo una copia de alguna parte del catálogo. Hacerlo mal es el error más caro que ofrece esta API, y tiene tres formas reconocibles: releerlo todo con un temporizador, paginar con un desplazamiento y tratar una ficha ausente como una ficha borrada.
La forma que funciona
- Rellena una vez. Recorre el filtro que te interesa desde el primer cursor hasta el último, guardando fichas por el camino.
- Anota la marca de nivel alto. Guarda el
updated_atmás nuevo que hayas visto, no la hora a la que se ejecutó tu trabajo. Son cosas distintas, y en esa diferencia es donde se pierden las fichas. - Consulta los cambios. Pide
updated_sinceunos minutos antes de esa marca. - O deja de consultar. Los webhooks eliminan este bucle por completo, y no cuestan cuota.
import { Skautik } from "@skautik/sdk";
const skautik = new Skautik({ apiKey: process.env.SKAUTIK_API_KEY! });
async function backfill(city: string) {
let newest = "";
for await (const property of skautik.properties.listAll({ city })) {
await upsert(property);
if (property.updatedAt > newest) {
newest = property.updatedAt;
}
}
return newest;
}El iterador sigue el cursor por ti y para en has_more, que es la
única condición correcta. Escribir el bucle a mano es donde la gente para en una página
corta, y una página llena puede seguir siendo la última.
Solapa la ventana
Pide unos minutos antes de tu marca de nivel alto, no la marca en sí:
GET /v1/api/properties?city=Berlin&updated_since=2026-08-11T03:55:00ZLas fichas se escriben de forma concurrente. Un límite estricto se salta cualquier cosa confirmada un instante después de tu corte pero sellada un instante antes, y esa ficha queda perdida hasta que casualmente vuelva a cambiar. Tratar dos veces la misma ficha no cuesta nada si tu escritura es un upsert; saltarse una te cuesta una respuesta equivocada durante un tiempo indefinido.
La ausencia no es un borrado
Una ficha que deja de aparecer en una lista filtrada no se ha ido necesariamente. Puede
haber cambiado de una forma que la saca de tu filtro: una subida de precio por encima de
tu max_price, un cambio de barrio, una retirada.
La retirada es explícita. Un inmueble retirado conserva su identificador y sigue siendo
legible por id; el estado de su anuncio dice archived o sold. Sale de la
lista por defecto porque el defecto son los anuncios activos, no porque haya dejado de
existir.
Así que: nunca deduzcas un borrado de una ausencia. O te suscribes a property.withdrawn,
o pides el estado explícitamente cuando necesites saberlo:
GET /v1/api/properties?city=Berlin&status=archivedSi tu copia borra todo lo que se cae de una página filtrada, un solo cambio de precio borrará un inmueble que sigue en el mercado.
Qué guardar
Guarda como mínimo el identificador y el updated_at. El identificador es opaco
y estable; la marca de tiempo es lo que abarata la siguiente sincronización.
Guarda también el external_id si además eres la fuente de la ficha. Es tu propio
identificador devuelto, y es lo que te permite reconciliar sin mantener una
tabla que mapee nuestros ids a los tuyos.
Coste
| Enfoque | Peticiones al día, 20.000 inmuebles |
|---|---|
| Releer cada hora, 200 por página | 2.400 |
updated_since cada hora | de 24 a 50, según la rotación |
| Webhooks | 0 |
La primera fila es el motivo por el que existen las cuotas. La tercera es el motivo por el que existen los webhooks.
Cuándo un rellenado es la herramienta equivocada
Las lecturas sostenidas y de gran volumen de todo el catálogo se sirven mejor con una exportación que con un rastreo más rápido. Una exportación es una única petición, produce un único archivo y no compite con tu propio tráfico de producción por el límite de ráfaga. Pregúntanos antes de construir algo que pagine todo el mercado cada noche.