---
title: "Distinct localities, municipalities and locality→municipality aliases for autocomplete"
description: "Three sorted lists aggregated over the whole parcel snapshot, for client-side autocomplete (the `matchoo` app is the only consumer). `locations` is derived from `cityname` (address/GWR join → only parcels WITH a building, so a purely rural municipality never appears); `municipalities` is derived from the never-null `fso_name_2021` and is the list that can reach a vacant plot; `localityAliases` translates a locality string a client may still hold (saved search, shared URL, geocoder result) into the municipality name(s) to filter `fso_name_2021` with `in`.\n\n**Caching.** The aggregate is three full-table scans (~7 s cold, ~12 s for all three), so the shaped payload is stored in Redis under `parcel_locations:v2:<table>` for 30 days (the snapshot table name is part of the key, so a snapshot swap never serves stale data; the monthly refresh should additionally `deleteByPattern('parcel_locations:*')`). A cold rebuild runs under a 90 s statement timeout with a stampede guard: concurrent cold callers share one in-flight query. Every 200 carries `Cache-Control: public, max-age=3600` so the Vercel edge proxies re-cache it.\n\n**No authentication** - same posture as `POST /res_api/parcel_search`."
---

> 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) › Parcel

`GET /res_api/parcel_search/locations`

Three sorted lists aggregated over the whole parcel snapshot, for client-side autocomplete (the `matchoo` app is the only consumer). `locations` is derived from `cityname` (address/GWR join → only parcels WITH a building, so a purely rural municipality never appears); `municipalities` is derived from the never-null `fso_name_2021` and is the list that can reach a vacant plot; `localityAliases` translates a locality string a client may still hold (saved search, shared URL, geocoder result) into the municipality name(s) to filter `fso_name_2021` with `in`.

**Caching.** The aggregate is three full-table scans (~7 s cold, ~12 s for all three), so the shaped payload is stored in Redis under `parcel_locations:v2:<table>` for 30 days (the snapshot table name is part of the key, so a snapshot swap never serves stale data; the monthly refresh should additionally `deleteByPattern('parcel_locations:*')`). A cold rebuild runs under a 90 s statement timeout with a stampede guard: concurrent cold callers share one in-flight query. Every 200 carries `Cache-Control: public, max-age=3600` so the Vercel edge proxies re-cache it.

**No authentication** - same posture as `POST /res_api/parcel_search`.

## Code samples

### cURL

```bash
curl --request GET \
  --url https://res.aireon.ch/res_api/parcel_search/locations
```

### TypeScript

```typescript
const url = 'https://res.aireon.ch/res_api/parcel_search/locations';
const options = {method: 'GET'};

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/res_api/parcel_search/locations"

response = requests.get(url)

print(response.text)
```

## Responses

### 200

The three lists.

#### Example

```json
{
  "generatedAt": "2019-08-24T14:15:22Z",
  "count": 3762,
  "locations": [
    [
      "Aadorf",
      [
        8355
      ],
      2790
    ],
    [
      "Aarau",
      [
        5000,
        5004
      ],
      4120
    ]
  ],
  "municipalities": [
    [
      "Aadorf",
      [
        8355
      ],
      3105
    ]
  ],
  "localityAliases": [
    [
      "Aarau Rohr",
      [
        "Aarau"
      ]
    ],
    [
      "Abländschen",
      [
        "Boltigen",
        "Saanen"
      ]
    ]
  ]
}
```

- `generatedAt` (`getParcelSearchLocations.response.200.generatedAt`; string, required): When the cached payload was computed (up to 30 days ago).
  - format `date-time`
- `count` (`getParcelSearchLocations.response.200.count`; integer, required): `locations.length`.
  - example `3762`
- `locations` (`getParcelSearchLocations.response.200.locations`; array<array<unknown>>, required): One entry per distinct `cityname`, sorted ascending: `[cityname, zips[], parcelCount]`.
  - example `[["Aadorf",[8355],2790],["Aarau",[5000,5004],4120]]`
- `municipalities` (`getParcelSearchLocations.response.200.municipalities`; array<array<unknown>>, required): One entry per distinct `fso_name_2021`, sorted ascending: `[fsoName, zips[], parcelCount]`. `zips` is often empty (a building-less municipality has no address rows).
  - example `[["Aadorf",[8355],3105]]`
- `localityAliases` (`getParcelSearchLocations.response.200.localityAliases`; array<array<unknown>>, required): Only genuine aliases (a `cityname` that is NOT a municipality name), sorted ascending: `[cityname, [fsoName, …]]`.
  - example `[["Aarau Rohr",["Aarau"]],["Abländschen",["Boltigen","Saanen"]]]`

### 500

Aggregate failed (e.g. exceeded the 90 s cold-rebuild timeout) - `{"error":"parcel locations failed"}`.

#### Example

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

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


Source: https://docs.aireon.ch/res/get-parcel-search-locations/index.md
