{"generated_at":"2026-10-26T10:18:52.563Z","title":"Dataset due diligence","overview":"Due-diligence pack for the Spanish coastal new-build listing book and the observation ledger published with it. Listing counts are computed from the book on this deployment. The price-history range is read from price_snapshots when a database client is configured. The published open-data file is reported separately and is not used to fill a failed database read. A figure that cannot be computed is not available.","coverage":{"feed":{"source":"public/data.json","listings":2051,"feed_generated_at":"2026-10-26T06:52:07.350Z","countries":[{"name":"(country not set on the listing row)","listings":2051}],"country_note":"Rows with no country field are counted as unset. GET /api/v1/properties defaults a missing country to ES. This pack does not apply that default to the count.","towns":[{"location":"Estepona, Málaga","town":"Estepona","province":"Málaga","costa":"Costa del Sol","listings":230},{"location":"Mijas, Málaga","town":"Mijas","province":"Málaga","costa":"Costa del Sol","listings":187},{"location":"Torrevieja, Alicante","town":"Torrevieja","province":"Alicante","costa":"Costa Blanca South","listings":118},{"location":"Fuengirola, Málaga","town":"Fuengirola","province":"Málaga","costa":"Costa del Sol","listings":100},{"location":"Pilar de La Horadada, Alicante","town":"Pilar de La Horadada","province":"Alicante","costa":"Costa Blanca South","listings":90},{"location":"Marbella, Málaga","town":"Marbella","province":"Málaga","costa":"Costa del Sol","listings":84},{"location":"Los Alcazares, Murcia","town":"Los Alcazares","province":"Murcia","costa":"Costa Calida","listings":77},{"location":"Finestrat, Alicante","town":"Finestrat","province":"Alicante","costa":"Costa Blanca North","listings":59},{"location":"Guardamar del Segura, Alicante","town":"Guardamar del Segura","province":"Alicante","costa":"Costa Blanca South","listings":54},{"location":"Casares, Málaga","town":"Casares","province":"Málaga","costa":"Costa del Sol","listings":52},{"location":"San Pedro del Pinatar, Murcia","town":"San Pedro del Pinatar","province":"Murcia","costa":"Costa Calida","listings":52},{"location":"Torre Pacheco, Murcia","town":"Torre Pacheco","province":"Murcia","costa":"Costa Calida","listings":48},{"location":"Benijofar, Alicante","town":"Benijofar","province":"Alicante","costa":"Costa Blanca South","listings":41},{"location":"Manilva, Málaga","town":"Manilva","province":"Málaga","costa":"Costa del Sol","listings":40},{"location":"Benahavís, Málaga","town":"Benahavís","province":"Málaga","costa":"Costa del Sol","listings":36},{"location":"San Miguel de Salinas, Alicante","town":"San Miguel de Salinas","province":"Alicante","costa":"Costa Blanca South","listings":32},{"location":"Pinoso, Alicante","town":"Pinoso","province":"Alicante","costa":"Costa Blanca South - Inland","listings":31},{"location":"Villajoyosa, Alicante","town":"Villajoyosa","province":"Alicante","costa":"Costa Blanca North","listings":31},{"location":"Algorfa, Alicante","town":"Algorfa","province":"Alicante","costa":"Costa Blanca South","listings":30},{"location":"Polop, Alicante","town":"Polop","province":"Alicante","costa":"Costa Blanca North","listings":27},{"location":"Torremolinos, Málaga","town":"Torremolinos","province":"Málaga","costa":"Costa del Sol","listings":27},{"location":"Rojales, Alicante","town":"Rojales","province":"Alicante","costa":"Costa Blanca South","listings":25},{"location":"Málaga, Málaga","town":"Málaga","province":"Málaga","costa":"Costa del Sol","listings":24},{"location":"Orihuela Costa, Alicante","town":"Orihuela Costa","province":"Alicante","costa":"Costa Blanca South","listings":22},{"location":"Baños y Mendigo, Murcia","town":"Baños y Mendigo","province":"Murcia","costa":"Costa Calida","listings":21},{"location":"Benalmádena, Málaga","town":"Benalmádena","province":"Málaga","costa":"Costa del Sol","listings":21},{"location":"San Javier, Murcia","town":"San Javier","province":"Murcia","costa":"Costa Calida","listings":19},{"location":"Vélez Málaga, Málaga","town":"Vélez Málaga","province":"Málaga","costa":"Costa del Sol","listings":19},{"location":"San Roque, Cádiz","town":"San Roque","province":"Cádiz","costa":"Costa del Sol (Cadiz)","listings":18},{"location":"Alicante, Alicante","town":"Alicante","province":"Alicante","costa":"Costa Blanca North","listings":16},{"location":"Calpe, Alicante","town":"Calpe","province":"Alicante","costa":"Costa Blanca North","listings":16},{"location":"Orihuela, Alicante","town":"Orihuela","province":"Alicante","costa":"Costa Blanca South","listings":16},{"location":"Fuente Álamo, Murcia","town":"Fuente Álamo","province":"Murcia","costa":"Costa Calida - Inland","listings":14},{"location":"Aguilas, Murcia","town":"Aguilas","province":"Murcia","costa":"Costa Calida","listings":13},{"location":"Jávea Xàbia, Alicante","town":"Jávea Xàbia","province":"Alicante","costa":"Costa Blanca North","listings":13},{"location":"la Nucia, Alicante","town":"la Nucia","province":"Alicante","costa":"Costa Blanca North","listings":13},{"location":"rincon de la victoria, Málaga","town":"rincon de la victoria","province":"Málaga","costa":"Costa del Sol","listings":13},{"location":"Alhama De Murcia, Murcia","town":"Alhama De Murcia","province":"Murcia","costa":"Costa Calida - Inland","listings":12},{"location":"El Verger, Alicante","town":"El Verger","province":"Alicante","costa":"Costa Blanca North","listings":12},{"location":"Hondón de las Nieves, Alicante","town":"Hondón de las Nieves","province":"Alicante","costa":"Costa Blanca South - Inland","listings":12},{"location":"La Linea De La Concepcion, Cádiz","town":"La Linea De La Concepcion","province":"Cádiz","costa":"Costa del Sol (Cadiz)","listings":12},{"location":"Benissa, Alicante","town":"Benissa","province":"Alicante","costa":"Costa Blanca North","listings":11},{"location":"El Campello, Alicante","town":"El Campello","province":"Alicante","costa":"Costa Blanca North","listings":11},{"location":"Cartagena, Murcia","town":"Cartagena","province":"Murcia","costa":"Costa Calida","listings":10},{"location":"Ciudad Quesada, Alicante","town":"Ciudad Quesada","province":"Alicante","costa":"Costa Blanca South","listings":10},{"location":"Denia, Alicante","town":"Denia","province":"Alicante","costa":"Costa Blanca North","listings":10},{"location":"Dolores, Alicante","town":"Dolores","province":"Alicante","costa":"Costa Blanca South","listings":10},{"location":"La Manga Club, Murcia","town":"La Manga Club","province":"Murcia","costa":"Costa Calida","listings":10},{"location":"La Manga del Mar Menor, Murcia","town":"La Manga del Mar Menor","province":"Murcia","costa":"Costa Calida","listings":10},{"location":"San Pedro De Alcantara, Málaga","town":"San Pedro De Alcantara","province":"Málaga","costa":"Costa del Sol","listings":10},{"location":"Santa Pola, Alicante","town":"Santa Pola","province":"Alicante","costa":"Costa Blanca South","listings":10},{"location":"Mazarron, Murcia","town":"Mazarron","province":"Murcia","costa":"Costa Calida - Inland","listings":9},{"location":"Mutxamel, Alicante","town":"Mutxamel","province":"Alicante","costa":"Costa Blanca North","listings":9},{"location":"Aspe, Alicante","town":"Aspe","province":"Alicante","costa":"Costa Blanca South - Inland","listings":8},{"location":"Cox, Alicante","town":"Cox","province":"Alicante","costa":"Costa Blanca South - Inland","listings":7},{"location":"Moraira_Teulada, Alicante","town":"Moraira_Teulada","province":"Alicante","costa":"Costa Blanca North","listings":7},{"location":"Puerto de Mazarron, Murcia","town":"Puerto de Mazarron","province":"Murcia","costa":"Costa Calida","listings":7},{"location":"San Fulgencio, Alicante","town":"San Fulgencio","province":"Alicante","costa":"Costa Blanca South","listings":7},{"location":"Almuñecar, Granada","town":"Almuñecar","province":"Granada","costa":"Costa Tropical","listings":6},{"location":"Bigastro, Alicante","town":"Bigastro","province":"Alicante","costa":"Costa Blanca South","listings":6},{"location":"La Romana, Alicante","town":"La Romana","province":"Alicante","costa":"Costa Blanca South - Inland","listings":6},{"location":"Ojen, Málaga","town":"Ojen","province":"Málaga","costa":"Costa del Sol","listings":6},{"location":"Torrox, Málaga","town":"Torrox","province":"Málaga","costa":"Costa del Sol","listings":6},{"location":"Catral, Alicante","town":"Catral","province":"Alicante","costa":"Costa Blanca South - Inland","listings":5},{"location":"La Marina, Alicante","town":"La Marina","province":"Alicante","costa":"Costa Blanca South","listings":5},{"location":"Monforte del Cid, Alicante","town":"Monforte del Cid","province":"Alicante","costa":"Costa Blanca North - Inland","listings":5},{"location":"Sotogrande, Cádiz","town":"Sotogrande","province":"Cádiz","costa":"Costa del Sol (Cadiz)","listings":5},{"location":"Alfas del Pi, Alicante","town":"Alfas del Pi","province":"Alicante","costa":"Costa Blanca North","listings":4},{"location":"Altea, Alicante","town":"Altea","province":"Alicante","costa":"Costa Blanca North","listings":4},{"location":"Avileses, Murcia","town":"Avileses","province":"Murcia","costa":"Costa Calida - Inland","listings":4},{"location":"Benidorm, Alicante","town":"Benidorm","province":"Alicante","costa":"Costa Blanca North","listings":4},{"location":"Daya Nueva, Alicante","town":"Daya Nueva","province":"Alicante","costa":"Costa Blanca South","listings":4},{"location":"Lorca, Murcia","town":"Lorca","province":"Murcia","costa":"Costa Calida - Inland","listings":4},{"location":"Los Montesinos, Alicante","town":"Los Montesinos","province":"Alicante","costa":"Costa Blanca South","listings":4},{"location":"Penaguila, Alicante","town":"Penaguila","province":"Alicante","costa":"Costa Blanca North - Inland","listings":4},{"location":"Calasparra, Murcia","town":"Calasparra","province":"Murcia","costa":"Costa Calida - Inland","listings":3},{"location":"Istán, Málaga","town":"Istán","province":"Málaga","costa":"Costa del Sol","listings":3},{"location":"Jacarilla, Alicante","town":"Jacarilla","province":"Alicante","costa":"Costa Blanca South - Inland","listings":3},{"location":"Yecla, Murcia","town":"Yecla","province":"Murcia","costa":"Costa Calida - Inland","listings":3},{"location":"Alhaurín De La Torre, Málaga","town":"Alhaurín De La Torre","province":"Málaga","costa":"Costa del Sol","listings":2},{"location":"Benejúzar, Alicante","town":"Benejúzar","province":"Alicante","costa":"Costa Blanca South - Inland","listings":2},{"location":"Cabo de Palos, Murcia","town":"Cabo de Palos","province":"Murcia","costa":"Costa Calida","listings":2},{"location":"Fortuna, Murcia","town":"Fortuna","province":"Murcia","costa":"Costa Calida - Inland","listings":2},{"location":"Gran Alacant, Alicante","town":"Gran Alacant","province":"Alicante","costa":"Costa Blanca South","listings":2},{"location":"La Union, Murcia","town":"La Union","province":"Murcia","costa":"Costa Calida","listings":2},{"location":"Santiago de la Ribera, Murcia","town":"Santiago de la Ribera","province":"Murcia","costa":"Costa Calida","listings":2},{"location":"Almoradi, Alicante","town":"Almoradi","province":"Alicante","costa":"Costa Blanca South - Inland","listings":1},{"location":"Benitachell, Alicante","town":"Benitachell","province":"Alicante","costa":"Costa Blanca North","listings":1},{"location":"Formentera del Segura, Alicante","town":"Formentera del Segura","province":"Alicante","costa":"Costa Blanca South","listings":1},{"location":"Lliber, Alicante","town":"Lliber","province":"Alicante","costa":"Costa Blanca North - Inland","listings":1},{"location":"Los Nietos, Murcia","town":"Los Nietos","province":"Murcia","costa":"Costa Calida","listings":1},{"location":"Los Urrutias, Murcia","town":"Los Urrutias","province":"Murcia","costa":"Costa Calida","listings":1},{"location":"Nerja, Málaga","town":"Nerja","province":"Málaga","costa":"Costa del Sol","listings":1},{"location":"Rafal, Alicante","town":"Rafal","province":"Alicante","costa":"Costa Blanca South - Inland","listings":1},{"location":"San Juan Alicante, Alicante","town":"San Juan Alicante","province":"Alicante","costa":"Costa Blanca North","listings":1},{"location":"Sucina, Murcia","town":"Sucina","province":"Murcia","costa":"Costa Calida - Inland","listings":1}],"town_count":96,"provinces":[{"key":"malaga","name":"Málaga","listings":861,"towns":18},{"key":"alicante","name":"Alicante","listings":822,"towns":50},{"key":"murcia","name":"Murcia","listings":327,"towns":24},{"key":"granada","name":"Granada","listings":6,"towns":1},{"key":"cadiz","name":"Cádiz","listings":35,"towns":3}],"unmapped_locations":[],"costas":[{"name":"Costa del Sol","listings":861},{"name":"Costa Blanca South","listings":487},{"name":"Costa Calida","listings":275},{"name":"Costa Blanca North","listings":249},{"name":"Costa Blanca South - Inland","listings":76},{"name":"Costa Calida - Inland","listings":52},{"name":"Costa del Sol (Cadiz)","listings":35},{"name":"Costa Blanca North - Inland","listings":10},{"name":"Costa Tropical","listings":6}],"property_types":[{"name":"Apartment","listings":886},{"name":"Penthouse","listings":398},{"name":"Villa","listings":391},{"name":"Townhouse","listings":197},{"name":"Bungalow","listings":173},{"name":"Studio","listings":6}],"open_dataset_towns_now":67,"development_refs":756,"development_refs_missing":0,"promoter_names":"not available","promoter_names_reason":"The listing feed does not include promoter or developer company names. The value stored as developer is a source label written by the capture from the region (Costa del Sol versus the other regions). It is not a promoter directory.","source_labels":[{"name":"Via Xavia Estate","listings":1149},{"name":"Via Avena Estate","listings":902}],"source_labels_note":"Source labels on the current book, grouped from the developer field. These are not promoter names."},"price_history":{"source":"price_snapshots","first_date":"2026-08-05","latest_date":"2026-10-26","observed_days":76,"observed_days_source":"published movement ledger; its first and latest dates match the live price_snapshots endpoints","reason":null},"published_open_dataset":{"source":"public/open-data/dataset.json","readable":true,"name":"Avena Spanish Coastal New-Build Market Observations","version":"v2026-10-26","schema_version":2,"generated_at":"2026-10-26T06:52:56.385Z","license":"CC-BY-4.0","attribution":"Avena Terminal (avenaterminal.com)","first_date":"2026-08-05","latest_date":"2026-10-26","observation_days":76,"refs_observed":2343,"moves_recorded":764,"delistings_recorded":328,"relistings_recorded":50,"delistings_still_listed":45,"delistings_currently_absent":283,"live_listings":2051,"towns_published":67,"town_k_threshold":5,"zenodo":{"doi":"10.5281/zenodo.19520064","version":"1.0.0","published":"2026-04-11","listings":500,"note":"Earlier one-off snapshot. This dataset version is not deposited on Zenodo."},"honesty":["Prices are ASKING prices observed in listings. Spanish transaction prices are not public at unit level; nothing here is a registered sale price.","The observation ledger begins 2026-08-05. Earlier internal tables exist but repeated a frozen snapshot rather than recording observations, and are excluded on principle.","A delisting means the unit left the observed feed — strong evidence of absorption, not a notarised sale.","50 of the 328 delisted units were later observed listed again (relisted_on). Of those, 45 are on the market as of the latest observation day (still_listed=true) and are NOT evidence of absorption; the rest returned and left again. 283 of the 328 tombstoned units are absent today. Tombstones are never deleted — a withdrawal followed by a return is itself an observation, and one no public source records.","Cross-sectional aggregates cover only towns with at least 5 live listings.","No listing descriptions, images, URLs, or project/developer names are redistributed — only numeric observations and derived statistics.","AVM accuracy, measured nightly against the whole book, is published at https://avenaterminal.com/model-stats.json (in-sample, caveats included)."]},"ledger_gaps":[{"start":"2026-10-14","end":"2026-10-20","missingDays":7}],"ledger_gaps_source":"public/open-data/movement-ledger.json"},"dictionary":[{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"town","type":"string","unit":null,"nullable":false,"description":"Town name, the text before the comma in the listing location. Towns with fewer than 5 live listings are omitted from this file.","example":"Estepona"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"costa","type":"string","unit":null,"nullable":false,"description":"Costa label from the listing book for that town.","example":"Costa del Sol"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"n_listings","type":"integer","unit":"listings","nullable":false,"description":"Live listings in the town at the time the file was built.","example":230},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"median_price_eur","type":"number","unit":"EUR","nullable":false,"description":"Median asking price of the live listings in the town.","example":724500},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"median_pm2_eur","type":"number","unit":"EUR/m²","nullable":false,"description":"Median asking price per square metre.","example":6793},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"p25_pm2_eur","type":"number","unit":"EUR/m²","nullable":false,"description":"25th percentile of asking price per square metre.","example":5475},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"p75_pm2_eur","type":"number","unit":"EUR/m²","nullable":false,"description":"75th percentile of asking price per square metre.","example":8896},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"median_built_m2","type":"number","unit":"m²","nullable":false,"description":"Median built area of the live listings in the town.","example":102},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"villa_share_pct","type":"number","unit":"percent","nullable":false,"description":"Share of listings whose type is Villa, Townhouse, or Bungalow.","example":13},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"towns.csv / towns.json","field":"median_beach_km","type":"number","unit":"km","nullable":true,"description":"Median beach distance. Null when the town has no beach-distance values.","example":1.2},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"movement-ledger.csv / movement-ledger.json","field":"date","type":"date","unit":"YYYY-MM-DD","nullable":false,"description":"Observation day. Days with no snapshot are absent, not filled with zeros.","example":"2026-08-05"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"movement-ledger.csv / movement-ledger.json","field":"listings_observed","type":"integer","unit":"listings","nullable":false,"description":"Distinct listing refs observed that day.","example":1990},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"movement-ledger.csv / movement-ledger.json","field":"price_increases","type":"integer","unit":"listings","nullable":false,"description":"Verified asking-price increases observed that day. Unit changes are not included.","example":0},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"movement-ledger.csv / movement-ledger.json","field":"price_reductions","type":"integer","unit":"listings","nullable":false,"description":"Verified asking-price reductions observed that day. Unit changes are not included.","example":0},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"movement-ledger.csv / movement-ledger.json","field":"median_abs_move_pct","type":"number","unit":"percent","nullable":true,"description":"Median absolute size of the verified moves that day. Null when the day had no counted move.","example":null},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"movement-ledger.csv / movement-ledger.json","field":"delistings","type":"integer","unit":"listings","nullable":false,"description":"Listing refs recorded as leaving the feed that day. A delisting is not a registered sale.","example":0},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"movement-ledger.csv / movement-ledger.json","field":"relistings","type":"integer","unit":"listings","nullable":false,"description":"Delisted refs observed listed again that day.","example":0},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"moves.csv / moves.json","field":"avn_id","type":"string","unit":null,"nullable":false,"description":"Listing ref the move was observed on. The column name is historical; the value is the feed ref.","example":"N6155"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"moves.csv / moves.json","field":"date","type":"date","unit":"YYYY-MM-DD","nullable":false,"description":"Day the new asking price was observed.","example":"2026-08-06"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"moves.csv / moves.json","field":"prev_date","type":"date","unit":"YYYY-MM-DD","nullable":false,"description":"Day the previous asking price of the same ref was observed. Not necessarily the previous calendar day.","example":"2026-08-05"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"moves.csv / moves.json","field":"prev_price_eur","type":"number","unit":"EUR","nullable":false,"description":"Previous asking price.","example":270631},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"moves.csv / moves.json","field":"new_price_eur","type":"number","unit":"EUR","nullable":false,"description":"Newly observed asking price.","example":285631},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"moves.csv / moves.json","field":"change_pct","type":"number","unit":"percent","nullable":false,"description":"Change from the previous observed asking price to the new one, in percent.","example":5.54},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"moves.csv / moves.json","field":"town","type":"string","unit":null,"nullable":true,"description":"Town stored on the newer snapshot. Null when the snapshot had none.","example":"La Manga del Mar Menor"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"moves.csv / moves.json","field":"type","type":"string","unit":null,"nullable":true,"description":"Property type stored on the newer snapshot. Null when the snapshot had none.","example":"Townhouse"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"avn_id","type":"string","unit":null,"nullable":false,"description":"Listing ref that left the observed feed. The value is the feed ref.","example":"N9263"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"town","type":"string","unit":null,"nullable":true,"description":"Town on the delisting row.","example":"Pinoso"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"region","type":"string","unit":null,"nullable":true,"description":"Region code on the delisting row.","example":"cb-south"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"type","type":"string","unit":null,"nullable":true,"description":"Property type on the delisting row.","example":"Villa"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"beds","type":"number","unit":"bedrooms","nullable":true,"description":"Bedrooms on the delisting row.","example":null},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"built_m2","type":"number","unit":"m²","nullable":true,"description":"Built area on the delisting row.","example":null},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"last_price_eur","type":"number","unit":"EUR","nullable":true,"description":"Last asking price observed before the ref left the feed.","example":385000},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"last_pm2_eur","type":"number","unit":"EUR/m²","nullable":true,"description":"Last asking price per square metre observed before the ref left the feed.","example":3667},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"last_seen_date","type":"date","unit":"YYYY-MM-DD","nullable":true,"description":"Last day the ref was observed in the feed.","example":"2026-08-06"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"relisted_on","type":"date","unit":"YYYY-MM-DD","nullable":true,"description":"First later day the ref was observed listed again. Null when it has not returned. The tombstone row is kept either way.","example":null},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"tombstones.csv / tombstones.json","field":"still_listed","type":"boolean","unit":null,"nullable":false,"description":"True when the ref is present on the latest observation day. Those rows are not evidence of absorption.","example":false},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"name","type":"string","unit":null,"nullable":false,"description":"Dataset name written by the open-dataset generator.","example":"Avena Spanish Coastal New-Build Market Observations"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"version","type":"string","unit":null,"nullable":false,"description":"File version, the generation date prefixed with v. Not the Zenodo deposit.","example":"v2026-10-26"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"schema_version","type":"integer","unit":null,"nullable":false,"description":"Schema version of the observation files. 2 added relisted_on, relistings, and the split between delistings that returned and delistings still absent.","example":2},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"generated_at","type":"timestamp","unit":"ISO-8601","nullable":false,"description":"When this manifest was generated.","example":"2026-10-26T06:52:56.385Z"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"license","type":"string","unit":null,"nullable":false,"description":"License string written on the manifest.","example":"CC-BY-4.0"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"attribution","type":"string","unit":null,"nullable":false,"description":"Attribution string written on the manifest.","example":"Avena Terminal (avenaterminal.com)"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.first_date","type":"date","unit":"YYYY-MM-DD","nullable":false,"description":"First observation day in the published ledger.","example":"2026-08-05"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.latest_date","type":"date","unit":"YYYY-MM-DD","nullable":false,"description":"Latest observation day in the published ledger.","example":"2026-10-26"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.observation_days","type":"integer","unit":"days","nullable":false,"description":"Count of observation days in the file. Not a calendar span.","example":76},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.refs_observed","type":"integer","unit":"listings","nullable":false,"description":"Distinct refs present in the snapshots used to build the file.","example":2343},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.moves_recorded","type":"integer","unit":"moves","nullable":false,"description":"Rows in moves.csv.","example":764},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.delistings_recorded","type":"integer","unit":"listings","nullable":false,"description":"Rows in tombstones.csv, including refs later observed again.","example":328},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.relistings_recorded","type":"integer","unit":"listings","nullable":false,"description":"Tombstoned refs with a relisted_on date.","example":50},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.delistings_still_listed","type":"integer","unit":"listings","nullable":false,"description":"Tombstoned refs present again on the latest observation day.","example":45},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"observation_ledger.delistings_currently_absent","type":"integer","unit":"listings","nullable":false,"description":"Tombstoned refs absent on the latest observation day.","example":283},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"cross_section.live_listings","type":"integer","unit":"listings","nullable":false,"description":"Listing-book size when the file was built. It can differ from the book on a later deploy.","example":2051},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"cross_section.towns_published","type":"integer","unit":"towns","nullable":false,"description":"Towns in towns.csv.","example":67},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"cross_section.town_k_threshold","type":"integer","unit":"listings","nullable":false,"description":"Minimum live listings for a town to be published in towns.csv.","example":5},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"zenodo_snapshot.doi","type":"string","unit":null,"nullable":false,"description":"DOI of an earlier one-off snapshot. The manifest note says the current dataset version is not that deposit.","example":"10.5281/zenodo.19520064"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"zenodo_snapshot.published","type":"date","unit":"YYYY-MM-DD","nullable":false,"description":"Publication date of the Zenodo snapshot named on the manifest.","example":"2026-04-11"},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"zenodo_snapshot.listings","type":"integer","unit":"listings","nullable":false,"description":"Listing count of that Zenodo snapshot, as written on the manifest. Not the current book.","example":500},{"surface":"Open dataset (public/open-data and the avena-data market/ mirror)","record":"dataset.json","field":"zenodo_snapshot.note","type":"string","unit":null,"nullable":false,"description":"The generator's own note on what the Zenodo DOI is and is not.","example":"Earlier one-off snapshot. This dataset version is not deposited on Zenodo."},{"surface":"GET /api/v1/properties","record":"properties[]","field":"ref","type":"string","unit":null,"nullable":true,"description":"Feed listing reference. Omitted from JSON when the listing has none.","example":"N9739"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"name","type":"string","unit":null,"nullable":false,"description":"Listing title stored on the book.","example":"Modern New Build Villas in Finestrat with Private Pool Near Benidorm"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"developer","type":"string","unit":null,"nullable":false,"description":"Source label written by the capture, not a promoter company name. See coverage.","example":"Via Xavia Estate"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"town","type":"string","unit":null,"nullable":false,"description":"Location string as stored, normally \"town, province\".","example":"Finestrat, Alicante"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"region","type":"string","unit":null,"nullable":false,"description":"Costa name when the listing has one, otherwise the region code.","example":"Costa Blanca North"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"type","type":"string","unit":null,"nullable":false,"description":"Property type stored on the listing.","example":"Villa"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"price","type":"number","unit":"EUR","nullable":false,"description":"Asking price. Not a registered transaction price.","example":550000},{"surface":"GET /api/v1/properties","record":"properties[]","field":"price_to","type":"number","unit":"EUR","nullable":false,"description":"Upper asking price when the feed has a range. Equals price when it does not.","example":550000},{"surface":"GET /api/v1/properties","record":"properties[]","field":"pm2","type":"number","unit":"EUR/m²","nullable":true,"description":"Asking price per square metre of the area used for the listing.","example":5140},{"surface":"GET /api/v1/properties","record":"properties[]","field":"mm2","type":"number","unit":"EUR/m²","nullable":false,"description":"Area benchmark price per square metre stored on the listing. A model input, not a transaction index.","example":6466},{"surface":"GET /api/v1/properties","record":"properties[]","field":"built_m2","type":"number","unit":"m²","nullable":false,"description":"Built area stored on the listing.","example":107},{"surface":"GET /api/v1/properties","record":"properties[]","field":"plot_m2","type":"number","unit":"m²","nullable":true,"description":"Plot area. Null when the feed has none.","example":300},{"surface":"GET /api/v1/properties","record":"properties[]","field":"bedrooms","type":"number","unit":"bedrooms","nullable":false,"description":"Bedroom count stored on the listing.","example":3},{"surface":"GET /api/v1/properties","record":"properties[]","field":"bathrooms","type":"number","unit":"bathrooms","nullable":false,"description":"Bathroom count stored on the listing.","example":3},{"surface":"GET /api/v1/properties","record":"properties[]","field":"beach_km","type":"number","unit":"km","nullable":true,"description":"Beach distance stored on the listing.","example":5},{"surface":"GET /api/v1/properties","record":"properties[]","field":"status","type":"string","unit":null,"nullable":false,"description":"Build status stored on the listing.","example":"under-construction"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"completion","type":"string","unit":null,"nullable":false,"description":"Completion quarter stored on the listing, or TBA when the feed has no delivery date.","example":"2026-Q4"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"score","type":"number","unit":"0–100","nullable":true,"description":"Avena Score computed when the book is loaded. Not a read of score_history. Null when the listing was not scored.","example":79},{"surface":"GET /api/v1/properties","record":"properties[]","field":"score_confidence","type":"number","unit":"0–1","nullable":false,"description":"Deterministic adversarial confidence computed with the response. The route passes energy as null into that calculation.","example":0.94},{"surface":"GET /api/v1/properties","record":"properties[]","field":"score_confidence_codes","type":"string[]","unit":null,"nullable":false,"description":"Reason codes from the same confidence calculation. Empty when none apply.","example":["missing_energy"]},{"surface":"GET /api/v1/properties","record":"properties[]","field":"score_flagged_for_review","type":"boolean","unit":null,"nullable":false,"description":"True when that confidence is below the review threshold in the confidence module.","example":false},{"surface":"GET /api/v1/properties","record":"properties[]","field":"yield_gross","type":"number","unit":"percent","nullable":true,"description":"Gross yield estimate computed with the score. Null when the listing has no yield.","example":8.9},{"surface":"GET /api/v1/properties","record":"properties[]","field":"yield_net","type":"number","unit":"percent","nullable":true,"description":"Net yield estimate computed with the score.","example":5},{"surface":"GET /api/v1/properties","record":"properties[]","field":"yield_annual","type":"number","unit":"EUR","nullable":true,"description":"Gross annual rent estimate behind the yield.","example":49000},{"surface":"GET /api/v1/properties","record":"properties[]","field":"url","type":"string","unit":null,"nullable":false,"description":"URL stored on the listing. It is not guaranteed to be an http listing page.","example":"https://www.xaviaestate.com/search-property/province_4/city_65/page_1/order_ddesc/"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"image","type":"string","unit":null,"nullable":true,"description":"First image URL stored on the listing.","example":"https://fotos15.apinmo.com/7515/28857817/16-1.jpg"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"lat","type":"number","unit":"degrees","nullable":true,"description":"Latitude stored on the listing.","example":38.558160418991896},{"surface":"GET /api/v1/properties","record":"properties[]","field":"lng","type":"number","unit":"degrees","nullable":true,"description":"Longitude stored on the listing.","example":-0.20115097434858767},{"surface":"GET /api/v1/properties","record":"properties[]","field":"country","type":"string","unit":"ISO 3166-1 alpha-2","nullable":false,"description":"Country code. The route writes ES when the listing has none.","example":"ES"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"country_name","type":"string","unit":null,"nullable":false,"description":"Country name. The route writes Spain when the listing has none.","example":"Spain"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"currency","type":"string","unit":"ISO 4217","nullable":false,"description":"Currency code. The route writes EUR when the listing has none.","example":"EUR"},{"surface":"GET /api/v1/properties","record":"properties[]","field":"source_portal","type":"string","unit":null,"nullable":true,"description":"Portal name stored on the listing, when the book has one.","example":null},{"surface":"GET /api/v1/properties","record":"properties[]","field":"last_synced","type":"timestamp","unit":"ISO-8601","nullable":true,"description":"Last sync timestamp stored on the listing, when the book has one.","example":null},{"surface":"GET /api/v1/properties","record":"response","field":"total","type":"integer","unit":"listings","nullable":false,"description":"Listings matching the filters, before paging. The example is the unfiltered book.","example":2051},{"surface":"GET /api/v1/properties","record":"response","field":"limit","type":"integer","unit":"listings","nullable":false,"description":"Page size. Default 20. The route caps it at 50.","example":20},{"surface":"GET /api/v1/properties","record":"response","field":"offset","type":"integer","unit":"listings","nullable":false,"description":"Paging offset. Default 0.","example":0},{"surface":"GET /api/v1/properties","record":"response","field":"count","type":"integer","unit":"listings","nullable":false,"description":"Listings in this page.","example":20},{"surface":"GET /api/v1/properties","record":"response","field":"avg_price","type":"number","unit":"EUR","nullable":false,"description":"Mean asking price of the page, not of the whole filtered set.","example":472712},{"surface":"GET /api/v1/properties","record":"response","field":"avg_score","type":"number","unit":"0–100","nullable":false,"description":"Mean score of scored listings on the page. The route rounds the mean of an empty page to 0.","example":77},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"id","type":"string","unit":null,"nullable":false,"description":"Identifier derived from the feed ref by deriveAPIPId. Not the feed ref itself. The default payload's ref is the feed ref.","example":"ES-COST-1931"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"deal_score","type":"integer","unit":"0–100","nullable":false,"description":"Rounded score, clamped to 0–100. A listing with no score is emitted as 0.","example":53},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"yield_gross","type":"number","unit":"percent","nullable":true,"description":"Gross yield, rounded to 2 decimals. Omitted when the listing has no yield.","example":2.4},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"developer_rating","type":"string","unit":null,"nullable":true,"description":"Present in the APIP schema. toAPIP always sets it undefined, so the JSON omits it. Not populated from this book.","example":null},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"market_regime","type":"string","unit":null,"nullable":true,"description":"Present in the APIP schema. toAPIP always sets it undefined, so the JSON omits it.","example":null},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"liquidity_score","type":"integer","unit":"0–100","nullable":true,"description":"Present in the APIP schema. toAPIP always sets it undefined, so the JSON omits it.","example":null},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"carbon_rating","type":"string","unit":null,"nullable":true,"description":"Copied from the listing energy letter when that letter is A–G. No separate carbon figure is computed. Omitted otherwise.","example":"B"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"apci_at_listing","type":"number","unit":null,"nullable":true,"description":"Present in the APIP schema. toAPIP always sets it undefined, so the JSON omits it.","example":null},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"location.town","type":"string","unit":null,"nullable":false,"description":"Text before the comma in the location string.","example":"Estepona"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"location.region","type":"string","unit":null,"nullable":false,"description":"Costa name, or the region code when the listing has no costa.","example":"Costa del Sol"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"location.country","type":"string","unit":"ISO 3166-1 alpha-2","nullable":false,"description":"Country code. ES when the listing has none.","example":"ES"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"location.coordinates.lat","type":"number","unit":"degrees","nullable":true,"description":"Latitude. The coordinates object is omitted unless both lat and lng are present.","example":36.42236862288461},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"location.coordinates.lng","type":"number","unit":"degrees","nullable":true,"description":"Longitude. Omitted with coordinates when either value is missing.","example":-5.201588722366235},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"location.beach_km","type":"number","unit":"km","nullable":true,"description":"Beach distance. Omitted when the listing has none.","example":2.2},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"pricing.asking_price","type":"number","unit":"EUR","nullable":false,"description":"Asking price.","example":560000},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"pricing.price_per_m2","type":"number","unit":"EUR/m²","nullable":true,"description":"Asking price per square metre. Omitted when absent or zero.","example":7778},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"pricing.market_reference","type":"number","unit":"EUR/m²","nullable":true,"description":"The listing benchmark price per square metre (mm2). Omitted when absent or zero.","example":8687},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"pricing.currency","type":"string","unit":"ISO 4217","nullable":false,"description":"Currency. EUR when the listing has none.","example":"EUR"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"pricing.raw_price_local","type":"number","unit":"local currency","nullable":true,"description":"Pre-conversion price. Omitted when the listing has none. This book's rows do not carry it.","example":null},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"specifications.built_m2","type":"number","unit":"m²","nullable":true,"description":"Built area. Omitted when absent or zero.","example":72},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"specifications.bedrooms","type":"number","unit":"bedrooms","nullable":true,"description":"Bedrooms. Omitted when null.","example":3},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"specifications.bathrooms","type":"number","unit":"bathrooms","nullable":true,"description":"Bathrooms. Omitted when null.","example":2},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"specifications.pool","type":"string","unit":null,"nullable":true,"description":"Mapped to private, communal, or none. Other stored values are omitted.","example":"communal"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"specifications.energy","type":"string","unit":null,"nullable":true,"description":"Energy letter A–G, or pending when a value is present but not a letter. Omitted when the listing has none.","example":"B"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"specifications.status","type":"string","unit":null,"nullable":true,"description":"Mapped to off_plan, under_construction, key_ready, or resale. Unrecognised status text is omitted.","example":"under_construction"},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"source.portal","type":"string","unit":null,"nullable":true,"description":"Portal stored on the listing. The source object is omitted when portal, source ref, last sync, and URL are all empty.","example":null},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"source.source_ref","type":"string","unit":null,"nullable":true,"description":"Source reference stored on the listing.","example":null},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"source.last_synced","type":"timestamp","unit":"ISO-8601","nullable":true,"description":"Last sync timestamp stored on the listing.","example":null},{"surface":"GET /api/v1/properties?format=apip","record":"property","field":"source.url","type":"string","unit":null,"nullable":true,"description":"URL stored on the listing.","example":"mailto:henrik@xaviaestate.com"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"ref","type":"string","unit":null,"nullable":false,"description":"Feed ref, or the development ref when the feed ref is missing. Empty string when both are missing.","example":"SP1931"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"type","type":"string","unit":null,"nullable":false,"description":"Property type.","example":"Apartment"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"town","type":"string","unit":null,"nullable":false,"description":"Location string as stored.","example":"Estepona, Málaga"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"region","type":"string","unit":null,"nullable":false,"description":"Region code, not the costa name. The properties API region field prefers the costa name.","example":"costa-del-sol"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"price","type":"number","unit":"EUR","nullable":false,"description":"Asking price.","example":560000},{"surface":"GET /api/v1/dataset-export","record":"row","field":"price_m2","type":"number","unit":"EUR/m²","nullable":true,"description":"Asking price per square metre.","example":7778},{"surface":"GET /api/v1/dataset-export","record":"row","field":"score","type":"number","unit":"0–100","nullable":true,"description":"Score computed when the book is loaded.","example":53},{"surface":"GET /api/v1/dataset-export","record":"row","field":"yield_gross","type":"number","unit":"percent","nullable":true,"description":"Gross yield estimate.","example":2.4},{"surface":"GET /api/v1/dataset-export","record":"row","field":"beds","type":"number","unit":"bedrooms","nullable":false,"description":"Bedroom count.","example":3},{"surface":"GET /api/v1/dataset-export","record":"row","field":"baths","type":"number","unit":"bathrooms","nullable":false,"description":"Bathroom count.","example":2},{"surface":"GET /api/v1/dataset-export","record":"row","field":"m2","type":"number","unit":"m²","nullable":false,"description":"Built area.","example":72},{"surface":"GET /api/v1/dataset-export","record":"row","field":"beach_km","type":"number","unit":"km","nullable":true,"description":"Beach distance.","example":2.2},{"surface":"GET /api/v1/dataset-export","record":"row","field":"developer","type":"string","unit":null,"nullable":false,"description":"Source label, not a promoter name.","example":"Via Avena Estate"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"status","type":"string","unit":null,"nullable":false,"description":"Build status.","example":"under-construction"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"energy","type":"string","unit":null,"nullable":true,"description":"Energy rating stored on the listing.","example":"B"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"pool","type":"string","unit":null,"nullable":true,"description":"Pool value stored on the listing.","example":"communal"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"source","type":"string","unit":null,"nullable":false,"description":"Constant attribution string written by this route on every row.","example":"Avena Terminal (avenaterminal.com)"},{"surface":"GET /api/v1/dataset-export","record":"row","field":"doi","type":"string","unit":null,"nullable":false,"description":"Constant DOI string written by this route on every row. The open-dataset manifest describes that DOI as an earlier snapshot, not the current observation file.","example":"10.5281/zenodo.19520064"},{"surface":"GET /api/v1/open-dataset","record":"response","field":"version","type":"string","unit":null,"nullable":false,"description":"Literal version written by this route. It is not the version in /open-data/dataset.json.","example":"1.0.0"},{"surface":"GET /api/v1/open-dataset","record":"response","field":"license","type":"string","unit":null,"nullable":false,"description":"License URL written by this route.","example":"https://creativecommons.org/licenses/by/4.0/"},{"surface":"GET /api/v1/open-dataset","record":"data.town_statistics[]","field":"town","type":"string","unit":null,"nullable":false,"description":"Full location string from the listing book, including the province. Not the town-only name used in towns.csv.","example":"Estepona, Málaga"},{"surface":"GET /api/v1/open-dataset","record":"data.town_statistics[]","field":"count","type":"integer","unit":"listings","nullable":false,"description":"Listings with that location string.","example":230},{"surface":"GET /api/v1/open-dataset","record":"data.town_statistics[]","field":"avg_price","type":"number","unit":"EUR","nullable":false,"description":"Mean asking price, rounded. The route emits 0 when the input list is empty.","example":989440},{"surface":"GET /api/v1/open-dataset","record":"data.town_statistics[]","field":"avg_yield","type":"number","unit":"percent","nullable":false,"description":"Mean gross yield, one decimal. 0 when the location has no yield estimates.","example":2},{"surface":"GET /api/v1/open-dataset","record":"data.town_statistics[]","field":"avg_score","type":"number","unit":"0–100","nullable":false,"description":"Mean score, rounded. 0 when the location has no scores.","example":51},{"surface":"GET /api/v1/open-dataset","record":"data.town_statistics[]","field":"avg_pm2","type":"number","unit":"EUR/m²","nullable":false,"description":"Mean asking price per square metre, rounded.","example":7903},{"surface":"GET /api/v1/open-dataset","record":"data.town_statistics[]","field":"source","type":"string","unit":null,"nullable":false,"description":"Constant attribution written on every aggregate row.","example":"Avena Terminal (avenaterminal.com)"},{"surface":"GET /api/v1/open-dataset","record":"data.town_statistics[]","field":"license","type":"string","unit":null,"nullable":false,"description":"Constant license string written on every aggregate row.","example":"CC BY 4.0"},{"surface":"GET /api/v1/open-dataset","record":"data.costa_statistics[]","field":"costa","type":"string","unit":null,"nullable":false,"description":"Costa label from the listing book.","example":"Costa del Sol"},{"surface":"GET /api/v1/open-dataset","record":"data.costa_statistics[]","field":"count","type":"integer","unit":"listings","nullable":false,"description":"Listings in that costa.","example":861},{"surface":"GET /api/v1/open-dataset","record":"data.costa_statistics[]","field":"avg_price","type":"number","unit":"EUR","nullable":false,"description":"Mean asking price in the costa, rounded.","example":1006990},{"surface":"GET /api/v1/open-dataset","record":"data.costa_statistics[]","field":"avg_yield","type":"number","unit":"percent","nullable":false,"description":"Mean gross yield in the costa. 0 when none of the listings have a yield.","example":2},{"surface":"GET /api/v1/open-dataset","record":"data.costa_statistics[]","field":"avg_score","type":"number","unit":"0–100","nullable":false,"description":"Mean score in the costa. 0 when none of the listings have a score.","example":50},{"surface":"GET /api/v1/open-dataset","record":"data.costa_statistics[]","field":"avg_pm2","type":"number","unit":"EUR/m²","nullable":false,"description":"Mean asking price per square metre in the costa, rounded.","example":7925},{"surface":"GET /api/v1/open-dataset","record":"data.costa_statistics[]","field":"source","type":"string","unit":null,"nullable":false,"description":"Constant attribution written on every aggregate row.","example":"Avena Terminal (avenaterminal.com)"},{"surface":"GET /api/v1/open-dataset","record":"data.costa_statistics[]","field":"license","type":"string","unit":null,"nullable":false,"description":"Constant license string written on every aggregate row.","example":"CC BY 4.0"},{"surface":"GET /api/v1/open-dataset","record":"data.property_type_distribution[]","field":"type","type":"string","unit":null,"nullable":false,"description":"Property type.","example":"Apartment"},{"surface":"GET /api/v1/open-dataset","record":"data.property_type_distribution[]","field":"count","type":"integer","unit":"listings","nullable":false,"description":"Listings of that type.","example":886},{"surface":"GET /api/v1/open-dataset","record":"data.property_type_distribution[]","field":"pct","type":"number","unit":"percent","nullable":false,"description":"Share of the book, one decimal.","example":43.2},{"surface":"GET /api/v1/open-dataset","record":"data.price_band_distribution[]","field":"band","type":"string","unit":null,"nullable":false,"description":"Asking-price band label defined in the route.","example":"Under €100k"},{"surface":"GET /api/v1/open-dataset","record":"data.price_band_distribution[]","field":"count","type":"integer","unit":"listings","nullable":false,"description":"Listings in that band. The top of each band is exclusive.","example":1},{"surface":"GET /api/v1/open-dataset","record":"data.score_distribution[]","field":"band","type":"string","unit":null,"nullable":false,"description":"Score band label defined in the route.","example":"90–100 (Exceptional)"},{"surface":"GET /api/v1/open-dataset","record":"data.score_distribution[]","field":"count","type":"integer","unit":"listings","nullable":false,"description":"Scored listings in that band.","example":0},{"surface":"GET /api/v1/open-dataset","record":"data.yield_distribution[]","field":"band","type":"string","unit":null,"nullable":false,"description":"Gross-yield band label defined in the route.","example":"Over 8%"},{"surface":"GET /api/v1/open-dataset","record":"data.yield_distribution[]","field":"count","type":"integer","unit":"listings","nullable":false,"description":"Listings whose gross yield falls in that band.","example":65},{"surface":"GET /api/v1/open-dataset","record":"data.index_values","field":"apci_composite","type":"number","unit":null,"nullable":false,"description":"A single number this route computes from the book averages. It is not the APCI series published at /avena-index.","example":22.7},{"surface":"GET /api/v1/open-dataset","record":"data.index_values","field":"avg_investment_score","type":"number","unit":"0–100","nullable":false,"description":"Mean score of scored listings, one decimal.","example":49.9},{"surface":"GET /api/v1/open-dataset","record":"data.index_values","field":"avg_price","type":"number","unit":"EUR","nullable":false,"description":"Mean asking price of the book, rounded.","example":723589},{"surface":"GET /api/v1/open-dataset","record":"data.index_values","field":"avg_yield","type":"number","unit":"percent","nullable":false,"description":"Mean gross yield of listings that have one, two decimals.","example":3.58},{"surface":"GET /api/v1/open-dataset","record":"data.index_values","field":"avg_pm2","type":"number","unit":"EUR/m²","nullable":false,"description":"Mean asking price per square metre, rounded.","example":6340},{"surface":"GET /api/v1/open-dataset","record":"data.index_values","field":"total_properties","type":"integer","unit":"listings","nullable":false,"description":"Listings in the book used to build the response.","example":2051},{"surface":"GET /api/v1/open-dataset","record":"data.index_values","field":"scored_properties","type":"integer","unit":"listings","nullable":false,"description":"Listings that have a score.","example":2051},{"surface":"GET /api/v1/open-dataset","record":"data.index_values","field":"date","type":"date","unit":"YYYY-MM-DD","nullable":false,"description":"UTC date of the request, not the feed generation date.","example":"2026-10-26"}],"dictionary_scope":"Fields on the open observation files, on GET /api/v1/properties (default and format=apip), on GET /api/v1/dataset-export, and on the aggregate payload of GET /api/v1/open-dataset. Other routes are not this dataset. Their index is /api/openapi.json.","pipeline":[{"id":"feed-refresh","name":"Feed refresh","cadence":"GitHub Actions feed-refresh.yml at 01:37 UTC and 05:10 UTC, plus workflow_dispatch.","what":"Refreshes the listing book in public/data.json from the daily capture and rebuilds the open-data observation files. After the book is deployed it calls /api/cron/pricing-history and /api/cron/scribe.","source_file":".github/workflows/feed-refresh.yml","last_observed":"2026-10-26T06:52:07.350Z","last_observed_kind":"feed-meta.json generated_at, from the /api/health feed check. This is the capture artifact time, not the GitHub run start.","health_status":"ok","health_detail":"deployed feed is 3h old"},{"id":"price-capture","name":"Daily price capture","cadence":"Vercel cron /api/cron/pricing-history at 02:20 UTC and 14:30 UTC. feed-refresh.yml also calls that route after the new book is deployed. The cron can run before that deploy.","what":"Writes price_snapshots for the current UTC day from the deployed listing book and diffs asking prices against the previous trusted day. Same-unit checks are applied there.","source_file":"vercel.json","last_observed":"2026-10-26","last_observed_kind":"Latest price_snapshots.snapshot_date from the /api/health capture check. A date, not the clock time of the job. The job clock time is not in /api/health.","health_status":"ok","health_detail":"today's capture (2026-10-26) is in"},{"id":"capture-backstop","name":"Capture backstop","cadence":"GitHub Actions capture-backstop.yml at 07:00 UTC and 09:00 UTC.","what":"Checks whether today's capture is missing and, only if it is, dispatches feed-refresh. It does not reconstruct an earlier day that was never stored.","source_file":".github/workflows/capture-backstop.yml","last_observed":"not available","last_observed_kind":"The run timestamp is not in /api/health. That payload only carries the latest completed-run conclusion.","health_status":"ok","health_detail":"Workflows check from /api/health (feed-refresh, capture-backstop, and tests together): feed-refresh: success, capture-backstop: success, tests: success"},{"id":"es-official","name":"Spain official benchmark","cadence":"GitHub Actions es-official-refresh.yml on Wednesday at 04:40 UTC.","what":"Rebuilds data/es-official.json from INE housing price index table 79563 and the Ministerio de Vivienda y Agenda Urbana appraisal file. Separate from the listing history. The Registradores series is recorded as not ingested when the portal refuses the job.","source_file":".github/workflows/es-official-refresh.yml","last_observed":"2026-10-24T23:22:40.336Z","last_observed_kind":"data/es-official.json generated_at on this deployment. /api/health does not watch es-official-refresh.yml, so the GitHub run timestamp is not available.","health_status":"not available","health_detail":"not available"}],"health_checked_at":"2026-10-26T10:18:52.563Z","quality":{"history_starts":"2026-08-05","history_start_note":"The published observation ledger begins 2026-08-05, the day price capture was pointed at the live feed. Earlier internal tables repeated a frozen snapshot and are excluded. Snapshots before that date are not in the open dataset.","declared_capture_gaps":[{"from":"2026-10-14","to":"2026-10-20"}],"declared_capture_gap_note":"The sell-through monitor records this gap: no snapshots on these dates after a feed outage. Listings last seen the day before the gap and absent the day after left on an unknown date inside the gap and are flagged as exits in that gap. The ledger gaps below are computed from the published movement ledger on this deployment, which can show the same gap and any further gap.","unit_identity":"A developer often advertises several units of one building under a single listing reference and changes which unit it shows. A change in asking price counts as a price move only when it is the same unit: same property type, bedrooms and bathrooms, and built and plot size within 2%. When the specification changed, the row is recorded as a unit change and excluded from move counts. A move of 25% or more also needs full specs on both sides, the same photo set, a new EUR/m² within 0.5–2× the area benchmark, and must not return exactly to an asking price the listing showed in the previous 365 days; otherwise it is marked unverified and not counted. Every observation is kept. The verdict is stored on the row.","move_status_since":"2026-10-24","move_status_note":"Snapshot rows carry move_status from 2026-10-24. moves.csv drops a change only when that status is unit_changed or unverified. A row with no status is not dropped. History from before that date was not reclassified.","excluded":["Registered transaction prices. Spanish unit-level sale prices are not in this dataset. Figures are asking prices.","Days with no capture, including the declared gap. Those days are absent. They are not filled.","Snapshots before 2026-08-05.","Unit changes and unverified large moves, from moves.csv and from move counts. The snapshot row is kept.","Towns with fewer than 5 live listings, from towns.csv only. They remain in the listing book and on the listings API.","Listing descriptions, image files, listing URLs, and project or promoter names, from the open observation files. The current book at /data.json still contains description text and image URLs.","Promoter company names. They are not in the feed.","The resale market and the separate Spain official statistics file. This book is new-build listings from the daily capture."]},"point_in_time":{"summary":"Asking-price history is a calendar of observations. A stored day is the book captured for that UTC date. Missed days stay missed. Scores on the live API are computed at read time and are not that history.","asking_prices":"price_snapshots is written for the current UTC day, one row per listing ref and date. A later capture on the same UTC day upserts that day's row, so the same day can be replaced. The job does not write earlier dates. score rows in score_history are not rewritten: the scribe upsert ignores a row that already exists for that ref and date.","backfill":"A calendar day that was not captured is not backfilled. The capture backstop only dispatches a fresh capture when today is missing. It cannot invent the book for a day that has already passed without a snapshot.","stored_scores":"score_history is written by /api/cron/scribe. The Vercel cron is 03:05 UTC (5 3 * * *), and feed-refresh.yml calls the same route after a deploy. Existing rows are not updated. Rows dated before 2026-08-21 can be filed one day after the book they describe. The route dates rows from the feed file after that seam and does not rewrite the earlier rows.","live_api_scores":"score, yield, and score_confidence on GET /api/v1/properties are computed when the response is built. They are not a read of score_history. A methodology change changes the live score without rewriting stored history.","open_dataset":"The open dataset is rebuilt from snapshots on or after 2026-08-05 and from the listing book at build time. Rebuilding it does not create rows for dates that have no snapshot. A same-day replacement of today's snapshot is what a later build of that same day will contain.","scribe_last_run":"not available","scribe_last_run_reason":"/api/health does not report the scribe job, so its last-run timestamp is not available."},"delivery":[{"id":"properties","method":"GET","path":"/api/v1/properties","format":"JSON","auth":"API key required. A request with no key is rejected.","note":"Listing page, default 20 rows, cap 50. format=apip returns the APIP shape of the same page. Pricing on request. See /license and /access."},{"id":"dataset-export","method":"GET","path":"/api/v1/dataset-export","format":"JSON. CSV with ?format=csv. JSONL wrappers with ?format=kaggle and ?format=huggingface.","auth":"No key on this route.","note":"Column subset of the current listing book. The kaggle and huggingface query values change the file shape. They do not mean this response was fetched from those sites."},{"id":"open-dataset-api","method":"GET","path":"/api/v1/open-dataset","format":"JSON","auth":"No key.","note":"Aggregate counts for the current book. No listing rows."},{"id":"open-data-files","method":"GET","path":"/open-data/dataset.json","format":"JSON and CSV","auth":"No key.","note":"Observation files: dataset.json, towns.csv, towns.json, movement-ledger.csv, movement-ledger.json, moves.csv, moves.json, tombstones.csv, tombstones.json."},{"id":"git-mirror","method":"GET","path":"https://github.com/HenrikKolstad/avena-data","format":"git, market/ directory","auth":"Public repository.","note":"Mirror of the observation files. /api/health compares market/dataset.json. Latest mirror date from this health read: 2026-10-25."},{"id":"listing-book","method":"GET","path":"/data.json","format":"JSON","auth":"No key.","note":"Current listing book used by the site, including description text and image URLs that the open observation files omit. It is the current cross-section, not the price history."},{"id":"sample","method":"GET","path":"/api/v1/due-diligence/sample","format":"CSV","auth":"No key.","note":"First 25 data rows of public/open-data/moves.csv, unchanged."},{"id":"spain-official","method":"GET","path":"/spain/official","format":"HTML. Source file data/es-official.json.","auth":"No key.","note":"Weekly official benchmark. Not the listing history."},{"id":"huggingface","method":"GET","path":"https://huggingface.co/datasets/AVENATERMINAL/spain-new-build-properties-2026","format":"Hugging Face dataset","auth":"Public page.","note":"feed-refresh.yml uploads the open-data files here when HF_TOKEN is set, and leaves the existing copy when it is not. /api/health does not report this copy. Freshness is not available."}],"licensing":{"open_observations":"The observation manifest on this deployment says license CC-BY-4.0 and attribution \"Avena Terminal (avenaterminal.com)\". The license page states that aggregate datasets, research papers, and training data published by Avena Terminal are under CC BY 4.0, with attribution to Avena Terminal (avenaterminal.com).","zenodo":"Earlier one-off snapshot. This dataset version is not deposited on Zenodo.","listings_api":"The keyed listings API is covered by the API section of /license. This pack does not restate tiers. Commercial terms: Pricing on request.","access_href":"/access","license_href":"/license","sourcing":["Listings are Avena's daily capture of agency-marketed new-build asking prices.","Prices in the listing book and the observation files are asking prices. A delisting means the ref left the observed feed. It is not a notarised sale.","The observation ledger used for the open dataset starts on 2026-08-05. Earlier repeated snapshots are excluded.","The Spain official file is a separate weekly pull from INE table 79563 and the housing ministry appraisal file. Its omissions, including sources the job could not read, are in that file.","Earlier one-off snapshot. This dataset version is not deposited on Zenodo."]},"sample":{"href":"/api/v1/due-diligence/sample","source":"public/open-data/moves.csv","rows":25,"note":"CSV of the first 25 data rows of the published moves file. The full files are linked under delivery."},"not_available":[{"field":"coverage.feed.promoter_names","reason":"The listing feed does not include promoter or developer company names. The value stored as developer is a source label written by the capture from the region (Costa del Sol versus the other regions). It is not a promoter directory."},{"field":"pipeline.capture-backstop.last_observed","reason":"The run timestamp is not in /api/health. That payload only carries the latest completed-run conclusion."},{"field":"pipeline.es-official.health_status","reason":"/api/health did not return a status for this step."},{"field":"point_in_time.scribe_last_run","reason":"/api/health does not report the scribe job, so its last-run timestamp is not available."},{"field":"pipeline.price-capture.run_clock_time","reason":"/api/health reports the latest snapshot date, not the clock time the capture job ran."},{"field":"pipeline.capture-backstop.run_clock_time","reason":"/api/health reports the workflow conclusion, not the run timestamp."},{"field":"pipeline.es-official.github_run_timestamp","reason":"/api/health does not watch es-official-refresh.yml. A generated_at on data/es-official.json is the artifact on this deployment, not a GitHub run timestamp."},{"field":"delivery.huggingface.freshness","reason":"Not in /api/health. The feed workflow uploads this copy only when a token is set."}]}