{"openapi":"3.1.0","info":{"title":"flatin.pt API","summary":"Portuguese home buying, machine-readable: new-build developments, where-to-live guides, municipality data, IMT and stamp duty (Imposto do Selo) on a purchase, IMI rates for all 308 municipalities.","description":"Keyless public API of flatin.pt. Numbers are the same as on the site and come from the official tables; every successful JSON answer carries an attribution field — show it next to the numbers. Rate limits: 120 requests per minute per IP address, HTTP 429 with Retry-After when exceeded. Status: https://flatin.pt/status/. MCP server: https://flatin.pt/mcp.","termsOfService":"https://flatin.pt/en/legal/terms/","contact":{"name":"flatin.pt","url":"https://flatin.pt/en/tools/api-and-data/","email":"info@flatin.pt"},"license":{"name":"CC BY 4.0 (data)","url":"https://creativecommons.org/licenses/by/4.0/"},"version":"1.0.0"},"servers":[{"url":"https://flatin.pt"}],"paths":{"/api/v1/imi/rates":{"get":{"tags":["public"],"summary":"IMI rates for all municipalities","description":"The yearly urban IMI rate of every Portuguese municipality for the latest verified tax year, or for `year` if given. Where a municipality sets no single rate (it is set per parish), the rate comes with `available: false` and the reason, never as zero. Every answer carries an `attribution` field.","operationId":"imi_rates_api_v1_imi_rates_get","parameters":[{"name":"year","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Year"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/imi/rates.csv":{"get":{"tags":["public"],"summary":"The same rates as one CSV file","description":"Open data: the same rows as the JSON list, under the same licence (see the Link header). An empty rate cell means the municipality sets no single rate, not zero. `year` selects a verified past table.","operationId":"imi_rates_csv_api_v1_imi_rates_csv_get","parameters":[{"name":"year","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Year"}}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/imi/rates.geojson":{"get":{"tags":["public"],"summary":"IMI rates with municipality boundaries (GeoJSON)","description":"Open data for GIS: a GeoJSON FeatureCollection (WGS 84) with one polygon per municipality and flat properties `codigo`, `municipality`, `distrito`, `year`, `urban_available`, `urban_rate_percent` (a number, 0.3 means 0.3 %), `urban_reason`, `rural_rate_percent` and `page`. Where a municipality sets no single rate the rate is null, `urban_available` is false and `urban_reason` says why; never zero. Boundaries: CAOP (Direção-Geral do Território), simplified, CC BY 4.0, credit in the `boundaries` member. `year` selects a verified past table.","operationId":"imi_rates_geojson_api_v1_imi_rates_geojson_get","parameters":[{"name":"year","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Year"}}],"responses":{"200":{"description":"GeoJSON FeatureCollection","content":{"application/geo+json":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/imi/rates-history.csv":{"get":{"tags":["public"],"summary":"Every verified year of IMI rates in one CSV file","description":"Open data: one row per municipality per verified tax year (long format), columns `codigo`, `municipality`, `municipality_as_published`, `distrito`, `year`, `urban_rate_percent`, `rural_rate_percent` (numbers, 0.3 means 0.3 %) and `verified_on` (the date the year was checked against the source). An empty rate cell means the municipality sets no single rate, not zero. CC BY 4.0.","operationId":"imi_rates_history_csv_api_v1_imi_rates_history_csv_get","responses":{"200":{"description":"CSV file","content":{"text/csv":{}}}}}},"/api/v1/imi/rates/{codigo}":{"get":{"tags":["public"],"summary":"IMI rate of one municipality","description":"One municipality by its four-digit code or name, with the rate `history` by tax year and its `movement` (raised, lowered, unchanged, returned, not_comparable). An unknown municipality gets 404 with a link to the full list.","operationId":"imi_rate_api_v1_imi_rates__codigo__get","parameters":[{"name":"codigo","in":"path","required":true,"schema":{"type":"string","description":"Four-digit municipality code (1312) or its name (Porto)","title":"Codigo"},"description":"Four-digit municipality code (1312) or its name (Porto)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/imt/calculate":{"post":{"tags":["public"],"summary":"What a purchase costs on top of the price","description":"IMT (property transfer tax), Imposto do Selo (stamp duty) and the property registration. Body: `value` (the contract price in euros), optional `territory` (`continente` or `regioes_autonomas`), `primary_home` (default true) and `buyer_is_young` (default false: 35 or under, first own permanent home, not an IRS dependant, no residential property owned in the previous three years), `non_resident` (default false: true for a buyer who is not and has never been tax resident in Portugal), `tax_haven_company` (default false: true when the buyer is a company or other entity with its tax domicile in a jurisdiction on the Portuguese list of more favourable tax regimes, or controlled by one; never an individual), and `vpt` (the valor patrimonial tributário from the caderneta predial, in euros; optional). A non-resident buyer pays IMT at a flat rate with no exemption or reduction (CIMT art. 17.º n.º 10): `imt_regime` is `non_resident_flat` instead of `tables`, the young buyers' table and the stamp duty deduction do not apply, and `annullable` gives what the Tax Authority annuls on request if the buyer becomes tax resident within the window or lets the home at a moderate rent (n.º 11–12) — two amounts, the months of each window and the request deadline. For a resident buyer `annullable` is null. A listed-regime company pays 10 % with no exemption or reduction (CIMT art. 17.º n.º 4), even when it is resident and even with `non_resident`: `imt_regime` is `tax_haven_flat` and `annullable` is null. IMT and stamp duty are charged on the higher of the contract price and the VPT (CIMT art. 12.º n.º 1; Código do Imposto do Selo art. 9.º n.º 4): `taxable_value_cents` is that base and `taxable_base` says which one it is (`price` or `vpt`). Without `vpt` the base is the price, and a higher VPT would make both taxes higher. `notary_estimate_cents` is the published price of one registration act at the Casa Pronta counter of the Ministério da Justiça. It does not cover the purchase contract at a notary, buying with a mortgage (a second registration act plus stamp duty on the loan) or the agency's fee — see `notes`. Annual IMI is not part of `total_cents`: it is charged on the VPT, not on the price — see /api/v1/imi/rates/{codigo} for the rate. For a young buyer the reduced IMT table applies and stamp duty is reduced by the deduction of art. 7.º-A of the Código do Imposto do Selo: `stamp_duty_cents` is the amount due, `stamp_duty_relief_cents` the deduction. Invalid input gets 422 with `error` and `field`.","operationId":"imt_calculate_api_v1_imt_calculate_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/barometer/series.csv":{"get":{"tags":["public"],"summary":"Building-permit barometer: monthly case counts per municipality","description":"Open data (CC BY 4.0). One row per municipality, period and measure. `cases` counts municipal building-works cases entering the licensing pipeline, dated by that municipality's declared reference event — not licences granted, and not dwellings. `measure` follows the INE breakdown: new_build, alter_extend, total_works, plus unclassified (cases whose works type the municipality does not state) and pip (preliminary enquiries, counted apart). `provisional` marks periods the source layer is still back-filling. `vintage` is the day the series was snapshotted: pass it back to reproduce a citation. Every row carries the source layer it was counted from.","operationId":"barometer_series_csv_api_v1_barometer_series_csv_get","parameters":[{"name":"granularity","in":"query","required":false,"schema":{"type":"string","default":"month","title":"Granularity"}},{"name":"vintage","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vintage"}}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/barometer/series":{"get":{"tags":["public"],"summary":"The same barometer series as JSON, with attribution","description":"The same rows as the CSV, plus an `attribution` object naming both data sources separately: our own counts from municipal GIS layers, and the official INE series used as context and as the population denominator.","operationId":"barometer_series_api_v1_barometer_series_get","parameters":[{"name":"granularity","in":"query","required":false,"schema":{"type":"string","default":"month","title":"Granularity"}},{"name":"vintage","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Vintage"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/barometer/official.csv":{"get":{"tags":["public"],"summary":"The official INE series the barometer is checked against","description":"Open data (CC BY 4.0, source INE). Licensed buildings and dwellings per municipality, and resident population, exactly as INE publishes them — no processing of ours beyond reshaping. Each row carries the exact INE API call it came from and the date INE last updated that indicator. Note on municipality_code: it is DICOFRE on the mainland, but for the thirty municipalities of the Azores and Madeira it is the tax authority's own code (Funchal is 2203, not 3103), because that is the key the rest of this site uses. municipality_as_ine_publishes_it carries INE's own name for the row.","operationId":"barometer_official_csv_api_v1_barometer_official_csv_get","parameters":[{"name":"series","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Series"}}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/barometer/sce.csv":{"get":{"tags":["public"],"summary":"ADENE energy-certificate statistics (SCE) for new housing","description":"Mirror of ADENE's public SCE statistics, per month and municipality, for two measures: precert_new_housing (context 'Projeto Edifícios Novos', type 'Habitação') and completed_new_housing (context 'Edifícios Concluídos Novos', type 'Habitação'). Source: ADENE — SCE; credit it as such. A pre-certificate is issued for every dwelling at the DESIGN stage: it is not a building licence and not a construction start, and this series is not comparable one-to-one with INE's licensed dwellings. certificates is the sum over energy classes; avg_useful_area_m2 is the certificate-weighted mean of ADENE's per-class averages. A municipality with no row in a month had zero certificates that month (ADENE prints only non-zero rows). Coverage: mainland Portugal and Madeira. Note on municipality_code: DICOFRE on the mainland, but for Madeira it is the tax authority's code (Funchal is 2203, not 3103), the same key as the rest of this site. Each row carries the ADENE file it came from, that file's sha256 and the day we fetched it.","operationId":"barometer_sce_csv_api_v1_barometer_sce_csv_get","parameters":[{"name":"measure","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Measure"}}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/newbuilds":{"get":{"tags":["public","public"],"summary":"Search new-build projects in Portugal","description":"Published new-build projects (empreendimentos) with filters: municipality (Portuguese name, slug or four-digit code), parish, typology (T0–T5, repeatable; T5 means five bedrooms or more), price_min and price_max in euros, stage (planned, licensed, building, selling, delivered), delivery_by (year; completed or promised for that year or earlier, overdue promises included), energy_class (A+…F, repeatable), on_sale, sort (price, name, delivery, new), limit (1–50, default 10) and offset. language (pt, en, ru, ua, de, fr, nl) picks the language of page URLs and labels. Every result carries its canonical page URL; catalog_url is the same selection on the site.","operationId":"newbuilds_search_api_v1_newbuilds_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"A parameter is not valid: error, field, message"}},"x-flatin-example":"/api/v1/newbuilds?municipality=Porto"}},"/api/v1/newbuilds/{slug}":{"get":{"tags":["public","public"],"summary":"One new-build project: prices, status, purchase cost, nearby","description":"One published project by slug (or its page URL): prices and units per typology, price history, construction stage and delivery promises, linked building permits, the developer, the full purchase cost at the cheapest available price (IMT, stamp duty, registration; primary_home and buyer_is_young adjust it), nearby transport, schools, health, shops and parks, and the canonical page URL in each of the seven languages.","operationId":"newbuild_detail_api_v1_newbuilds__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"A parameter is not valid"},"404":{"description":"No published project with this slug"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-flatin-example":"/api/v1/newbuilds?limit=1"}},"/api/v1/reports/obra-nova.json":{"get":{"tags":["public","public"],"summary":"Monthly report 'Obra nova em Portugal': list of editions","description":"Every published edition of the monthly new-build report, newest first, with links to its page, CSV and JSON. Editions are frozen on their publication day.","operationId":"report_editions_api_v1_reports_obra_nova_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/reports/obra-nova/{edition}.csv":{"get":{"tags":["public","public"],"summary":"One edition of the monthly new-build report as CSV","description":"Open data (CC BY 4.0, see the Link header). One row per municipality plus a national row (`municipality_code` = PT): INE dwellings licensed in new buildings (3-month window and the same window a year before, and the latest full year), INE median €/m² of new-dwelling sales, and the flatin.pt catalogue (developments, units for sale, entry price, median asking €/m²) and barometer. `edition` is YYYY-MM or `latest`.","operationId":"report_csv_api_v1_reports_obra_nova__edition__csv_get","parameters":[{"name":"edition","in":"path","required":true,"schema":{"type":"string","description":"Edition month YYYY-MM, or `latest`","examples":["latest"],"title":"Edition"},"description":"Edition month YYYY-MM, or `latest`"}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/reports/obra-nova/{edition}.json":{"get":{"tags":["public","public"],"summary":"One edition of the monthly new-build report as JSON, with attribution","description":"The same rows as the CSV plus an `attribution` object naming each source and how to cite the edition. `edition` is YYYY-MM or `latest`.","operationId":"report_json_api_v1_reports_obra_nova__edition__json_get","parameters":[{"name":"edition","in":"path","required":true,"schema":{"type":"string","description":"Edition month YYYY-MM, or `latest`","examples":["latest"],"title":"Edition"},"description":"Edition month YYYY-MM, or `latest`"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/where-to-live.csv":{"get":{"tags":["public"],"summary":"Where to live in Portugal: the city guides compared, as CSV","description":"Open data (CC BY 4.0, see the Link header): one row per flatin.pt 'where to live' city guide. IMI urban rate (min and max over the guide's municipalities, Portal das Finanças table for imi_year); INE median sale price per m2 (latest fresh quarter, min and max); new-build supply in the flatin.pt catalogue (developments, units for sale, median asking price per m2 over units with a floor area, only from 5 such units up); counts of areas the guide rates good / depends / avoid and of places named for recent police operations (dated official source, at most 24 months old). An empty cell means we hold no number, not zero.","operationId":"where_cities_csv_api_v1_where_to_live_csv_get","responses":{"200":{"description":"CSV file","content":{"text/csv":{}}}}}},"/api/v1/where-to-live":{"get":{"tags":["places"],"summary":"Where-to-live guides: the list of cities and regions","description":"The cities and regions flatin.pt has a where-to-live guide for, with the municipalities each one covers and the guide's address in the requested language.","operationId":"where_to_live_index_api_v1_where_to_live_get","parameters":[{"name":"language","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en","examples":["en"],"enum":["pt","en","ru","ua","de","fr","nl","uk"],"title":"Language"},"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"The request was not understood: `error` is one of bad_language, bad_profile, bad_verdict, bad_include, bad_measure, bad_granularity, bad_count, municipality_required, ambiguous (with `candidates` or `suggestions`)","content":{"application/json":{"example":{"error":"ambiguous","message":"'Vila' matches several municipalities; pick one","candidates":[{"code":"0313","name":"Vila Verde","distrito":"Braga"}]}}}},"404":{"description":"Nothing matches: `error` is not_found, with `suggestions` (or `guides`) to pick from","content":{"application/json":{"example":{"error":"not_found","message":"municipality 'Atlantis' is not among the 308","suggestions":[]}}}},"503":{"description":"The IMI table is being re-checked: data_unavailable"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/where-to-live/{city}":{"get":{"tags":["places"],"summary":"Where to live in a city: verdict by area, noise and safety","description":"The verdict of a flatin.pt guide by area — live (good to live), depends (depends on you) or avoid (we advise against) — with the reason as written on the site, who each area suits, and the sources of its numbers. Sections: noise in plain words (festivals, bars, aircraft under approach paths), safety as dated, sourced police operations (local reputation of a place, never a claim about its residents), prices, municipal housing, climate, transport. `city` is a guide name in any site language, its slug, or a municipality inside a guide (Gaia → Greater Porto). A profile keeps the areas that suit it plus every 'avoid' area.","operationId":"where_to_live_api_v1_where_to_live__city__get","parameters":[{"name":"city","in":"path","required":true,"schema":{"type":"string","description":"City, region or municipality","examples":["Porto"],"title":"City"},"description":"City, region or municipality"},{"name":"language","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en","examples":["en"],"enum":["pt","en","ru","ua","de","fr","nl","uk"],"title":"Language"},"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en"},{"name":"profile","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Keep areas that suit this profile (and every avoid area)","enum":["family","car_free","retirees","remote","budget","nightlife"],"title":"Profile"},"description":"Keep areas that suit this profile (and every avoid area)"},{"name":"verdict","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Keep only areas with this verdict","enum":["live","depends","avoid"],"title":"Verdict"},"description":"Keep only areas with this verdict"},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated parts of the guide to return. Default: areas,noise,safety. `all` returns every section","examples":["areas,noise,safety,prices"],"title":"Include"},"description":"Comma-separated parts of the guide to return. Default: areas,noise,safety. `all` returns every section"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"The request was not understood: `error` is one of bad_language, bad_profile, bad_verdict, bad_include, bad_measure, bad_granularity, bad_count, municipality_required, ambiguous (with `candidates` or `suggestions`)","content":{"application/json":{"example":{"error":"ambiguous","message":"'Vila' matches several municipalities; pick one","candidates":[{"code":"0313","name":"Vila Verde","distrito":"Braga"}]}}}},"404":{"description":"Nothing matches: `error` is not_found, with `suggestions` (or `guides`) to pick from","content":{"application/json":{"example":{"error":"not_found","message":"municipality 'Atlantis' is not among the 308","suggestions":[]}}}},"503":{"description":"The IMI table is being re-checked: data_unavailable"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/municipalities/compare":{"get":{"tags":["places"],"summary":"Compare 2 to 5 municipalities side by side","description":"The same figures as /municipalities/{municipality}/stats for two to five municipalities in one answer. Pass `municipalities` as a comma-separated list or repeat the parameter.","operationId":"municipalities_compare_api_v1_municipalities_compare_get","parameters":[{"name":"municipalities","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"description":"Names or four-digit codes, 2 to 5","examples":[["Porto","Matosinhos","Vila Nova de Gaia"]],"default":[],"title":"Municipalities"},"description":"Names or four-digit codes, 2 to 5"},{"name":"language","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en","examples":["en"],"enum":["pt","en","ru","ua","de","fr","nl","uk"],"title":"Language"},"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"The request was not understood: `error` is one of bad_language, bad_profile, bad_verdict, bad_include, bad_measure, bad_granularity, bad_count, municipality_required, ambiguous (with `candidates` or `suggestions`)","content":{"application/json":{"example":{"error":"ambiguous","message":"'Vila' matches several municipalities; pick one","candidates":[{"code":"0313","name":"Vila Verde","distrito":"Braga"}]}}}},"404":{"description":"Nothing matches: `error` is not_found, with `suggestions` (or `guides`) to pick from","content":{"application/json":{"example":{"error":"not_found","message":"municipality 'Atlantis' is not among the 308","suggestions":[]}}}},"503":{"description":"The IMI table is being re-checked: data_unavailable"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"x-flatin-example":"/api/v1/municipalities/compare?municipalities=Porto,Matosinhos"}},"/api/v1/municipalities/{municipality}/stats":{"get":{"tags":["places"],"summary":"Everything flatin.pt publishes about one municipality","description":"IMI rate with its history (Autoridade Tributária), INE median sale price per m², purchasing power and population, INE licensed buildings and new dwellings by year, municipal building-works cases by year where we collect them, the construction-barometer row, the number of new-build developments in the catalogue and the where-to-live guides. Every block names its source and its date; a figure that is not published is null, never estimated. `municipality` is a name (any case, accents optional, Lisbon/Oporto accepted) or the four-digit code.","operationId":"municipality_stats_api_v1_municipalities__municipality__stats_get","parameters":[{"name":"municipality","in":"path","required":true,"schema":{"type":"string","description":"Name or four-digit code","examples":["Porto","1312"],"title":"Municipality"},"description":"Name or four-digit code"},{"name":"language","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en","examples":["en"],"enum":["pt","en","ru","ua","de","fr","nl","uk"],"title":"Language"},"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"The request was not understood: `error` is one of bad_language, bad_profile, bad_verdict, bad_include, bad_measure, bad_granularity, bad_count, municipality_required, ambiguous (with `candidates` or `suggestions`)","content":{"application/json":{"example":{"error":"ambiguous","message":"'Vila' matches several municipalities; pick one","candidates":[{"code":"0313","name":"Vila Verde","distrito":"Braga"}]}}}},"404":{"description":"Nothing matches: `error` is not_found, with `suggestions` (or `guides`) to pick from","content":{"application/json":{"example":{"error":"not_found","message":"municipality 'Atlantis' is not among the 308","suggestions":[]}}}},"503":{"description":"The IMI table is being re-checked: data_unavailable"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/construction-barometer":{"get":{"tags":["places"],"summary":"Construction barometer: building-works cases and INE licences","description":"Without `municipality`: the 12-month count of municipal building-works cases for each municipality we collect, the change on the previous 12 months, cases per 1,000 residents, and the fixed-panel index. With `municipality`: our monthly (or yearly) series where we collect it, plus INE's official yearly series of licensed buildings and new dwellings for any of the 308. A case is not a licence granted and not a building. The full series is at /api/v1/barometer/series.","operationId":"construction_barometer_api_v1_construction_barometer_get","parameters":[{"name":"municipality","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Name or four-digit code","examples":["Porto"],"title":"Municipality"},"description":"Name or four-digit code"},{"name":"measure","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Kind of works. Default: total_works","enum":["total_works","new_build","alter_extend"],"title":"Measure"},"description":"Kind of works. Default: total_works"},{"name":"granularity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Period of our own series. Default: month","enum":["month","year"],"title":"Granularity"},"description":"Period of our own series. Default: month"},{"name":"language","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en","examples":["en"],"enum":["pt","en","ru","ua","de","fr","nl","uk"],"title":"Language"},"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"The request was not understood: `error` is one of bad_language, bad_profile, bad_verdict, bad_include, bad_measure, bad_granularity, bad_count, municipality_required, ambiguous (with `candidates` or `suggestions`)","content":{"application/json":{"example":{"error":"ambiguous","message":"'Vila' matches several municipalities; pick one","candidates":[{"code":"0313","name":"Vila Verde","distrito":"Braga"}]}}}},"404":{"description":"Nothing matches: `error` is not_found, with `suggestions` (or `guides`) to pick from","content":{"application/json":{"example":{"error":"not_found","message":"municipality 'Atlantis' is not among the 308","suggestions":[]}}}},"503":{"description":"The IMI table is being re-checked: data_unavailable"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/glossary":{"get":{"tags":["places"],"summary":"Glossary of Portuguese home-buying terms: the list","description":"Every term of the flatin.pt glossary with its Portuguese and English name and its page in the requested language.","operationId":"glossary_index_api_v1_glossary_get","parameters":[{"name":"language","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en","examples":["en"],"enum":["pt","en","ru","ua","de","fr","nl","uk"],"title":"Language"},"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"The request was not understood: `error` is one of bad_language, bad_profile, bad_verdict, bad_include, bad_measure, bad_granularity, bad_count, municipality_required, ambiguous (with `candidates` or `suggestions`)","content":{"application/json":{"example":{"error":"ambiguous","message":"'Vila' matches several municipalities; pick one","candidates":[{"code":"0313","name":"Vila Verde","distrito":"Braga"}]}}}},"404":{"description":"Nothing matches: `error` is not_found, with `suggestions` (or `guides`) to pick from","content":{"application/json":{"example":{"error":"not_found","message":"municipality 'Atlantis' is not among the 308","suggestions":[]}}}},"503":{"description":"The IMI table is being re-checked: data_unavailable"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/glossary/{term}":{"get":{"tags":["places"],"summary":"One glossary term: definition, law reference and page","description":"Definition, where the term comes up when buying, the articles of law with the official text and the date they were checked. `term` is the term's key, its Portuguese or English name, a name in any site language or an abbreviation (IMT, CPCV, VPT); close spellings are found.","operationId":"glossary_term_api_v1_glossary__term__get","parameters":[{"name":"term","in":"path","required":true,"schema":{"type":"string","description":"Term","examples":["cpcv"],"title":"Term"},"description":"Term"},{"name":"language","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en","examples":["en"],"enum":["pt","en","ru","ua","de","fr","nl","uk"],"title":"Language"},"description":"Language of the site content in the answer (verdicts, definitions, labels) and of the page links: pt, en, ru, ua (or uk), de, fr, nl. Field names and the summary stay English. Default: en"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"400":{"description":"The request was not understood: `error` is one of bad_language, bad_profile, bad_verdict, bad_include, bad_measure, bad_granularity, bad_count, municipality_required, ambiguous (with `candidates` or `suggestions`)","content":{"application/json":{"example":{"error":"ambiguous","message":"'Vila' matches several municipalities; pick one","candidates":[{"code":"0313","name":"Vila Verde","distrito":"Braga"}]}}}},"404":{"description":"Nothing matches: `error` is not_found, with `suggestions` (or `guides`) to pick from","content":{"application/json":{"example":{"error":"not_found","message":"municipality 'Atlantis' is not among the 308","suggestions":[]}}}},"503":{"description":"The IMI table is being re-checked: data_unavailable"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/consultation":{"post":{"tags":["actions"],"summary":"Send a request to a licensed real estate agency (two steps)","description":"The same as the MCP tool `request_consultation`, with the same body. `mode`: `link` (default) returns the form link and the consent text; `prepare` checks the details (`name`, `phone` + `channel` or else `email`, `city` or `project`, `language`, optional `budget`, `typology`, `intent`, `message`, `client`) and returns a `summary`, the GDPR consent text in the person's language, its `consent_text_version` and a `confirmation_token` (valid 30 minutes, not before 5 seconds); nothing is sent. `submit` sends the request to a licensed agency: the same details plus `confirmation_token`, `consent: true` and `consent_text_version` — only after the person has read the consent text and explicitly agreed. Changed details, a missing consent or an outdated text version are refused. The answer to `submit` is the same whether the request is new, a repeat or merged into an open one. Refusals: 422 with `error`, `message` and `field` or `problems`; 429 with `Retry-After` (30 prepares and 10 submits an hour per address, 5 accepted requests an hour per address).","operationId":"consultation_api_v1_consultation_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/subscriptions":{"post":{"tags":["actions"],"summary":"Subscribe an email to new developments or construction","description":"The same as the MCP tool `subscribe_digest`, with the same body: `email`, `what` (`new_developments`, daily, the default; or `construction`, newly licensed construction, weekly), `city`, `parish` (construction only), `typology`, `price_min`, `price_max`, `on_sale`, `language`. It only sends a confirmation email (double opt-in): nothing is active until the person clicks the link, within 7 days. The answer is the same for a new address, a subscribed one and a repeat. Refusals: 422 with `error` and `field`; 429 with `Retry-After` (10 an hour per address, shared with the site's forms).","operationId":"subscriptions_api_v1_subscriptions_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}},"tags":[{"name":"public","description":"Keyless public endpoints: IMI rates and IMT calculation."},{"name":"places","description":"Where to live, municipality figures, construction barometer and the glossary — the same answers as the MCP tools."},{"name":"actions","description":"Acting on a person's behalf: a request to a licensed agency (only after the person agrees to the consent text) and an email subscription (double opt-in)."}]}