Podstawy
Base URL https://geo.runningcat.dev. Send your key as Authorization: Bearer <key> or x-api-key: <key>; keys come from https://geo.runningcat.dev/account. Coordinates are [lon, lat] in degrees (WGS 84), times ISO 8601 in UTC, distances in km or m as the field name says. Errors answer {"error": "...", "reason": "..."} with the status codes listed per operation.
Every answer says what it cost and what is left: X-Request-Cost, X-RateLimit-Limit and X-RateLimit-Remaining (per minute), X-RateLimit-Day-Limit and X-RateLimit-Day-Remaining.
Credits to show: map data © OpenStreetMap contributors (ODbL); weather and air quality from Open-Meteo.com (CC BY 4.0); terrain from Mapterhorn; air quality stations and river gauges as each answer's credits or the data sources page lists.
Ta sama dokumentacja jako plik OpenAPI 3.1: /openapi.json. Można go wczytać do Postmana, Insomnii lub generatora kodu albo przekazać asystentowi AI.
- Reports:
GET /v1/point,GET /v1/area,POST /v1/route/report - Places and time zones:
GET /v1/where,POST /v1/where,POST /v1/timezones,POST /v1/route/timezones,POST /v1/places/search - Elevation and terrain:
GET /v1/elevation,POST /v1/elevation,POST /v1/route/profile,GET /v1/dem/{z}/{x}/{y}.png - Map layers:
GET /v1/layers/{layer},GET /v1/layers/landcover,POST /v1/route/landcover,POST /v1/route/layers - Weather:
GET /v1/weather,GET /v1/weather/area,POST /v1/weather/current,POST /v1/route/weather - Air quality:
GET /v1/air,GET /v1/air/area,GET /v1/air/stations,POST /v1/route/air/stations,GET /v1/air/stations/{id}/history - Rivers:
GET /v1/rivers,POST /v1/route/rivers,GET /v1/rivers/{id}/history - Routing:
POST /v1/route,POST /v1/route/loop,POST /v1/route/surfaces - Stops along a route:
GET /v1/route-poi/categories,POST /v1/route-poi/corridor,GET /v1/route-poi/tile/{row}/{col} - OpenStreetMap data:
POST /v1/overpass/interpreter,POST /v1/poi/corridor,POST /v1/poi/boxes,POST /v1/roads/along - Service:
GET /v1/status
Reports
Several answers about one point, area or route in one request.
GET /v1/point
Everything about a point. Place, time zone, elevation, weather, air quality, air quality stations and river gauges at a point in one request. include picks the parts (comma-separated: place, timezone, elevation, weather, air, airStations, rivers; all by default). A part that fails comes back in errors with the reason; the others still answer.
Koszt: One request whatever the parts.
Parametry
lon | Longitude, −180 to 180 |
lat | Latitude, −90 to 90 |
include opcjonalnie | Comma-separated parts: place, timezone, elevation, weather, air, airStations, rivers |
lang opcjonalnie | Language of place names, e.g. en, de, pl; local names when absent |
days opcjonalnie | Forecast days, 1 to 14 (default 2) |
hours opcjonalnie | Air quality hours, 1 to 120 (default 24) |
pastHours opcjonalnie | Past hours of the air quality model before the current hour, 0 to 48 (default 0) |
radiusKm opcjonalnie | Search radius for stations and gauges, 1 to 100 km (default 10) |
Zapytanie
curl 'https://geo.runningcat.dev/v1/point?lon=6.1432&lat=46.2044&include=place,timezone,elevation&lang=en' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"lon": 6.1432,
"lat": 46.2044,
"place": {
"lon": 6.1432,
"lat": 46.2044,
"country": {
"code": "CH",
"name": "Switzerland"
},
"region": {
"name": "Geneva",
"code": "CH-GE"
},
"locality": {
"name": "Geneva",
"type": "city",
"distanceKm": 0.39
},
"nearestPlace": {
"name": "Saint-Gervais",
"type": "neighbourhood",
"distanceKm": 0.26
},
"areas": [
{
"level": 2,
"name": "Switzerland",
"code": "CH"
},
{
"level": 4,
"name": "Geneva",
"code": "CH-GE"
},
{
"level": 8,
"name": "Geneva"
}
],
"timezone": {
"tz": "Europe/Zurich",
"offsetMin": 60
}
},
"timezone": {
"tz": "Europe/Zurich",
"offsetMin": 60
},
"elevation": {
"ele": 374
}
}
GET /v1/area
Everything over an area. Weather and air quality grids, elevation, air quality stations, river gauges and map layers over a box. include picks the parts (weather, air, airStations, elevation, rivers, layers; all but layers by default). Grids have about cells cells (at most 400) listed from the north-west corner row by row, hourly from the current hour; cells × hours at most 9600. Stations, gauges and layers need a box of at most 16 square degrees.
Koszt: One request per part; layers one per layer.
Parametry
bbox | west,south,east,north in degrees, at most 3600 square degrees |
include opcjonalnie | Comma-separated parts: weather, air, airStations, elevation, rivers, layers |
cells opcjonalnie | Grid cells, 1 to 400 (default 100) |
hours opcjonalnie | Hours, 1 to 120 (default 24) |
layers opcjonalnie | Comma-separated layers: protected_area, route, piste, aerialway, boundary (default protected_area, route, piste, aerialway) |
Zapytanie
curl 'https://geo.runningcat.dev/v1/area?bbox=6.0,46.1,6.3,46.3&include=weather,elevation&cells=4&hours=2' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"bbox": [
6,
46.1,
6.3,
46.3
],
"rows": 2,
"cols": 2,
"lon": [
6.075,
6.225
],
"lat": [
46.25,
46.15
],
"weather": {
"times": [
"2026-11-12T12:00:00Z",
"2026-11-12T13:00:00Z"
],
"values": {
"temperatureC": [
[
11.6,
12.3,
12.2,
12
],
[
11.8,
12.3,
12.3,
12.2
]
],
"feelsLikeC": [
[
10.4,
11.4,
10.9,
11.5
],
[
10.1,
11,
11.1,
11.6
]
],
"precipitationMm": [
[
0.8,
0.9,
1,
1.1
],
[
0.2,
0.4,
0.4,
0.7
]
],
"weatherCode": [
[
61,
61,
61,
61
],
[
61,
61,
61,
61
]
],
"windKmh": [
[
9.4,
9.2,
11.7,
6.6
],
[
12.8,
12.1,
12,
8.4
]
],
"windDirDeg": [
[
40,
21,
34,
351
],
[
38,
27,
33,
10
]
],
"gustKmh": [
[
16.2,
18.4,
22.3,
16.6
],
[
24.8,
20.9,
24.1,
19.8
]
],
"cloudPct": [
[
100,
100,
100,
100
],
[
100,
100,
100,
100
]
],
"humidityPct": [
[
94,
94,
95,
98
],
[
91,
94,
95,
99
]
],
"pressureHpa": [
[
992.9,
992.9,
992.9,
993.1
],
[
992,
992.1,
992.1,
992.2
]
],
"boundaryLayerM": [
[
205,
185,
210,
145
],
[
230,
180,
185,
120
]
]
}
},
"elevation": {
"values": [
453.2,
435,
424.3,
526.6
]
}
}
POST /v1/route/report
Everything along a route. Elevation profile, weather at the time you reach each point, time zones, air quality stations, river gauges, map layers, surfaces and land cover along a route in one request. include picks the parts (profile, weather, timezones, airStations, rivers, layers, surfaces, landcover; by default profile, weather, timezones, airStations, rivers, layers); the other fields are those of the single endpoints below. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request per part.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
include opcjonalnie | array of profile, weather, timezones, airStations, rivers, layers, surfaces, landcover, at least 1 items |
departure opcjonalnie | string (ISO time with offset) |
speedKmh opcjonalnie | number, 2 to 80 |
stepKm opcjonalnie | number, 0.5 to 100 |
stepM opcjonalnie | number, 10 to 1000 |
layers opcjonalnie | array of protected_area, route, piste, aerialway, boundary, at least 1 items |
bufferM opcjonalnie | number, 0 to 1000 |
bufferKm opcjonalnie | number, 0.1 to 20 |
lang opcjonalnie | string |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/report' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]},"include":["profile","timezones","surfaces","landcover"]}'
Przykładowa odpowiedź
{
"profile": {
"routeLengthKm": 7.567,
"stepM": 10,
"ascentM": 814,
"descentM": 109,
"minM": 374,
"maxM": 1093.7,
"structures": [
{
"fromKm": 0.139,
"toKm": 0.178,
"kind": "tunnel",
"name": "Passage de la Petite-Corraterie",
"maxheight": null,
"maxheightM": null
},
{
"fromKm": 1.05,
"toKm": 1.07,
"kind": "tunnel",
"name": null,
"maxheight": "default",
"maxheightM": null
},
{
"fromKm": 3.89,
"toKm": 3.91,
"kind": "bridge",
"name": null,
"maxheight": null,
"maxheightM": null
}
],
"profile": [
{
"km": 0,
"lon": 6.1432,
"lat": 46.2044,
"ele": 374
},
{
"km": 0.01,
"lon": 6.14324,
"lat": 46.204315,
"ele": 374.4
},
{
"km": 0.02,
"lon": 6.143281,
"lat": 46.204229,
"ele": 374.5
}
]
},
"timezones": {
"at": "2026-11-12T12:35:36.495Z",
"routeLengthKm": 7.6,
"timezones": [
{
"tz": "Europe/Zurich",
"fromKm": 0,
"toKm": 5.6,
"offsetMin": 60
},
{
"tz": "Europe/Paris",
"fromKm": 5.6,
"toKm": 7.6,
"offsetMin": 60
}
]
},
"surfaces": {
"km": {
"paved": 2.76,
"unpaved": 0.32,
"unknown": 4.49
},
"highwayKm": {
"none": 1.95,
"footway": 1.53,
"service": 1.25,
"path": 0.7,
"residential": 0.54,
"tertiary": 0.44,
"track": 0.32,
"cycleway": 0.2,
"living_street": 0.18,
"unclassified": 0.16,
"pedestrian": 0.14,
"secondary": 0.06,
"primary": 0.04,
"motorway": 0.04,
"secondary_link": 0.02,
"platform": 0.02
},
"runs": [
{
"fromKm": 0,
"toKm": 0.02,
"surface": "asphalt",
"highway": "residential",
"tracktype": null,
"smoothness": null
},
{
"fromKm": 0.02,
"toKm": 0.04,
…
Places and time zones
What lies at a point and what time it is there.
GET /v1/where
Where a point is. Country, region, locality, the nearest named place, protected areas and the time zone at a point.
Koszt: One request.
Parametry
lon | Longitude, −180 to 180 |
lat | Latitude, −90 to 90 |
lang opcjonalnie | Language of place names, e.g. en, de, pl; local names when absent |
Zapytanie
curl 'https://geo.runningcat.dev/v1/where?lon=6.1432&lat=46.2044&lang=en' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"lon": 6.1432,
"lat": 46.2044,
"country": {
"code": "CH",
"name": "Switzerland"
},
"region": {
"name": "Geneva",
"code": "CH-GE"
},
"locality": {
"name": "Geneva",
"type": "city",
"distanceKm": 0.39
},
"nearestPlace": {
"name": "Saint-Gervais",
"type": "neighbourhood",
"distanceKm": 0.26
},
"areas": [
{
"level": 2,
"name": "Switzerland",
"code": "CH"
},
{
"level": 4,
"name": "Geneva",
"code": "CH-GE"
},
{
"level": 8,
"name": "Geneva"
}
],
"timezone": {
"tz": "Europe/Zurich",
"offsetMin": 60
}
}
POST /v1/where
Where many points are. The same for up to 1000 points, in order. at (ISO time) sets the moment for the time zone offsets; now by default.
Koszt: One request.
Treść
points | array of [lon, lat], 1 to 1000 items |
lang opcjonalnie | string |
at opcjonalnie | string (ISO time with offset) |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/where' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[[6.1432,46.2044],[19.94,50.06]],"lang":"en"}'
Przykładowa odpowiedź
{
"places": [
{
"lon": 6.1432,
"lat": 46.2044,
"country": {
"code": "CH",
"name": "Switzerland"
},
"region": {
"name": "Geneva",
"code": "CH-GE"
},
"locality": {
"name": "Geneva",
"type": "city",
"distanceKm": 0.39
},
"nearestPlace": {
"name": "Saint-Gervais",
"type": "neighbourhood",
"distanceKm": 0.26
},
"areas": [
{
"level": 2,
"name": "Switzerland",
"code": "CH"
},
{
"level": 4,
"name": "Geneva",
"code": "CH-GE"
},
{
"level": 8,
"name": "Geneva"
}
],
"timezone": {
"tz": "Europe/Zurich",
"offsetMin": 60
}
},
{
"lon": 19.94,
"lat": 50.06,
"country": {
"code": "PL",
"name": "Poland"
},
"region": {
"name": "Lesser Poland Voivodeship",
"code": "PL-12"
},
"locality": {
"name": "Krakow",
"type": "city",
"distanceKm": 0.31
},
"nearestPlace": {
"name": "Krakow",
"type": "city",
"distanceKm": 0.31
},
"areas": [
{
"level": 2,
"name": "Poland",
"code": "PL"
},
{
"level": 4,
"name": "Lesser Poland Voivodeship",
"code": "PL-12"
},
{
"level": 6,
"name": "Krakow"
}
],
"timezone": {
"tz": "Europe/Warsaw",
"offsetMin": 60
}
}
]
}
POST /v1/timezones
Time zones of points. IANA time zone and its offset in minutes east of UTC for up to 10,000 points, at at (now by default).
Koszt: One request.
Treść
points | array of [lon, lat], 1 to 10000 items |
at opcjonalnie | string (ISO time with offset) |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/timezones' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[[6.1432,46.2044],[-73.98,40.75]]}'
Przykładowa odpowiedź
{
"timezones": [
{
"tz": "Europe/Zurich",
"offsetMin": 60
},
{
"tz": "America/New_York",
"offsetMin": -300
}
]
}
POST /v1/route/timezones
Time zones along a route. The stretches of a route in each time zone, with their offsets at at. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
at opcjonalnie | string (ISO time with offset) |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/timezones' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]}}'
Przykładowa odpowiedź
{
"routeLengthKm": 7.6,
"at": "2026-11-12T12:35:38.786Z",
"timezones": [
{
"tz": "Europe/Zurich",
"fromKm": 0,
"toKm": 5.6,
"offsetMin": 60
},
{
"tz": "Europe/Paris",
"fromKm": 5.6,
"toKm": 7.6,
"offsetMin": 60
}
]
}
POST /v1/places/search
Find places by name. Villages, towns, cities and other named places matching a query: exact names first, then names starting with the query, larger and more populous first. Each name comes as "Place, Region, Country", in locale where the place has it. Place names only, no street addresses.
Koszt: One request.
Treść
query | string, 2 to 120 characters |
limit opcjonalnie | integer, 1 to 10 (default 6) |
locale opcjonalnie | string |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/places/search' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"Chamonix","limit":2,"locale":"en"}'
Przykładowa odpowiedź
{
"places": [
{
"name": "Chamonix, Auvergne-Rhône-Alpes, France",
"lat": 46.0295495,
"lon": 6.6117818
},
{
"name": "Chamonix-Mont-Blanc, Auvergne-Rhône-Alpes, France",
"lat": 45.9230969,
"lon": 6.8700009
}
]
}
Elevation and terrain
Heights, profiles and terrain tiles.
GET /v1/elevation
Height of a point. Height above sea level in metres (0.1 m steps); open sea is 0.
Koszt: One request.
Parametry
lon | Longitude, −180 to 180 |
lat | Latitude, −90 to 90 |
Zapytanie
curl 'https://geo.runningcat.dev/v1/elevation?lon=7.6586&lat=45.9763' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"ele": 4449.1
}
POST /v1/elevation
Heights of points. Heights of the ground for up to 10,000 points, in order; null where there is no terrain. Each point is read on its own, so a point in a tunnel gets the mountain above it and one on a bridge the valley below; for a route or a recorded track use POST /v1/route/profile (with at: "points" to keep its own points), which follows the road there.
Koszt: One request.
Treść
points | array of [lon, lat], 1 to 10000 items |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/elevation' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[[7.6586,45.9763],[6.1432,46.2044]]}'
Przykładowa odpowiedź
{
"elevations": [
4449.1,
374
]
}
POST /v1/route/profile
Elevation profile of a route. Heights every stepM metres (10 to 1000; chosen by length when absent), with climb, descent, lowest and highest point. A profile has at most 5,000 samples, so on a long route the step grows past the one asked for (10 m holds up to about 50 km, 20 m up to 100 km); the answer's stepM is the step used. at: "points" gives a height at each point of the route as sent instead, for recorded tracks: no resampling, distances stay the track's, up to 50,000 points (more answers 413), stepM null in the answer. On bridges and in tunnels (OSM bridge and tunnel ways the route runs along) the heights follow the road: a straight line between the heights just beyond each end, not the valley under a bridge or the mountain over a tunnel. A recorded track whose points stray from a tunnel or bridge where GPS was lost still counts as on it within 80 m, as long as no other road is nearer than 25 m. structures lists those stretches (fromKm, toKm, kind bridge or tunnel, name, and the clearance: maxheight as tagged in OSM, maxheightM in metres when it is a number, null when untagged; default means no sign and room for the country's general limit, below_default no sign and less room than that); it is null when they could not be looked up and the heights are the terrain's. heights: "terrain" gives the ground under every point instead. For a recorded track send it here with at: "points" rather than to POST /v1/elevation, which reads each point on its own and so cannot follow a road through a tunnel. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
stepM opcjonalnie | number, 10 to 1000 |
at opcjonalnie | step, points |
heights opcjonalnie | road, terrain |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/profile' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]},"stepM":500}'
Przykładowa odpowiedź
{
"routeLengthKm": 7.567,
"stepM": 500,
"ascentM": 733,
"descentM": 31,
"minM": 375.1,
"maxM": 1090.8,
"structures": [
{
"fromKm": 0.139,
"toKm": 0.178,
"kind": "tunnel",
"name": "Passage de la Petite-Corraterie",
"maxheight": null,
"maxheightM": null
},
{
"fromKm": 1.05,
"toKm": 1.07,
"kind": "tunnel",
"name": null,
"maxheight": "default",
"maxheightM": null
},
{
"fromKm": 3.89,
"toKm": 3.91,
"kind": "bridge",
"name": null,
"maxheight": null,
"maxheightM": null
}
],
"profile": [
{
"km": 0,
"lon": 6.1432,
"lat": 46.2044,
"ele": 375.1
},
{
"km": 0.5,
"lon": 6.145218,
"lat": 46.200126,
"ele": 383.6
},
{
"km": 1,
"lon": 6.147237,
"lat": 46.195852,
"ele": 385.8
}
]
}
GET /v1/dem/{z}/{x}/{y}.png
Terrain tiles (Terrarium). Terrain tiles for hillshading, 3D terrain and contours, in Terrarium encoding: height in metres = R × 256 + G + B / 256 − 32768. {y}.png is 256 px, zoom 0 to 13; {y}.webp is 512 px lossless, zoom 0 to 12. All land is covered; there is no zoom 14, so a contour layer drawn at 14 sets maxzoom 13 on its source. 404 where there is no tile. Credit: terrain from Mapterhorn.
Koszt: One request per 50 tiles.
Parametry
z | Zoom |
x | Tile column |
y | Tile row |
Zapytanie
curl 'https://geo.runningcat.dev/v1/dem/12/2117/1446.png' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź: image/png or image/webp
Map layers
Protected areas, trails, pistes, lifts, boundaries and land cover.
GET /v1/layers/{layer}
A map layer in a box. Protected areas, hiking and cycling routes, ski pistes, lifts or administrative boundaries in a box, as a GeoJSON FeatureCollection with OSM tags; truncated is true when limit cut it. Layers: protected_area, route, piste, aerialway, boundary. kinds narrows a layer (route: hiking, bicycle, mtb, ...; boundary: admin levels such as 2, 4).
Koszt: One request.
Parametry
layer | protected_area, route, piste, aerialway, boundary |
bbox | west,south,east,north in degrees, at most 16 square degrees |
kinds opcjonalnie | Comma-separated kinds within the layer |
limit opcjonalnie | Features, 1 to 5000 (default 2000) |
lang opcjonalnie | Language of place names, e.g. en, de, pl; local names when absent |
Zapytanie
curl 'https://geo.runningcat.dev/v1/layers/protected_area?bbox=6.0,46.1,6.3,46.3&limit=2&lang=en' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"type": "FeatureCollection",
"truncated": true,
"features": [
{
"type": "Feature",
"id": "R5555535",
"properties": {
"layer": "protected_area",
"kind": "protected_area",
"name": "Parc naturel régional du Haut-Jura",
"tags": {
"name": "Parc naturel régional du Haut-Jura",
"name:br": "Park natur rannvroel ar Jura-Uhel",
"name:de": "Regionaler Naturpark Hochjura",
"name:en": "Jura Mountains Regional Natural Park",
"name:fr": "Parc naturel régional du Haut-Jura",
"website": "https://www.parc-haut-jura.fr/",
"boundary": "protected_area",
"wikidata": "Q3364633",
"wikipedia": "fr:Parc naturel régional du Haut-Jura",
"iucn_level": "5",
"protect_class": "5",
"protection_title": "parc naturel régional"
}
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
6.065334,
46.3
],
[
6.064507,
46.298717
],
[
6.063409,
46.297955
]
]
]
}
},
{
"type": "Feature",
"id": "R14980670",
"properties": {
"layer": "protected_area",
"kind": "protected_area",
"name": "Réserve naturelle de la haute chaîne du Jura",
"tags": {
"name": "Réserve naturelle de la haute chaîne du Jura",
"access": "restricted",
"leisure": "nature_reserve",
"name:it": "Riserva naturale dell'Alta Catena del Giura",
"website": "https://www.rnn-hautechainedujura.fr/",
"boundary": "protected_area",
"wikidata": "Q3457394",
"wikipedia": "fr:Réserve naturelle nationale de la haute chaîne du Jura",
"protect_class": "4",
"protection_title": "Réserve naturelle nationale"
}
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
…
GET /v1/layers/landcover
Land cover in a box. What the ground is, from OpenStreetMap areas: forest, scrub, grassland, farmland, wetland, water, glacier, bare, park, built (kind). A GeoJSON FeatureCollection, largest areas first, clipped to the box; the box is at most 0.1 square degrees because forests and fields come by the thousand. kinds keeps some classes.
Koszt: One request.
Parametry
bbox | west,south,east,north, at most 0.1 square degrees |
kinds opcjonalnie | Comma-separated classes: forest, scrub, grassland, farmland, wetland, water, glacier, bare, park, built |
limit opcjonalnie | Features, 1 to 5000 (default 2000) |
Zapytanie
curl 'https://geo.runningcat.dev/v1/layers/landcover?bbox=6.10,46.15,6.30,46.30&limit=2' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"type": "FeatureCollection",
"truncated": true,
"features": [
{
"type": "Feature",
"id": "R332617",
"properties": {
"layer": "landcover",
"kind": "water",
"name": "Le Léman",
"tags": {
"ele": "372",
"boat": "yes",
"name": "Le Léman",
"salt": "no",
"tidal": "no",
"water": "lake",
"name:ca": "Llac Léman",
"name:cs": "Ženevské jezero",
"name:da": "Lemansøen",
"name:de": "Genfersee",
"name:en": "Lake Geneva",
"name:es": "Lago Lemán",
"name:et": "Genfi järv",
"name:fr": "Le Léman",
"name:he": "אגם ז'נבה",
"name:hr": "Ženevsko jezero",
"name:hu": "Genfi-tó",
"name:is": "Genfarvatn",
"name:it": "Lago Lemano",
"name:ja": "レマン湖",
"name:lb": "Genferséia",
"name:nl": "Meer van Genève",
"name:pl": "Jezioro Genewskie",
"name:ru": "Женевское озеро",
"name:sk": "Ženevské jazero",
"name:sl": "Ženevsko jezero",
"name:sr": "Женевско језеро",
"name:tt": "Женева күле",
"name:uk": "Женевське озеро",
"natural": "water",
"alt_name": "Lac Léman;Lac de Genève",
"name:frp": "Lèman",
"swimming": "yes",
"wikidata": "Q6403",
"ref:gwlnr": "CH0097570000",
"wikipedia": "fr:Léman",
"ref:gewiss": "9757",
"short_name": "Léman",
"alt_name:da": "Genevesøen",
"alt_name:de": "Genfer See",
"alt_name:en": "Lake Leman",
"alt_name:es": "Lago de Ginebra",
"alt_name:et": "Leman järv",
"alt_name:fr": "Lac Léman;Lac de Genève",
"alt_name:hr": "Lemansko jezero",
"alt_name:hu": "Leman-tó",
"alt_name:it": "Lago di Ginevra",
"alt_name:lb": "Lemanerséi",
"alt_name:sr": "Леманско језеро",
"intermittent": "no",
"name:sr-Latn": "Ženevsko jeze
…
POST /v1/route/landcover
Land cover along a route. What the ground is along a route, every 50 m (coarser over 250 km): kilometres per class and the stretches of each, in route order. A point takes the class of the smallest area it lies in (a wood inside a park is forest); unmapped where OpenStreetMap maps no area (often roads, villages and fields nobody drew). A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/landcover' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]}}'
Przykładowa odpowiedź
{
"routeLengthKm": 7.57,
"stepM": 50,
"km": {
"built": 3.1,
"park": 1.7,
"forest": 1.07,
"grassland": 0.85,
"unmapped": 0.65,
"farmland": 0.15,
"water": 0.05
},
"runs": [
{
"fromKm": 0,
"toKm": 0.25,
"class": "built"
},
{
"fromKm": 0.25,
"toKm": 0.3,
"class": "park"
},
{
"fromKm": 0.3,
"toKm": 0.35,
"class": "built"
}
]
}
POST /v1/route/layers
Map layers along a route. The layer features a route runs through or within bufferM (0 to 1000, default 30) of, with the stretches of the route inside each. Layers protected_area, route, piste, aerialway by default. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
layers opcjonalnie | array of protected_area, route, piste, aerialway, boundary, at least 1 items |
bufferM opcjonalnie | number, 0 to 1000 |
lang opcjonalnie | string |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/layers' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]}}'
Przykładowa odpowiedź
{
"routeLengthKm": 7.57,
"stepM": 50,
"bufferM": 30,
"features": [
{
"layer": "route",
"id": "R11063902",
"kind": "hiking",
"name": "ViaJacobi",
"tags": {
"to": "Genève (frontière)",
"ref": "4",
"from": "Genève",
"name": "ViaJacobi",
"route": "hiking",
"network": "nwn",
"distance": "9",
"operator": "Wanderland Schweiz",
"osmc:symbol": "green:green::4:white"
},
"stretches": [
{
"fromKm": 0,
"toKm": 0.2
},
{
"fromKm": 0.75,
"toKm": 0.75
}
],
"km": 0.2
},
{
"layer": "route",
"id": "R1307899",
"kind": "bicycle",
"name": "Cyclévasion Genève-Salève",
"tags": {
"to": "Pas-de-l'Échelle",
"ref": "104",
"from": "Genève",
"name": "Cyclévasion Genève-Salève",
"route": "bicycle",
"name:fr": "Cyclévasion Genève-Salève",
"network": "lcn",
"distance": "7",
"operator": "Etat de Genève et Ville de Genève"
},
"stretches": [
{
"fromKm": 0,
"toKm": 0
},
{
"fromKm": 0.5,
"toKm": 0.6
}
],
"km": 0.1
},
{
"layer": "route",
"id": "R1230605",
"kind": "hiking",
"name": "Eaux d'Arve - Pinchat",
"tags": {
"name": "Eaux d'Arve - Pinchat",
"route": "hiking",
"network": "lwn",
"osmc:symbol": "yellow::yellow_diamond"
},
"stretches": [
{
"fromKm": 2.95,
"toKm": 3
}
],
"km": 0.05
}
]
}
Weather
Forecasts for a point, an area and a route on the way.
GET /v1/weather
Forecast for a point. Current conditions, hourly and daily forecast for up to 14 days (default 7), corrected to the height of the point; the local time zone comes along. Hours carry temperature, feels-like, precipitation, weather code, wind, gusts, cloud cover, humidity, sea-level pressure (pressureHpa) and the height of the boundary layer (boundaryLayerM, from the global GFS model everywhere, about 13 km cells). Units: °C, mm, km/h, degrees, percent, hPa, m; times in UTC.
Koszt: One request.
Parametry
lon | Longitude, −180 to 180 |
lat | Latitude, −90 to 90 |
days opcjonalnie | 1 to 14 (default 7) |
Zapytanie
curl 'https://geo.runningcat.dev/v1/weather?lon=6.1432&lat=46.2044&days=2' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"lon": 6.1432,
"lat": 46.2044,
"elevationM": 374,
"current": {
"time": "2026-11-12T12:30:00Z",
"temperatureC": 12.7,
"feelsLikeC": 11.7,
"precipitationMm": 0.1,
"weatherCode": 61,
"windKmh": 9.8,
"windDirDeg": 36,
"gustKmh": 23,
"cloudPct": 100,
"humidityPct": 93,
"pressureHpa": 992.5,
"boundaryLayerM": 205,
"isDay": true
},
"hourly": [
{
"time": "2026-11-11T23:00:00Z",
"temperatureC": 10.1,
"feelsLikeC": 9.7,
"precipitationMm": 0,
"weatherCode": 3,
"windKmh": 2.6,
"windDirDeg": 164,
"gustKmh": 5.4,
"cloudPct": 100,
"humidityPct": 97,
"pressureHpa": 1002.4,
"boundaryLayerM": 10,
"isDay": false
},
{
"time": "2026-11-12T00:00:00Z",
"temperatureC": 9.9,
"feelsLikeC": 9.3,
"precipitationMm": 0,
"weatherCode": 3,
"windKmh": 2.9,
"windDirDeg": 150,
"gustKmh": 4.3,
"cloudPct": 100,
"humidityPct": 97,
"pressureHpa": 1001.7,
"boundaryLayerM": 10,
"isDay": false
},
{
"time": "2026-11-12T01:00:00Z",
"temperatureC": 10.2,
"feelsLikeC": 9.8,
"precipitationMm": 0,
"weatherCode": 3,
"windKmh": 1.6,
"windDirDeg": 117,
"gustKmh": 5.4,
"cloudPct": 100,
"humidityPct": 95,
"pressureHpa": 1000.8,
"boundaryLayerM": 10,
"isDay": false
}
],
"daily": [
{
"date": "2026-11-12",
"minC": 9.9,
"maxC": 12.7,
"precipitationMm": 15.7,
"windMaxKmh": 10.8,
"gustMaxKmh": 23,
"weatherCode": 61,
"sunrise": "2026-11-12T06:32:07Z",
"sunset": "2026-11-12T16:06:42Z"
},
{
"date": "2026-11-13",
"minC": 3.9,
"maxC": 11.5,
"precipitationMm": 1.3,
"windMaxKmh": 25.2,
"gustMaxKmh": 57.2,
"weatherCode": 61,
"sunrise": "2026-11-13T06:33:33Z",
"sunset": "2026-11-13T16:05:32Z"
}
],
"timezone": {
…
GET /v1/weather/area
Forecast grid over an area. Forecast on a grid of about cells cells (at most 400), listed from the north-west corner row by row: values.<name>[step][cell], with times for the steps. hours steps come back, stepHours apart, from pastHours before the current hour. cells × steps at most 9600. Keys given the bulk_grid permission (on request) may ask for up to 20,000 cells and 250,000 values; such grids are built one at a time behind other requests, so they take longer.
Koszt: One request.
Parametry
bbox | west,south,east,north in degrees, at most 3600 square degrees |
cells opcjonalnie | 1 to 400 (default 100) |
stepDeg opcjonalnie | Instead of cells: a lattice with cell centres at west + k·stepDeg and north − k·stepDeg, 0.01 to 10 degrees, so the cells can sit on a model's own nodes (CAMS Europe: every 0.1° at x.x5°, CAMS Global: every 0.4°) |
hours opcjonalnie | How many steps come back, 1 to 120 (default 24) |
stepHours opcjonalnie | Hours between two steps, 1 to 6 (default 1) |
pastHours opcjonalnie | Start this many hours before the current hour, 0 to 48 (default 0); the window may span up to 168 hours |
Zapytanie
curl 'https://geo.runningcat.dev/v1/weather/area?bbox=6.0,46.1,6.3,46.3&cells=4&hours=2' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"bbox": [
6,
46.1,
6.3,
46.3
],
"rows": 2,
"cols": 2,
"lon": [
6.075,
6.225
],
"lat": [
46.25,
46.15
],
"times": [
"2026-11-12T12:00:00Z",
"2026-11-12T15:00:00Z"
],
"values": {
"temperatureC": [
[
11.6,
12.3,
12.2,
12
],
[
11.4,
12.1,
12.1,
11.9
]
],
"feelsLikeC": [
[
10.4,
11.4,
10.9,
11.5
],
[
10.5,
10.9,
11.1,
10.9
]
],
"precipitationMm": [
[
0.8,
0.9,
1,
1.1
],
[
1.2,
1.1,
1.1,
1.4
]
],
"weatherCode": [
[
61,
61,
61,
61
],
[
61,
61,
61,
61
]
],
"windKmh": [
[
9.4,
9.2,
11.7,
6.6
],
[
6.9,
10.8,
9.9,
9.1
]
],
"windDirDeg": [
[
40,
21,
34,
351
],
[
43,
26,
19,
342
]
],
"gustKmh": [
[
16.2,
18.4,
22.3,
16.6
],
[
19.4,
21.2,
19.1,
19.8
]
],
"cloudPct": [
[
100,
100,
100,
100
],
[
100,
100,
100,
100
]
],
"humidityPct": [
[
94,
94,
95,
98
],
[
93,
94,
96,
96
]
],
"pressureHpa": [
[
992.9,
992.9,
992.9,
993.1
],
[
991.7,
991.5,
991.7,
991.7
]
],
"boundaryLayerM": [
[
205,
185,
210,
145
],
[
200,
120,
130,
100
]
]
}
}
POST /v1/weather/current
Current weather at many points. Current conditions at up to 2,000 points in one request, in order (for example a wind field for a map): the same fields as current in /v1/weather, the boundary layer height included. Over 400 points the request waits its turn behind other large requests.
Koszt: One request.
Treść
points | array of [lon, lat], 1 to 2000 items |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/weather/current' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[[6.1432,46.2044],[19.94,50.06]]}'
Przykładowa odpowiedź
{
"points": [
{
"lon": 6.1432,
"lat": 46.2044,
"current": {
"time": "2026-11-12T12:30:00Z",
"temperatureC": 12.7,
"feelsLikeC": 11.7,
"precipitationMm": 0.1,
"weatherCode": 61,
"windKmh": 9.8,
"windDirDeg": 36,
"gustKmh": 23,
"cloudPct": 100,
"humidityPct": 93,
"pressureHpa": 992.5,
"boundaryLayerM": 205,
"isDay": true
}
},
{
"lon": 19.94,
"lat": 50.06,
"current": {
"time": "2026-11-12T12:30:00Z",
"temperatureC": 8,
"feelsLikeC": 7,
"precipitationMm": 0,
"weatherCode": 2,
"windKmh": 1.1,
"windDirDeg": 162,
"gustKmh": 4.7,
"cloudPct": 80,
"humidityPct": 89,
"pressureHpa": 997.8,
"boundaryLayerM": 585,
"isDay": true
}
}
]
}
POST /v1/route/weather
Weather along a route on the way. The forecast at points along the route for the time you reach each of them, leaving at departure (now by default) at speedKmh (default 20), every stepKm; a summary gives the coldest and warmest, the wettest hour, the strongest headwind and gust. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
departure opcjonalnie | string (ISO time with offset) |
speedKmh opcjonalnie | number, 2 to 80 |
stepKm opcjonalnie | number, 0.5 to 100 |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/weather' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]},"speedKmh":18}'
Przykładowa odpowiedź
{
"routeLengthKm": 7.6,
"departure": "2026-11-12T12:35:43.550Z",
"arrival": "2026-11-12T13:00:57.025Z",
"speedKmh": 18,
"summary": {
"minTemperatureC": 8.4,
"maxTemperatureC": 12.7,
"maxPrecipitationMm": 0.7,
"maxHeadwindKmh": -3.1,
"maxGustKmh": 27
},
"points": [
{
"km": 0,
"lon": 6.1432,
"lat": 46.2044,
"time": "2026-11-12T12:35:43.550Z",
"temperatureC": 12.7,
"feelsLikeC": 11.7,
"precipitationMm": 0.4,
"weatherCode": 61,
"windKmh": 9.9,
"windDirDeg": 37,
"gustKmh": 21.1,
"cloudPct": 100,
"humidityPct": 92,
"pressureHpa": 992.1,
"boundaryLayerM": 230,
"isDay": true,
"headwindKmh": -3.3,
"crosswindKmh": 9.3
},
{
"km": 5,
"lon": 6.17818,
"lat": 46.16746,
"time": "2026-11-12T12:52:23.550Z",
"temperatureC": 12.2,
"feelsLikeC": 11.4,
"precipitationMm": 0.5,
"weatherCode": 61,
"windKmh": 8.8,
"windDirDeg": 31,
"gustKmh": 19.2,
"cloudPct": 100,
"humidityPct": 95,
"pressureHpa": 992.2,
"boundaryLayerM": 180,
"isDay": true,
"headwindKmh": -3.5,
"crosswindKmh": 8.1
},
{
"km": 7.6,
"lon": 6.2,
"lat": 46.15,
"time": "2026-11-12T13:00:57.025Z",
"temperatureC": 8.4,
"feelsLikeC": 6.3,
"precipitationMm": 0.7,
"weatherCode": 61,
"windKmh": 11.2,
"windDirDeg": 33,
"gustKmh": 27,
"cloudPct": 100,
"humidityPct": 100,
"pressureHpa": 992.3,
"boundaryLayerM": 120,
"isDay": true,
"headwindKmh": -3.1,
"crosswindKmh": 10.8
}
]
}
Air quality
Forecasts and what stations measure now.
GET /v1/air
Air quality forecast for a point. Current and hourly PM2.5, PM10, nitrogen dioxide, ozone, sulphur dioxide, carbon monoxide, dust, UV index, European and US AQI; in Europe also ammonia and pollen (alder, birch, grass, mugwort, olive, ragweed). µg/m³; pollen in grains/m³.
Koszt: One request.
Parametry
lon | Longitude, −180 to 180 |
lat | Latitude, −90 to 90 |
hours opcjonalnie | Hours from the current one, 1 to 120 (default 48) |
pastHours opcjonalnie | Past hours of the model before the current hour, 0 to 48 (default 0): what the forecast said for the last hours, to set against what stations measured |
Zapytanie
curl 'https://geo.runningcat.dev/v1/air?lon=6.1432&lat=46.2044&hours=2' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"lon": 6.1432,
"lat": 46.2044,
"current": {
"time": "2026-11-12T12:00:00Z",
"pm25": 3,
"pm10": 4.5,
"nitrogenDioxide": 9.5,
"ozone": 45,
"sulphurDioxide": 0.3,
"carbonMonoxide": 143,
"ammonia": 1.2,
"dust": 0,
"uvIndex": 0.5,
"europeanAqi": 19,
"usAqi": 38,
"alderPollen": 0,
"birchPollen": 0,
"grassPollen": 0,
"mugwortPollen": 0,
"olivePollen": 0,
"ragweedPollen": 0
},
"hourly": [
{
"time": "2026-11-12T12:00:00Z",
"pm25": 3,
"pm10": 4.5,
"nitrogenDioxide": 9.5,
"ozone": 45,
"sulphurDioxide": 0.3,
"carbonMonoxide": 143,
"ammonia": 1.2,
"dust": 0,
"uvIndex": 0.5,
"europeanAqi": 19,
"usAqi": 38,
"alderPollen": 0,
"birchPollen": 0,
"grassPollen": 0,
"mugwortPollen": 0,
"olivePollen": 0,
"ragweedPollen": 0
},
{
"time": "2026-11-12T13:00:00Z",
"pm25": 2.7,
"pm10": 4.3,
"nitrogenDioxide": 9.2,
"ozone": 48,
"sulphurDioxide": 0.3,
"carbonMonoxide": 140,
"ammonia": 1.2,
"dust": 0,
"uvIndex": 0.3,
"europeanAqi": 18,
"usAqi": 38,
"alderPollen": 0,
"birchPollen": 0,
"grassPollen": 0,
"mugwortPollen": 0,
"olivePollen": 0,
"ragweedPollen": 0
}
]
}
GET /v1/air/area
Air quality grid over an area. The air quality values of /v1/air on a grid, shaped like the weather grid, with the same hours, stepHours and pastHours. Keys given the bulk_grid permission (on request) may ask for up to 20,000 cells and 250,000 values; such grids are built one at a time behind other requests, so they take longer.
Koszt: One request.
Parametry
bbox | west,south,east,north in degrees, at most 3600 square degrees |
cells opcjonalnie | 1 to 400 (default 100) |
stepDeg opcjonalnie | Instead of cells: a lattice with cell centres at west + k·stepDeg and north − k·stepDeg, 0.01 to 10 degrees, so the cells can sit on a model's own nodes (CAMS Europe: every 0.1° at x.x5°, CAMS Global: every 0.4°) |
hours opcjonalnie | How many steps come back, 1 to 120 (default 24) |
stepHours opcjonalnie | Hours between two steps, 1 to 6 (default 1) |
pastHours opcjonalnie | Start this many hours before the current hour, 0 to 48 (default 0); the window may span up to 168 hours |
Zapytanie
curl 'https://geo.runningcat.dev/v1/air/area?bbox=6.0,46.1,6.3,46.3&cells=4&hours=2' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"bbox": [
6,
46.1,
6.3,
46.3
],
"rows": 2,
"cols": 2,
"lon": [
6.075,
6.225
],
"lat": [
46.25,
46.15
],
"times": [
"2026-11-12T12:00:00Z",
"2026-11-12T13:00:00Z"
],
"values": {
"pm25": [
[
3,
3.5,
3.6,
4.3
],
[
2.5,
3.2,
3.1,
4.4
]
],
"pm10": [
[
3.7,
4.9,
4.7,
5.6
],
[
3.5,
4.9,
4.5,
5.2
]
],
"nitrogenDioxide": [
[
6.5,
10.5,
10.9,
14.1
],
[
6.2,
9.1,
9.7,
13.8
]
],
"ozone": [
[
54,
43,
45,
35
],
[
55,
44,
48,
38
]
],
"sulphurDioxide": [
[
0.3,
0.3,
0.3,
0.3
],
[
0.2,
0.3,
0.3,
0.3
]
],
"carbonMonoxide": [
[
136,
154,
153,
165
],
[
130,
147,
149,
165
]
],
"ammonia": [
[
0.9,
1.1,
1.2,
1
],
[
0.9,
1.2,
1.3,
1.1
]
],
"dust": [
[
0,
0,
0,
0
],
[
0,
0,
0,
0
]
],
"uvIndex": [
[
0.5,
0.5,
0.4,
0.4
],
[
0.3,
0.4,
0.3,
0.3
]
],
"europeanAqi": [
[
18,
21,
21,
25
],
[
18,
18,
19,
25
]
],
"usAqi": [
[
30,
42,
38,
39
],
[
29,
42,
38,
39
]
],
"alderPollen": [
[
0,
0,
0,
0
],
[
0,
0,
0,
0
]
],
"birchPollen": [
[
0,
0,
0,
0
],
[
0,
0,
0,
0
]
],
"grassPollen": [
[
0,
0,
0,
0
],
[
0,
0,
0,
0
]
],
"mugwortPollen": [
[
0,
0,
0,
0
],
[
0,
0,
0,
0
]
]
…
GET /v1/air/stations
Measured air quality at stations. The latest value per pollutant (last 3 hours; 6 for EEA stations) at official stations (kind=government) and volunteer sensors (kind=citizen), nearest first: around a point (lon, lat, radiusKm 1 to 100, default 25) or in a box (bbox, nearest its centre first). µg/m³; credits names the sources to show.
Koszt: One request.
Parametry
lon opcjonalnie | Longitude, −180 to 180 |
lat opcjonalnie | Latitude, −90 to 90 |
radiusKm opcjonalnie | 1 to 100 (default 25) |
bbox opcjonalnie | west,south,east,north in degrees, at most 16 square degrees |
limit opcjonalnie | Around a point 1 to 100 (default 10); in a box 1 to 1000 (default 200) |
kind opcjonalnie | government or citizen; both when absent |
Zapytanie
curl 'https://geo.runningcat.dev/v1/air/stations?lon=19.94&lat=50.06&bbox=6.0,46.1,6.3,46.3&limit=2' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"stations": [
{
"id": "syngeos:10043",
"name": "Kraków, Warszawska 24",
"kind": "citizen",
"lon": 19.94143,
"lat": 50.07168,
"distanceKm": 1.3,
"time": "2026-11-12T10:37:38.000Z",
"values": {
"pm10": 19,
"pm25": 23
}
},
{
"id": "syngeos:10082",
"name": "Kraków, Warszawska 24",
"kind": "citizen",
"lon": 19.94367,
"lat": 50.07152,
"distanceKm": 1.31,
"time": "2026-11-12T11:05:27.000Z",
"values": {
"o3": 38,
"pm10": 11,
"pm25": 11
}
}
],
"credits": [
"Syngeos sensor network (https://syngeos.pl)"
]
}
POST /v1/route/air/stations
Air quality stations along a route. Stations within bufferKm (0.1 to 20) of the route, in route order with alongKm; up to limit (at most 500). A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
bufferKm opcjonalnie | number, 0.1 to 20 |
limit opcjonalnie | integer, 1 to 500 |
kind opcjonalnie | government, citizen |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/air/stations' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[19.9,50.07],[19.98,50.05]]},"limit":2}'
Przykładowa odpowiedź
{
"stations": [
{
"id": "gios:400",
"name": "Kraków, Aleja Krasińskiego",
"kind": "government",
"lon": 19.92619,
"lat": 50.05768,
"distanceKm": 0.6,
"alongKm": 2.25,
"time": "2026-11-12T12:00:00.000Z",
"values": {
"co": 544,
"no2": 38.2,
"pm10": 37.7,
"pm25": 19.8
}
},
{
"id": "syngeos:10043",
"name": "Kraków, Warszawska 24",
"kind": "citizen",
"lon": 19.94143,
"lat": 50.07168,
"distanceKm": 1.25,
"alongKm": 2.75,
"time": "2026-11-12T10:37:38.000Z",
"values": {
"pm10": 19,
"pm25": 23
}
}
],
"credits": [
"Źródło danych: GIOŚ - EKOINFONET; current data are unverified and may change, CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)",
"Syngeos sensor network (https://syngeos.pl)"
]
}
GET /v1/air/stations/{id}/history
Readings of one station. Hourly readings per pollutant for the last days (1 to 7, default 7). The id comes from the station lists.
Koszt: One request.
Parametry
id | source:station, e.g. gios:400 |
days opcjonalnie | 1 to 7 (default 7) |
Zapytanie
curl 'https://geo.runningcat.dev/v1/air/stations/gios:400/history?days=1' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"id": "syngeos:10043",
"readings": {
"pm10": [
{
"time": "2026-11-11T14:00:00.000Z",
"value": 15
},
{
"time": "2026-11-11T15:00:00.000Z",
"value": 17
},
{
"time": "2026-11-11T16:00:00.000Z",
"value": 17
}
],
"pm25": [
{
"time": "2026-11-11T13:00:00.000Z",
"value": 11
},
{
"time": "2026-11-11T14:00:00.000Z",
"value": 11
},
{
"time": "2026-11-11T15:00:00.000Z",
"value": 12
}
]
},
"credits": [
"Syngeos sensor network (https://syngeos.pl)"
]
}
Rivers
Water levels and discharge at river gauges.
GET /v1/rivers
River gauges. The latest water level (cm above the gauge zero), discharge (m³/s), change over a day and the warning state at gauges, nearest first: around a point (lon, lat, radiusKm 1 to 100, default 25) or in a box (bbox).
Koszt: One request.
Parametry
lon opcjonalnie | Longitude, −180 to 180 |
lat opcjonalnie | Latitude, −90 to 90 |
radiusKm opcjonalnie | 1 to 100 (default 25) |
bbox opcjonalnie | west,south,east,north in degrees, at most 16 square degrees |
limit opcjonalnie | Around a point 1 to 100 (default 10); in a box 1 to 1000 (default 200) |
Zapytanie
curl 'https://geo.runningcat.dev/v1/rivers?lon=6.1432&lat=46.2044&bbox=6.0,46.1,6.3,46.3&limit=2' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"gauges": [
{
"id": "hubeau:V035501202",
"name": "[Le Rhône] en Suisse - Halle de l'Ile - Barrage du Seujet (OFEV)",
"river": null,
"lon": 6.1416,
"lat": 46.20457,
"distanceKm": 0.13,
"time": "2026-11-12T12:00:00.000Z",
"levelCm": null,
"change24hCm": null,
"dischargeM3s": 107,
"warningCm": null,
"alarmCm": null,
"state": null
},
{
"id": "bafu:2606",
"name": "Genève, Halle de l'Île",
"river": "Rhône",
"lon": 6.14154,
"lat": 46.20466,
"distanceKm": 0.13,
"time": "2026-11-12T12:20:00.000Z",
"levelCm": null,
"change24hCm": null,
"dischargeM3s": 110.375,
"warningCm": null,
"alarmCm": null,
"state": null
}
]
}
POST /v1/route/rivers
River gauges along a route. Gauges within bufferKm (0.1 to 20, default 2) of the route, nearest first. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
bufferKm opcjonalnie | number, 0.1 to 20 |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/rivers' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]}}'
Przykładowa odpowiedź
{
"gauges": [
{
"id": "bafu:2606",
"name": "Genève, Halle de l'Île",
"river": "Rhône",
"lon": 6.14154,
"lat": 46.20466,
"distanceKm": 0.13,
"time": "2026-11-12T12:20:00.000Z",
"levelCm": null,
"change24hCm": null,
"dischargeM3s": 110.375,
"warningCm": null,
"alarmCm": null,
"state": null
},
{
"id": "hubeau:V035501202",
"name": "[Le Rhône] en Suisse - Halle de l'Ile - Barrage du Seujet (OFEV)",
"river": null,
"lon": 6.1416,
"lat": 46.20457,
"distanceKm": 0.13,
"time": "2026-11-12T12:00:00.000Z",
"levelCm": null,
"change24hCm": null,
"dischargeM3s": 107,
"warningCm": null,
"alarmCm": null,
"state": null
},
{
"id": "bafu:2170",
"name": "Genève, Bout du Monde",
"river": "Arve",
"lon": 6.15935,
"lat": 46.1803,
"distanceKm": 0.16,
"time": "2026-11-12T12:20:00.000Z",
"levelCm": 37949.2,
"change24hCm": 15.3,
"dischargeM3s": 64.84,
"warningCm": null,
"alarmCm": null,
"state": null
}
]
}
GET /v1/rivers/{id}/history
Readings of one gauge. Readings for the last days (1 to 30, default 7). The id comes from the gauge lists.
Koszt: One request.
Parametry
id | source:station, e.g. hubeau:V035501202 |
days opcjonalnie | 1 to 30 (default 7) |
Zapytanie
curl 'https://geo.runningcat.dev/v1/rivers/hubeau:V035501202/history?days=1' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"id": "hubeau:V035501202",
"readings": [
{
"time": "2026-11-11T12:40:00.000Z",
"levelCm": null,
"dischargeM3s": 83.7
},
{
"time": "2026-11-11T13:00:00.000Z",
"levelCm": null,
"dischargeM3s": 92.2
},
{
"time": "2026-11-11T13:10:00.000Z",
"levelCm": null,
"dischargeM3s": 87.9
}
]
}
Routing
Routes, loops and the surfaces of a route.
POST /v1/route
A route through points. A route through 2 to 50 points on OpenStreetMap data. Profiles: bike, city, road-bike, quiet-road-bike, gravel, mtb, hiking, car, shortest (default bike; city keeps to cycleways and off busy roads). alternative 1 to 3 gives other routes. The answer is a LineString with a height at every point, its length, climb and riding time, and surfaces: kilometres paved, unpaved and unknown, kilometres per highway value, and the stretches of each way kind with its OSM surface, highway, tracktype (grade1 solid to grade5 soft) and smoothness (null where the way has no such tag), so a stretch without a surface tag can still be judged by the kind of way. format: "gpx" answers a GPX file instead. 404 no_route when a point cannot be reached with the profile; 504 timeout after two minutes (add waypoints or split the trip).
Koszt: One request and one route per started 100 km of the route found (50 km for mtb).
Treść
points | array of [lon, lat], 2 to 50 items |
profile opcjonalnie | bike, city, road-bike, quiet-road-bike, gravel, mtb, hiking, car, shortest |
alternative opcjonalnie | integer, 0 to 3 |
format opcjonalnie | geojson, gpx |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[[6.1432,46.2044],[6.2,46.15]],"profile":"bike"}'
Przykładowa odpowiedź
{
"profile": "bike",
"lengthKm": 18.82,
"ascentM": 735,
"durationS": 8696,
"geometry": {
"type": "LineString",
"coordinates": [
[
6.143198,
46.204407,
374
],
[
6.143206,
46.204408,
374
],
[
6.143399,
46.204372,
374
]
]
},
"surfaces": {
"km": {
"paved": 18,
"unpaved": 0.04,
"unknown": 0.79
},
"highwayKm": {
"tertiary": 6.34,
"cycleway": 5.23,
"secondary": 3.46,
"residential": 2.25,
"unclassified": 0.68,
"primary": 0.47,
"track": 0.2,
"pedestrian": 0.07,
"footway": 0.07,
"primary_link": 0.06
},
"runs": [
{
"fromKm": 0,
"toKm": 0.235,
"surface": "asphalt",
"highway": "residential",
"tracktype": null,
"smoothness": null
},
{
"fromKm": 0.235,
"toKm": 0.308,
"surface": "asphalt",
"highway": "pedestrian",
"tracktype": null,
"smoothness": null
},
{
"fromKm": 0.308,
"toKm": 0.584,
"surface": "asphalt",
"highway": "unclassified",
"tracktype": null,
"smoothness": null
}
]
}
}
POST /v1/route/loop
A round trip from a point. A loop of about distanceKm (5 to 200) back to start, setting off towards direction (degrees, 0 = north, default 0); another direction gives another loop. The length usually lands within 10 % of the asked one. If no loop can be made that way (a glacier, the sea), the other directions are tried. The answer has the shape of /v1/route.
Koszt: One request and one route per started 100 km of the route found (50 km for mtb).
Treść
start | [lon, lat] |
distanceKm | number, 5 to 200 |
profile opcjonalnie | bike, city, road-bike, quiet-road-bike, gravel, mtb, hiking, car, shortest |
direction opcjonalnie | number, 0 to 360 |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/loop' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"start":[6.1432,46.2044],"distanceKm":25,"profile":"bike","direction":90}'
Przykładowa odpowiedź
{
"profile": "bike",
"lengthKm": 25.807,
"ascentM": 141,
"durationS": 4932,
"geometry": {
"type": "LineString",
"coordinates": [
[
6.143198,
46.204407,
374
],
[
6.143206,
46.204408,
374
],
[
6.143201,
46.204436,
374
]
]
},
"surfaces": {
"km": {
"paved": 16.01,
"unpaved": 0.05,
"unknown": 9.75
},
"highwayKm": {
"none": 7.07,
"secondary": 6.25,
"residential": 4.64,
"tertiary": 2.58,
"cycleway": 2.51,
"living_street": 0.96,
"unclassified": 0.89,
"footway": 0.26,
"service": 0.21,
"primary": 0.21,
"path": 0.13,
"pedestrian": 0.08
},
"runs": [
{
"fromKm": 0,
"toKm": 0.01,
"surface": "asphalt",
"highway": "residential",
"tracktype": null,
"smoothness": null
},
{
"fromKm": 0.01,
"toKm": 0.044,
"surface": "asphalt",
"highway": "residential",
"tracktype": null,
"smoothness": "excellent"
},
{
"fromKm": 0.044,
"toKm": 0.104,
"surface": "asphalt",
"highway": "residential",
"tracktype": null,
"smoothness": null
}
]
}
}
POST /v1/route/surfaces
Surfaces of any track. The OSM surface along a track you already have (an imported GPX, a drawn line): every 20 m the track takes the nearest road or path within 25 m. The answer has the shape of surfaces in /v1/route: kilometres paved, unpaved and unknown, kilometres per highway, and stretches with surface, highway, tracktype and smoothness. The track is not re-routed. unknown surface: the way has no surface tag (its highway, tracktype and smoothness still come along), or no way lies within 25 m (then all three are null). heightLimits lists the stretches on ways with a height limit, tunnels and passages under bridges included, so you can tell whether a car with bikes on the roof fits: maxheight as tagged in OSM (the lower of maxheight and maxheight:physical), maxheightM in metres (feet converted), or below_default, meaning no sign but less room than the country's general limit (maxheightM null); name of the way. Only what is tagged on the ways: a height barrier mapped as a point on the road is not in the list, and a way with no tag may still be low. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route/surfaces' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]}}'
Przykładowa odpowiedź
{
"km": {
"paved": 2.76,
"unpaved": 0.32,
"unknown": 4.49
},
"highwayKm": {
"none": 1.95,
"footway": 1.53,
"service": 1.25,
"path": 0.7,
"residential": 0.54,
"tertiary": 0.44,
"track": 0.32,
"cycleway": 0.2,
"living_street": 0.18,
"unclassified": 0.16,
"pedestrian": 0.14,
"secondary": 0.06,
"primary": 0.04,
"motorway": 0.04,
"secondary_link": 0.02,
"platform": 0.02
},
"runs": [
{
"fromKm": 0,
"toKm": 0.02,
"surface": "asphalt",
"highway": "residential",
"tracktype": null,
"smoothness": null
},
{
"fromKm": 0.02,
"toKm": 0.04,
"surface": "unknown",
"highway": "cycleway",
"tracktype": null,
"smoothness": null
},
{
"fromKm": 0.04,
"toKm": 0.059,
"surface": "asphalt",
"highway": "pedestrian",
"tracktype": null,
"smoothness": "good"
}
],
"heightLimits": []
}
Stops along a route
Water, food, shops and more along a route.
GET /v1/route-poi/categories
Stop categories. The categories and subtypes /v1/route-poi/corridor answers with: the OSM tags behind each, the default distance from the route, whether it is in the default search, and GPX and FIT waypoint symbols. version (also the ETag) changes when the catalog does.
Koszt: One request.
Zapytanie
curl 'https://geo.runningcat.dev/v1/route-poi/categories' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"version": "a266ea079477",
"defaultCategories": [
"grocery",
"fuel",
"food"
],
"maxDistanceM": 5000,
"maxCorridorKm2": 2000,
"fallbackExport": {
"gpx": "Waypoint",
"fit": "generic"
},
"categories": [
{
"id": "grocery",
"inDefaultSearch": true,
"defaultDistanceM": 200,
"sources": [
"db",
"tiles"
],
"export": {
"gpx": "Shopping Center",
"fit": "store"
},
"subtypes": [
{
"id": "supermarket",
"osm": [
{
"shop": [
"supermarket"
]
}
],
"export": {
"gpx": "Shopping Center",
"fit": "store"
}
},
{
"id": "convenience",
"osm": [
{
"shop": [
"convenience"
]
}
],
"export": {
"gpx": "Convenience Store",
"fit": "store"
}
},
{
"id": "bakery",
"osm": [
{
"shop": [
"bakery"
]
}
],
"export": {
"gpx": "Convenience Store",
"fit": "food"
}
}
]
},
{
"id": "fuel",
"inDefaultSearch": true,
"defaultDistanceM": 200,
"sources": [
"db",
"tiles"
],
"export": {
"gpx": "Gas Station",
"fit": "store"
},
"subtypes": [
{
"id": "fuel",
"osm": [
{
"amenity": [
"fuel"
]
}
],
"export": {
"gpx": "Gas Station",
"fit": "store"
}
}
]
},
{
"id": "food",
"inDefaultSearch": true,
"defaultDistanceM": 200,
"sources": [
"db",
"tiles"
],
"export": {
"gpx": "Restaurant",
"fit": "food"
},
"subtypes": [
{
"id": "cafe",
"osm": [
{
"amenity": [
"cafe"
]
}
],
"export": {
"gpx": "Restaurant",
"f
…
POST /v1/route-poi/corridor
Stops along a route. Water, food, groceries, toilets, bike shops and fuel (and on request places to sleep, sights, charging, benches, picnic spots) along a route, each with its kilometre along the route and its distance from it, plus the stretches of more than 40 km without water and food (gaps). The route comes as points of {lat, lon, d} (d: metres from the start), or as sections of them for separate pieces; up to 1,000 points. Distances: each category's default, maxDistanceM for all, or distancesM per category, up to 5,000 m; route length × the widest distance at most 2,000 km·km (1,000 km at 2 km, 400 km at 5 km), else 413. Chain stores carry their brand logo and icon URLs.
Koszt: One request.
Treść
points opcjonalnie | array of object, 2 to 1000 items |
sections opcjonalnie | array of array of object, 2 to 1000 items, 1 to 64 items |
categories opcjonalnie | array of grocery, fuel, food, water, toilets, bike, sleep, sights, charging, bench, picnic, at most 11 items |
maxDistanceM opcjonalnie | integer, 1 to 5000 |
distancesM opcjonalnie | object |
includeSprings opcjonalnie | boolean |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/route-poi/corridor' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[{"lat":46.2044,"lon":6.1432,"d":0},{"lat":46.19,"lon":6.15,"d":1666}],"categories":["water","food"]}'
Przykładowa odpowiedź
{
"pois": [
{
"id": "node/12456128201",
"category": "food",
"subtype": "restaurant",
"name": "Little Kitchen",
"lat": 46.205307,
"lon": 6.1434257,
"flags": {},
"tags": {
"amenity": "restaurant"
},
"distanceAlongRouteKm": 0,
"offsetFromRouteM": 102
},
{
"id": "node/1379366890",
"category": "water",
"subtype": "drinking_water",
"name": null,
"lat": 46.2047788,
"lon": 6.1417476,
"flags": {
"hasWater": true
},
"tags": {
"amenity": "fountain",
"drinking_water": "yes"
},
"distanceAlongRouteKm": 0,
"offsetFromRouteM": 120
},
{
"id": "node/3032374079",
"category": "food",
"subtype": "restaurant",
"name": "Le Paradis",
"lat": 46.2054609,
"lon": 6.1419829,
"flags": {},
"tags": {
"website": "https://www.terrasse-paradis.ch/",
"addr:street": "Quai Turrettini",
"amenity": "restaurant"
},
"distanceAlongRouteKm": 0,
"offsetFromRouteM": 151
}
],
"totals": {
"grocery": 0,
"fuel": 0,
"food": 79,
"water": 19,
"toilets": 0,
"bike": 0
},
"totalCount": 98,
"gaps": [],
"gapCount": 0,
"routeLengthKm": 7.568,
"partial": false,
"cached": false,
"source": "db",
"coverage": [
{
"sectionIndex": 0,
"segmentIndexes": [
0,
1,
2
]
}
]
}
GET /v1/route-poi/tile/{row}/{col}
All stops in a tile. Every stop of the default categories in one 0.1° tile (row = floor(lat × 10), col = floor(lon × 10)), for apps that cache stops by area.
Koszt: One request.
Parametry
row | floor(lat × 10) |
col | floor(lon × 10) |
Zapytanie
curl 'https://geo.runningcat.dev/v1/route-poi/tile/462/61' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"pois": [
{
"id": "node/10009315581",
"category": "water",
"subtype": "drinking_water",
"name": null,
"lat": 46.2185561,
"lon": 6.150866,
"flags": {
"hasWater": true
},
"tags": {
"amenity": "drinking_water",
"access": "yes",
"fee": "no"
}
},
{
"id": "node/10079250380",
"category": "food",
"subtype": "restaurant",
"name": "Hanae",
"lat": 46.2043595,
"lon": 6.1563109,
"flags": {},
"tags": {
"opening_hours": "Tu-Sa 12:00-14:00,19:00-22:00",
"website": "https://hanae-restaurant.ch/",
"addr:street": "Rue des Pierres-du-Niton",
"addr:housenumber": "5",
"addr:city": "Genève",
"phone": "+41 22 736 93 93",
"amenity": "restaurant"
}
},
{
"id": "node/10096957554",
"category": "food",
"subtype": "fast_food",
"name": "River Side",
"lat": 46.2013962,
"lon": 6.1553355,
"flags": {},
"tags": {
"opening_hours": "Mo 19:00-01:00; Tu 19:00-02:00; We 19:00-02:30; Th 19:00-03:00; Fr, Sa 19:00-04:00; Su 19:00-00:00",
"phone": "+41227362365",
"amenity": "fast_food"
}
}
],
"complete": true,
"source": "db",
"fetchedAt": "2026-11-12T12:36:13.181Z",
"row": 462,
"col": 61,
"version": 1
}
OpenStreetMap data
Overpass QL and OSM features by tag.
POST /v1/overpass/interpreter
Overpass QL. Overpass QL queries answered from our copy of OpenStreetMap, in the Overpass JSON format. Send the query as the body (text/plain), as the form field data, or as ?data= on GET; /v1/overpass/api/interpreter works too, and the key may come as ?key=. open_at=YYYY-MM-DDTHH:MM (local time) keeps only the places open then. Errors come back as remark, as Overpass does. See the Overpass QL examples page for what is supported.
Koszt: One request.
Parametry
open_at opcjonalnie | Local time such as 2026-11-10T06:30 |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/overpass/interpreter' \
-H "Authorization: Bearer YOUR_KEY" \
--data-binary 'node["amenity"="drinking_water"](around:300,46.2044,6.1432);out;'
Przykładowa odpowiedź
{
"version": 0.6,
"generator": "Running Cat Geo API",
"osm3s": {
"timestamp_osm_base": "2026-11-02T21:21:26+00:00",
"copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."
},
"elements": [
{
"type": "node",
"id": 897590805,
"lat": 46.2054894,
"lon": 6.1451637,
"tags": {
"amenity": "drinking_water",
"fountain": "bottle_refill",
"check_date": "2023-05-24"
}
},
{
"type": "node",
"id": 1906525422,
"lat": 46.2028922,
"lon": 6.1448299,
"tags": {
"amenity": "drinking_water",
"designation": "potable water"
}
}
]
}
POST /v1/poi/corridor
OSM features along a route by tag. OSM nodes and ways (with center) whose tags match filters ({"amenity": ["cafe", "restaurant"], ...}, 1 to 50 keys) within buffer_m of the route. 422 not_covered outside the map data. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
buffer_m | number, 1 to 20000 |
filters | object |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/poi/corridor' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]},"buffer_m":300,"filters":{"amenity":["drinking_water"]}}'
Przykładowa odpowiedź
{
"source": "db",
"elements": [
{
"type": "node",
"id": 897590805,
"lat": 46.2054894,
"lon": 6.1451637,
"tags": {
"amenity": "drinking_water",
"fountain": "bottle_refill",
"check_date": "2023-05-24"
}
},
{
"type": "node",
"id": 1485121637,
"lat": 46.1903548,
"lon": 6.1505338,
"tags": {
"amenity": "drinking_water"
}
},
{
"type": "node",
"id": 1769544502,
"lat": 46.1919462,
"lon": 6.1465644,
"tags": {
"amenity": "drinking_water",
"fountain": "drinking",
"check_date": "2024-01-30"
}
}
]
}
POST /v1/poi/boxes
OSM features in boxes by tag. The same in up to 16 boxes [west, south, east, north] of at most 1 square degree each.
Koszt: One request.
Treść
boxes | array of [lon, lat], 1 to 16 items |
filters | object |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/poi/boxes' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"boxes":[[6.14,46.2,6.16,46.21]],"filters":{"amenity":["cafe"]}}'
Przykładowa odpowiedź
{
"source": "db",
"elements": [
{
"type": "node",
"id": 626085414,
"lat": 46.206384,
"lon": 6.1450353,
"tags": {
"name": "Starbucks",
"brand": "Starbucks",
"amenity": "cafe",
"cuisine": "coffee_shop",
"takeaway": "yes",
"addr:city": "Genève",
"official_name": "Starbucks Coffee",
"brand:wikidata": "Q37158",
"brand:wikipedia": "en:Starbucks",
"opening_hours": "Mo-Fr 06:30-20:30; Sa 07:00-20:30; Su 07:30-20:30",
"source:opening_hours": "atp",
"check_date:opening_hours": "2026-11-05",
"phone": "+41 43 421 42 26",
"website": "https://www.starbucks.co.uk/store-locator/40024-96840/quai-des-bergues"
}
},
{
"type": "node",
"id": 656492497,
"lat": 46.2009495,
"lon": 6.1415985,
"tags": {
"name": "Café du Grütli",
"phone": "+41 22 321 51 58",
"amenity": "cafe",
"cuisine": "regional",
"website": "https://www.cafedugrutli.ch/",
"diet:vegan": "yes",
"wheelchair": "yes",
"addr:street": "Rue du Général-Dufour",
"opening_hours": "Mo-Th 08:00-24:00, Fr 16:00-23:00, Sa 16:00-01:00, Su 16:00-23:00",
"addr:housenumber": "16",
"diet:gluten_free": "yes"
}
},
{
"type": "node",
"id": 767144613,
"lat": 46.207876,
"lon": 6.1416771,
"tags": {
"name": "Chatime",
"brand": "Chatime",
"branch": "KINAYO",
"amenity": "cafe",
"cuisine": "bubble_tea",
"takeaway": "yes",
"brand:wikidata": "Q16829306"
}
}
]
}
POST /v1/roads/along
Roads along a route. Highway ways within buffer_m (1 to 200) of a route, with their OSM tags and geometry. For surface statistics /v1/route/surfaces does the matching for you. A route is GeoJSON {"type": "LineString", "coordinates": [[lon, lat], ...]} or a MultiLineString of sections in order, up to 20,000 km.
Koszt: One request.
Treść
route | GeoJSON LineString or MultiLineString or GeoJSON LineString or MultiLineString |
buffer_m | number, 1 to 200 |
Zapytanie
curl -X POST 'https://geo.runningcat.dev/v1/roads/along' \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"route":{"type":"LineString","coordinates":[[6.1432,46.2044],[6.15,46.19],[6.175,46.17],[6.2,46.15]]},"buffer_m":20}'
Przykładowa odpowiedź
{
"source": "db",
"ways": [
{
"id": 4272838,
"tags": {
"lit": "yes",
"name": "Rue Lombard",
"lanes": "2",
"busway": "lane",
"oneway": "yes",
"highway": "secondary",
"surface": "asphalt",
"cycleway": "share_busway",
"maxspeed": "50",
"lanes:psv": "1",
"psv:lanes": "yes|designated"
},
"geometry": [
[
6.147473,
46.195835
],
[
6.147557,
46.19577
],
[
6.147715,
46.195644
]
]
},
{
"id": 5070216,
"tags": {
"lit": "yes",
"name": "Boulevard de la Tour",
"lanes": "3",
"oneway": "yes",
"highway": "secondary",
"surface": "asphalt",
"maxspeed": "30",
"cycleway:right": "lane"
},
"geometry": [
[
6.14679,
46.195418
],
[
6.146854,
46.195432
],
[
6.146914,
46.195452
]
]
},
{
"id": 5070228,
"tags": {
"lit": "yes",
"name": "Rue de la Cité",
"bicycle": "designated",
"highway": "pedestrian",
"surface": "sett",
"segregated": "no"
},
"geometry": [
[
6.14362,
46.203894
],
[
6.143629,
46.203875
],
[
6.143649,
46.203835
]
]
}
]
}
Service
The state of the data.
GET /v1/status
Data status. The loaded OpenStreetMap regions, when they were imported and how fresh their data is, and how busy the server is.
Koszt: One request.
Zapytanie
curl 'https://geo.runningcat.dev/v1/status' \
-H "Authorization: Bearer YOUR_KEY"
Przykładowa odpowiedź
{
"import": {
"regions": [
"africa",
"antarctica",
"australia-oceania"
],
"version": 31,
"import_id": 31,
"imported_at": "2026-11-08T17:55:10.220669+00:00",
"switched_at": "2026-11-08T17:55:10.220669+00:00",
"data_timestamp": "2026-11-02T21:21:26+00:00",
"region_details": [
{
"region": "africa",
"import_id": 29,
"switched_at": "2026-11-08T17:53:57.686042+00:00",
"data_timestamp": "2026-11-07T21:21:36+00:00"
},
{
"region": "antarctica",
"import_id": 30,
"switched_at": "2026-11-08T17:55:10.220669+00:00",
"data_timestamp": "2026-11-07T21:21:36+00:00"
},
{
"region": "australia-oceania",
"import_id": 28,
"switched_at": "2026-11-07T09:06:14.889892+00:00",
"data_timestamp": "2026-11-05T21:23:02+00:00"
}
]
},
"flyover": {
"memory": 0,
"store": 0,
"db": 0,
"uncovered": 0,
"failed": 0,
"memory_bytes": 0,
"db_slots": {
"active": 0,
"waiting": 0
}
},
"requests": {
"running": 1,
"waiting": 0
}
}