---
title: "Comparable buildings for the similoo 3D viewer"
description: "Given a target parcel EGRID, returns the parcel's own metrics plus a ranked list of comparable parcels in the same zoning (`cz_local`) with recent construction. The primary candidate pool joins `gwr_new_projects` (the monthly scraper feed) onto `parcel_2025_07` via a 50 m centroid radius; when fewer than 5 comparables match, the endpoint falls back to `parcel_2025_07`'s own `bldg_vol_sb3dgdb` / `cy_max` columns (`meta.fallback_used = 'parcel_table'`). Similarity is computed in normalised z-space over (`parcel_area_m2`, `building_volume_m3`, `ratioV`) and inverted to `1 / (1 + distance)`. Response is cached in Redis for 7 days under `similoo:v4:egrid:<EGRID>:years:<years|all>:limit:<limit>`. The version segment moves with the payload shape: v3 added the same-municipality gate, v4 the unrestricted window, and the window segment renders as `all` rather than `null` so a numeric-window payload can never be served for an unrestricted request."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.aireon.ch/llms.txt
> Use this file to discover all available pages before exploring further.

Path: RES API (public) › Score

`POST /score/similoo`

Given a target parcel EGRID, returns the parcel's own metrics plus a ranked list of comparable parcels in the same zoning (`cz_local`) with recent construction. The primary candidate pool joins `gwr_new_projects` (the monthly scraper feed) onto `parcel_2025_07` via a 50 m centroid radius; when fewer than 5 comparables match, the endpoint falls back to `parcel_2025_07`'s own `bldg_vol_sb3dgdb` / `cy_max` columns (`meta.fallback_used = 'parcel_table'`). Similarity is computed in normalised z-space over (`parcel_area_m2`, `building_volume_m3`, `ratioV`) and inverted to `1 / (1 + distance)`. Response is cached in Redis for 7 days under `similoo:v4:egrid:<EGRID>:years:<years|all>:limit:<limit>`. The version segment moves with the payload shape: v3 added the same-municipality gate, v4 the unrestricted window, and the window segment renders as `all` rather than `null` so a numeric-window payload can never be served for an unrestricted request.

## Authentication

- `ResApiToken`, apiKey, in header, header `token`

## Request body

_Required._

- `egrid` (`postSimiloo.egrid`; string, required): Swiss EGRID (`CH` + 12 alphanumerics).
  - example `"CH641316777430"`
- `years` (`postSimiloo.years`; one of, optional): Construction-year window. Any integer 1-100; the suite precision ladder uses the steps 5 / 10 / 15 / 20 / 40 / 60. Pass the string "all" (case-insensitive) or the number 0 for an unrestricted window with no construction-year floor at all. NOTE 100 is not "all" - Swiss parcels carry construction years well before 1926. A missing or unparseable value falls back to 10, never to unrestricted.
  - default `10`; example `20`
  - one of: `integer`, `string`
- `limit` (`postSimiloo.limit`; integer, optional): Max comparables to return. Default 20.
  - min 1; max 200; default `20`

## Example request

```json
{
  "egrid": "CH641316777430",
  "years": 20,
  "limit": 20
}
```

## Code samples

### cURL

```bash
curl --request POST \
  --url https://res.aireon.ch/score/similoo \
  --header 'Content-Type: application/json' \
  --header 'token: <token>' \
  --data '
{
  "egrid": "CH641316777430",
  "years": 20,
  "limit": 20
}
'
```

### TypeScript

```typescript
const url = 'https://res.aireon.ch/score/similoo';
const options = {
  method: 'POST',
  headers: {'Content-Type': 'application/json', token: '<token>'},
  body: JSON.stringify({egrid: 'CH641316777430', years: 20, limit: 20})
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error(err));
```

### Python

```python
import requests

url = "https://res.aireon.ch/score/similoo"

payload = {
    "egrid": "CH641316777430",
    "years": 20,
    "limit": 20
}
headers = {
    "Content-Type": "application/json",
    "token": "<token>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
```

## Responses

### 200

Target parcel metrics + ranked comparables.

#### Example

```json
{
  "target": {
    "egrid": "string",
    "municipality": "string",
    "cz_local": "string",
    "cz_abbrev": "string",
    "parcel_area_m2": 0,
    "building_volume_m3": 0,
    "height_m": 0,
    "floors": 0,
    "construction_year": 0,
    "ratioV": 0,
    "lat": 0,
    "lng": 0
  },
  "comparables": [
    {
      "egrid": "string",
      "municipality": "string",
      "cz_local": "string",
      "parcel_area_m2": 0,
      "building_volume_m3": 0,
      "footprint_m2": 0,
      "height_m": 0,
      "floors": 0,
      "construction_year": 0,
      "ratioV": 0,
      "similarity_score": 0,
      "lat": 0,
      "lng": 0
    }
  ],
  "meta": {
    "gwr_month": "2026-04",
    "total_candidates": 0,
    "years_window": 0,
    "years_window_all": true,
    "fallback_used": null,
    "generated_at": "2019-08-24T14:15:22Z"
  }
}
```

