{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://flbrokers.mukutu.cloud/schema.json","title":"FL Brokers listing","description":"One commercial real-estate listing from FL Brokers, collected from the Kenlo (ex-inGaia) public API and normalized. Measured against the 9.980 rows collected on 2026-08-14; every range and caveat below came from that data, not from a spec. THIS SCHEMA DESCRIBES THE RECORD, not the HTTP envelope — pagination, facets and errors are in /api/openapi.json, generated from the routes themselves.","x-coverage":{"collected":9980,"declared_by_source":11243,"missing":1263,"missing_pct":11.2,"why":"The Kenlo index is prd_sites_listings_v1 (Elasticsearch). Its default max_result_window is 10.000, so deep pagination stops there — page 209 answers HTTP 200 with an empty list and NO count field, a false ending. Getting the rest needs the query partitioned, not more pages.","collected_at_window":["2026-08-14T12:31:14+00:00","2026-08-14T12:38:38+00:00"],"raw_pages":209},"x-inventory":{"note":"This is a COMMERCIAL portfolio, not residential. Read the mix before sizing a use case.","OFFICE_FLOOR":7832,"HOUSE":638,"OUTHOUSE":522,"APARTMENT":339,"BUSINESS":302,"distinct_property_types":19,"distinct_cities":83,"distinct_states":14},"type":"object","required":["ref","source","site_id","collected_at"],"properties":{"ref":{"type":"string","description":"The listing reference from Kenlo, e.g. CJ23573-FLE. This is the public identifier and the primary key — there is no autoincrement id, because a second identifier would mean two identities for the same property.","examples":["CJ23573-FLE"]},"source":{"type":"string","description":"Where the record came from. OPEN string, never an enum: today 100% of rows are kenlo_rest, and a value we do not recognize must be stored raw rather than dropped.","examples":["kenlo_rest"]},"site_id":{"type":"integer","description":"The Kenlo site id the listing belongs to. FL Brokers is 1710.","examples":[1710]},"property_type":{"type":["string","null"],"description":"Kenlo's own property_type, untranslated. 19 distinct values observed; OFFICE_FLOOR is 78,5% of the portfolio.","examples":["OFFICE_FLOOR","HOUSE","APARTMENT"]},"purposes":{"type":["string","null"],"description":"A JSON array, as a string. Only three shapes exist in the data: [\"FOR_RENT\"] (4.814), [\"FOR_SALE\", \"FOR_RENT\"] (3.607) and [\"FOR_SALE\"] (1.559). A listing is commonly both.","examples":["[\"FOR_SALE\", \"FOR_RENT\"]"]},"sale_cents_min":{"type":["integer","null"],"description":"Sale price in CENTS, integer. Never a float — the source sends 1700000.01 and float money is the bug that only shows up in the report. Null in 5.222 rows (rent-only listings). CAVEAT: 15 rows carry exactly 1 cent. That is a sentinel meaning 'price on request', NOT a price. Anyone sorting by cheapest without handling it puts those 15 on top."},"sale_cents_max":{"type":["integer","null"],"description":"Upper bound of the sale range, in cents. CAVEAT: the maximum observed is 120000000000 — R$ 1,2 bilhão, on an OFFICE_FLOOR in São Paulo. It is in the source; we do not correct it."},"rent_cents_min":{"type":["integer","null"],"description":"Monthly rent in cents. Null in 1.820 rows (sale-only listings)."},"rent_cents_max":{"type":["integer","null"],"description":"Upper bound of the rent range, in cents."},"condo_fee_cents":{"type":["integer","null"],"description":"Condo fee in cents, monthly."},"property_tax_cents":{"type":["integer","null"],"description":"Property tax (IPTU) in cents. Kenlo's payment period is MONTHLY — treating it as annual is off by 12."},"total_rent_cents":{"type":["integer","null"],"description":"Rent plus condo fee plus tax, in cents, as the source computes it."},"area_m2_min":{"type":["number","null"],"description":"Area in square metres. Comes as a [min, max] pair because a building with several units has a range; keeping only the min would lose that silently. CAVEAT: observed range is 2,5 m² to 5.022.800 m². Five million m² is 502 hectares — either rural land or a typo at the source. And the raw payload's property_metreage sometimes says SQFT on a listing whose own title advertises m²: that field lies, and it is only visible through /api/listings/{ref}/raw."},"area_m2_max":{"type":["number","null"],"description":"Upper bound of the area range. Equal to the min on a single-unit listing."},"bedrooms":{"type":["integer","null"],"description":"Bedrooms. Usually null on a commercial floor."},"suites":{"type":["integer","null"],"description":"En-suite bedrooms."},"bathrooms":{"type":["integer","null"],"description":"Bathrooms. Values in the hundreds are plausible here — a whole corporate building is one listing."},"parking_spaces":{"type":["integer","null"],"description":"Parking spaces. Same note as bathrooms: a whole building can carry over a thousand."},"city":{"type":["string","null"],"description":"City. 83 distinct; São Paulo dominates. No row has a null city.","examples":["São Paulo","Barueri"]},"state":{"type":["string","null"],"description":"State, two letters. 14 distinct; SP is ~89%.","examples":["SP"]},"neighborhood":{"type":["string","null"],"description":"Neighborhood as the source writes it — not normalized against any official list."},"full_address":{"type":["string","null"],"description":"Address as the source writes it."},"url":{"type":["string","null"],"description":"The listing page on the FL Brokers site."},"photo_count":{"type":["integer","null"],"description":"How many photos exist. The URLs themselves are in the raw payload, not here — serving them would mean hosting a third party's files."},"cover_photo":{"type":["string","null"],"description":"Cover image URL on img.kenlo.io. Returned as it came."},"video_url":{"type":["string","null"],"description":"Video URL when the listing has one."},"updated_at":{"type":["string","null"],"description":"THEIR updated_at — when Kenlo says the listing changed."},"collected_at":{"type":"string","format":"date-time","description":"When WE saw it. Present on every response, always. Real-estate data ages, and an answer without a collection date looks current and lies. /api/health reports the maximum of this field, which is what freshness means here."}}}