---
title: "Walkability POIs around a location (local OSM dataset)"
description: "Returns OpenStreetMap points of interest around a coordinate, served from the local `osm_pois` table via a PostGIS radius search instead of a live Overpass API call. Education POIs use a 2 km radius, every other category 1 km. The response uses Overpass element shape so existing clients can map it unchanged. The `osm_pois` table is refreshed monthly by a scheduled ingest.\n\n`lat` and `lng` are rounded to 5 decimals (about 1 m) before the query runs, so equal rounded coordinates always return an identical payload. The response carries `Cache-Control: private, max-age=86400, stale-while-revalidate=604800` (private: the endpoint is token-gated by a header) and a weak `ETag` over the exact JSON sent; `If-None-Match` with a matching tag answers `304`. The ingest records no data vintage, so the monthly reload (which flushes the cached payloads) is what changes the tag. Rate limited per client IP (60 per minute by default) and per RES token (300 per minute by default), counted in Redis across workers; over either limit the endpoint answers 429 with a `Retry-After` header. Box-local calls skip the per-IP limit, and a Redis outage lets requests through."
---

> 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

`GET /score/poi-osm`

Returns OpenStreetMap points of interest around a coordinate, served from the local `osm_pois` table via a PostGIS radius search instead of a live Overpass API call. Education POIs use a 2 km radius, every other category 1 km. The response uses Overpass element shape so existing clients can map it unchanged. The `osm_pois` table is refreshed monthly by a scheduled ingest.

`lat` and `lng` are rounded to 5 decimals (about 1 m) before the query runs, so equal rounded coordinates always return an identical payload. The response carries `Cache-Control: private, max-age=86400, stale-while-revalidate=604800` (private: the endpoint is token-gated by a header) and a weak `ETag` over the exact JSON sent; `If-None-Match` with a matching tag answers `304`. The ingest records no data vintage, so the monthly reload (which flushes the cached payloads) is what changes the tag. Rate limited per client IP (60 per minute by default) and per RES token (300 per minute by default), counted in Redis across workers; over either limit the endpoint answers 429 with a `Retry-After` header. Box-local calls skip the per-IP limit, and a Redis outage lets requests through.

## Authentication

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

## Query parameters

- `lat` (`getPoiOsm.query.lat`; number, required): WGS84 latitude.
- `lng` (`getPoiOsm.query.lng`; number, required): WGS84 longitude.
- `country` (`getPoiOsm.query.country`; string, optional): POI dataset: `ch` (default, table `osm_pois`), `th` (admin-only Thailand experiment, table `osm_pois_th`) `de` (admin-only Germany experiment, table `osm_pois_de`) `at` (admin-only Austria experiment, table `osm_pois_at`), `fr`, `nl`, `be`, `lu`, `gb` or `it` (admin-only France, Netherlands, Belgium, Luxembourg, United Kingdom and Italy experiments, tables `osm_pois_<code>`); every country other than `ch` is refreshed monthly from its Geofabrik extract. Any other value answers 400.
  - one of `"ch"`, `"th"`, `"de"`, `"at"`, `"fr"`, `"nl"`, `"be"`, `"lu"`, `"gb"`, `"it"`; default `"ch"`

## Code samples

### cURL

```bash
curl --request GET \
  --url 'https://res.aireon.ch/score/poi-osm?lat=0&lng=0' \
  --header 'token: <token>'
```

### TypeScript

```typescript
const url = 'https://res.aireon.ch/score/poi-osm?lat=0&lng=0';
const options = {method: 'GET', headers: {token: '<token>'}};

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/poi-osm?lat=0&lng=0"

headers = {"token": "<token>"}

response = requests.get(url, headers=headers)

print(response.text)
```

## Responses

### 200

POIs around the coordinate, in Overpass element shape.

#### Example

```json
{
  "version": 0,
  "generator": "string",
  "elements": [
    {
      "type": "node",
      "id": 0,
      "lat": 0,
      "lon": 0,
      "tags": {
        "property1": "string",
        "property2": "string"
      }
    }
  ]
}
```

- `version` (`getPoiOsm.response.200.version`; number, optional)
- `generator` (`getPoiOsm.response.200.generator`; string, optional)
- `elements` (`getPoiOsm.response.200.elements`; array<object>, optional)
  - `type` (`getPoiOsm.response.200.elements.type`; string, optional)
    - one of `"node"`, `"way"`, `"relation"`
  - `id` (`getPoiOsm.response.200.elements.id`; integer, optional)
  - `lat` (`getPoiOsm.response.200.elements.lat`; number, optional)
  - `lon` (`getPoiOsm.response.200.elements.lon`; number, optional)
  - `tags` (`getPoiOsm.response.200.elements.tags`; map<string>, optional)

### 304

`If-None-Match` matches the current `ETag`. Empty body.

### 400

Invalid request.

#### Example

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

- `error` (`getPoiOsm.response.400.error`; string, required): Human-readable error description.
- `message` (`getPoiOsm.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
```

### 429

Rate limited: too many requests from this client IP or with this token in the current one-minute window. Retry after the number of seconds in `Retry-After`.

#### Example

```json
{
  "error": "rate_limited",
  "scope": "ip",
  "retry_after": 1
}
```

- `error` (`getPoiOsm.response.429.error`; string, required)
  - one of `"rate_limited"`
- `scope` (`getPoiOsm.response.429.scope`; string, required): Which limit was hit.
  - one of `"ip"`, `"token"`
- `retry_after` (`getPoiOsm.response.429.retry_after`; integer, required)
  - min 1

### 500

Server error.

#### Example

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

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


Source: https://docs.aireon.ch/res/get-poi-osm/index.md