- `target` (`postSimiloo.response.200.target`; object, optional)
  - `egrid` (`postSimiloo.response.200.target.egrid`; string, optional)
  - `municipality` (`postSimiloo.response.200.target.municipality`; string | null, optional)
  - `cz_local` (`postSimiloo.response.200.target.cz_local`; string | null, optional)
  - `cz_abbrev` (`postSimiloo.response.200.target.cz_abbrev`; string | null, optional)
  - `parcel_area_m2` (`postSimiloo.response.200.target.parcel_area_m2`; number | null, optional)
  - `building_volume_m3` (`postSimiloo.response.200.target.building_volume_m3`; number | null, optional)
  - `height_m` (`postSimiloo.response.200.target.height_m`; number | null, optional)
  - `floors` (`postSimiloo.response.200.target.floors`; integer | null, optional)
  - `construction_year` (`postSimiloo.response.200.target.construction_year`; integer | null, optional)
  - `ratioV` (`postSimiloo.response.200.target.ratioV`; number | null, optional)
  - `lat` (`postSimiloo.response.200.target.lat`; number | null, optional)
  - `lng` (`postSimiloo.response.200.target.lng`; number | null, optional)
- `comparables` (`postSimiloo.response.200.comparables`; array<object>, optional)
  - `egrid` (`postSimiloo.response.200.comparables.egrid`; string, optional)
  - `municipality` (`postSimiloo.response.200.comparables.municipality`; string | null, optional)
  - `cz_local` (`postSimiloo.response.200.comparables.cz_local`; string | null, optional)
  - `parcel_area_m2` (`postSimiloo.response.200.comparables.parcel_area_m2`; number | null, optional)
  - `building_volume_m3` (`postSimiloo.response.200.comparables.building_volume_m3`; number | null, optional)
  - `footprint_m2` (`postSimiloo.response.200.comparables.footprint_m2`; number | null, optional)
  - `height_m` (`postSimiloo.response.200.comparables.height_m`; number | null, optional)
  - `floors` (`postSimiloo.response.200.comparables.floors`; integer | null, optional)
  - `construction_year` (`postSimiloo.response.200.comparables.construction_year`; integer | null, optional)
  - `ratioV` (`postSimiloo.response.200.comparables.ratioV`; number | null, optional)
  - `similarity_score` (`postSimiloo.response.200.comparables.similarity_score`; number, optional)
  - `lat` (`postSimiloo.response.200.comparables.lat`; number | null, optional)
  - `lng` (`postSimiloo.response.200.comparables.lng`; number | null, optional)
- `meta` (`postSimiloo.response.200.meta`; object, optional)
  - `gwr_month` (`postSimiloo.response.200.meta.gwr_month`; string | null, optional)
    - example `"2026-04"`
  - `total_candidates` (`postSimiloo.response.200.meta.total_candidates`; integer, optional)
  - `years_window` (`postSimiloo.response.200.meta.years_window`; integer | null, optional): The applied window in years, or null when unrestricted. Read `years_window_all` rather than treating null as "unknown".
  - `years_window_all` (`postSimiloo.response.200.meta.years_window_all`; boolean, optional): True when the window was unrestricted (years "all" or 0).
  - `fallback_used` (`postSimiloo.response.200.meta.fallback_used`; string | null, optional): `null` when the GWR-based pool was used, `"parcel_table"` when the parcel-table fallback produced the list.
    - one of `null`, `"parcel_table"`
  - `generated_at` (`postSimiloo.response.200.meta.generated_at`; string, optional)
    - format `date-time`

### 400

Invalid request.

#### Example

```json
{
  "error": "string",
  "message": "string"
}
```

- `error` (`postSimiloo.response.400.error`; string, required): Human-readable error description.
- `message` (`postSimiloo.response.400.message`; string, optional): Optional underlying error message.

### 401

Authentication token missing (plain-text body).

#### Example

```text
Missing Token
```

### 403

Authentication token invalid (plain-text body).

#### Example

```text
Wrong Token
```

### 404

No parcel found for the supplied EGRID, or the target parcel has no `cz_local` zoning.

#### Example

```json
{
  "error": "string"
}
```

- `error` (`postSimiloo.response.404.error`; string, optional)

### 500

Server error.

#### Example

```json
{
  "error": "string",
  "message": "string"
}
```

- `error` (`postSimiloo.response.500.error`; string, required): Human-readable error description.
- `message` (`postSimiloo.response.500.message`; string, optional): Optional underlying error message.


Source: https://docs.aireon.ch/res/post-similoo/index.md
