Open Landmarks / Documentation
API reference
Discover landmarks by location and download their models, metadata and editable sources.
https://open-landmarks.benmaps.frNo API key required. All resources support GET, HEAD and cross-origin reads. Resolve returned paths against the base URL.
Resolve the global approved or preview channel, then request tiles from its catalogue. Fetch model files only when needed.
Get a release
/api/v1/{channel}.jsonResolves a channel to its current release. Save the returned catalogue path to pin that release.
Path parameters channel — latest for approved models, or preview to include drafts.
200 OK · application/json
A release pointer. A channel with nothing published returns 200 with release: null, catalogue: null and count: 0 — treat that as "not yet released" rather than an empty release. The current submissions have 24 approved models and 88 models in preview.
| Field | Type | Description |
|---|---|---|
schemaVersion | integer | Response schema version. |
channel | string | approved for latest.json; preview for preview.json. |
release | string | null | Immutable release ID, or null when nothing is published. |
count | integer | Number of models in this release. |
catalogue | string | null | Path to the pinned catalogue, or null when nothing is published. |
Response example
{
"schemaVersion": 1,
"channel": "preview",
"release": "preview-7bd48fe030ad21eb2280",
"count": 88,
"catalogue": "/api/v1/releases/preview-7bd48fe030ad21eb2280/catalogue.json"
}Cache: 60 seconds · revalidate. Open example ↗
Get a catalogue
/api/v1/releases/{release}/catalogue.jsonReturns spatial index information and links to the full dataset.
Path parameters release — exact release ID returned by a pointer.
200 OK · application/json
A catalogue for the requested release.
| Field | Type | Description |
|---|---|---|
schemaVersion / release / channel / count | integer / string | Schema version, release ID, channel and model count, as in the release pointer. |
status | string | approved-only or includes-unreviewed-drafts. |
assetBase | string | Origin-relative asset root. |
bounds | number[4] | Dataset extent: [west, south, east, north], WGS84 degrees. |
maxHeightM | number | Maximum model height in metres; useful for padding discovery. |
minZoom | number | Lowest member display zoom; resolve metadata once, then defer index requests below this zoom. |
index.zoom | integer | Fixed index zoom; currently 12. |
index.template | string | Tile path template with {x} and {y} placeholders. |
index.occupied | string[] | Available cells, each formatted as "x/y". |
assets | string | Path to all model metadata in this release. |
sourceDatabase | string | Path to the complete spatial source database. |
attribution / dataLicense | string | Dataset credit and spatial data license. |
Response example
{
"schemaVersion": 1,
"release": "preview-7bd48fe030ad21eb2280",
"channel": "preview",
"count": 88,
"status": "includes-unreviewed-drafts",
"assetBase": "/",
"materialLibrary": {
"schemaVersion": 1,
"sha256": "7afc40cf0b82b7c3c054f287817be2a37e52192aa734f187f8b20ee3277187dd",
"url": "/materials/7afc40cf0b82b7c3c054f287817be2a37e52192aa734f187f8b20ee3277187dd.json"
},
"bounds": [
-122.4809672,
37.7724394,
2.3985133,
51.5147302
],
"maxHeightM": 330,
"minZoom": 13,
"attribution": "Open Landmarks; © OpenStreetMap contributors",
"dataLicense": "ODbL-1.0",
"index": {
"zoom": 12,
"template": "/api/v1/releases/preview-7bd48fe030ad21eb2280/index/12/{x}/{y}.json",
"occupied": [
"2046/1362",
"2047/1361",
"2073/1408",
"2073/1409",
"2074/1408",
"2074/1409",
"2075/1408",
"2075/1409",
"654/1582",
"654/1583",
"655/1582",
"655/1583"
]
},
"assets": "/api/v1/releases/preview-7bd48fe030ad21eb2280/assets.json",
"sourceDatabase": "/api/v1/releases/preview-7bd48fe030ad21eb2280/spatial-database.json"
}Cache: 1 year · immutable. Open example ↗
Get a tile
/api/v1/releases/{release}/index/12/{x}/{y}.jsonReturns metadata for whole models whose ground bounding boxes intersect an XYZ cell.
Path parameters release — exact release ID returned by a pointer. x, y — integer Web Mercator tile coordinates at zoom 12 (0–4095). Use cells listed in index.occupied.
200 OK · application/json
A tile containing model entries. Unoccupied cells return 404. Entries contain placement, download and attribution fields; full provenance is available at each entry’s metadata path.
| Field | Type | Description |
|---|---|---|
schemaVersion | integer | Response schema version. |
release | string | Pinned release ID. |
assets | object[] | Model entries; see metadata fields below. |
Response example · selected fields
{
"schemaVersion": 1,
"release": "preview-7bd48fe030ad21eb2280",
"assets": [
{
"id": "elizabeth-tower",
"revision": "a753f2b89a4c25178256c3de24e6c84cd436d600d63ea7ccc69377133f7cdbd9",
"anchor": [
-0.12457352696457669,
51.500700465991045
],
"minZoom": 15,
"detailZoom": 17,
"metadata": "/assets/elizabeth-tower/b910cdfc2a7e4a309b85071fd272c7905a1cc83173051e62b00518ff68bc6c3a/asset.json",
"lods": {
"low": {
"url": "/models/elizabeth-tower/073f09850da39f08fa5bb4b5b7a4036360ddaba0e46fc1dab4aab9994ca2d674/low.glb",
"bytes": 205680,
"sha256": "073f09850da39f08fa5bb4b5b7a4036360ddaba0e46fc1dab4aab9994ca2d674",
"triangles": 4746,
"gzip": {
"url": "/models/elizabeth-tower/073f09850da39f08fa5bb4b5b7a4036360ddaba0e46fc1dab4aab9994ca2d674/low.glb.gz",
"bytes": 67219,
"sha256": "58286788e3e4a02b685f243d05ededfbe92f5f848bf084f586b8709e53dec9b3",
"encoding": "gzip-file"
}
},
"detail": {
"url": "/models/elizabeth-tower/cfc00bc16755d9dd8a989f1751ecb62deeec44f44c98a21a50db111bc462aaf3/detail.glb",
"bytes": 1431068,
"sha256": "cfc00bc16755d9dd8a989f1751ecb62deeec44f44c98a21a50db111bc462aaf3",
"triangles": 33510,
"gzip": {
"url": "/models/elizabeth-tower/cfc00bc16755d9dd8a989f1751ecb62deeec44f44c98a21a50db111bc462aaf3/detail.glb.gz",
"bytes": 419553,
"sha256": "762e8028e28ea129d7596262cc53a6c7ddae8e9f4813c20c6d57484bd4a7401d",
"encoding": "gzip-file"
}
}
}
},
{
"id": "london-eye",
"revision": "630cc43535a4d4086917c767925405d11b8682f94f285367139c9f1404d8fe81",
"anchor": [
-0.1196765,
51.503341600000006
],
"minZoom": 15,
"detailZoom": 17,
"metadata": "/assets/london-eye/9e762d5406a3f1e1e7c97c6ee5ab28481713f9b2951af8a6bee17eb4f771a3c0/asset.json",
"lods": {
"low": {
"url": "/models/london-eye/720e9fee1ab7dd29cbe465c156ccd22efe2e680890cdb498c5b30b7dc6dc2404/low.glb",
"bytes": 141076,
"sha256": "720e9fee1ab7dd29cbe465c156ccd22efe2e680890cdb498c5b30b7dc6dc2404",
"triangles": 6678,
"gzip": {
"url": "/models/london-eye/720e9fee1ab7dd29cbe465c156ccd22efe2e680890cdb498c5b30b7dc6dc2404/low.glb.gz",
"bytes": 81211,
"sha256": "939f5fc94525d2b8f8d71ef8f69afe35c0c7ea7063446863a23aa1b958db89f9",
"encoding": "gzip-file"
}
},
"detail": {
"url": "/models/london-eye/83267b7584aec63b539b7bd96f76996b26a2d4fc50fd041008b4920de4eeb2b9/detail.glb",
"bytes": 706164,
"sha256": "83267b7584aec63b539b7bd96f76996b26a2d4fc50fd041008b4920de4eeb2b9",
"triangles": 37558,
"gzip": {
"url": "/models/london-eye/83267b7584aec63b539b7bd96f76996b26a2d4fc50fd041008b4920de4eeb2b9/detail.glb.gz",
"bytes": 392625,
"sha256": "05f6af90ed0e350f41a79885c983d95cf24dcf8ac7e951c42fc7bb0cb7c4f26d",
"encoding": "gzip-file"
}
}
}
},
{
"id": "nelsons-column",
"revision": "ce345a78e44bbe4c688c01b140fe765c1d0e604c15bbb2c138e0a0077292c1d4",
"anchor": [
-0.12792960922045085,
51.50775729907043
],
"minZoom": 15,
"detailZoom": 17,
"metadata": "/assets/nelsons-column/f45c9f422ea032d38e915dff659cc70a0b0d3277e5c4d214aaf9f97bdeddfca5/asset.json",
"lods": {
"low": {
"url": "/models/nelsons-column/71d2cb95a98738c192b138b9ef668d55e443a249ee9d06d37f539cf8bedccdee/low.glb",
"bytes": 64600,
"sha256": "71d2cb95a98738c192b138b9ef668d55e443a249ee9d06d37f539cf8bedccdee",
"triangles": 2848,
"gzip": {
"url": "/models/nelsons-column/71d2cb95a98738c192b138b9ef668d55e443a249ee9d06d37f539cf8bedccdee/low.glb.gz",
"bytes": 31435,
"sha256": "90bd9c0bd1447ef4ae5ae4b80a9a59cb4cdd2f0fcb19f8e7b6e5280954d06f93",
"encoding": "gzip-file"
}
},
"detail": {
"url": "/models/nelsons-column/a2a1138a7e3b3f5434f423d1d5d0f9daed64c5ecc8fcf365651a9c7c41713a08/detail.glb",
"bytes": 293112,
"sha256": "a2a1138a7e3b3f5434f423d1d5d0f9daed64c5ecc8fcf365651a9c7c41713a08",
"triangles": 13352,
"gzip": {
"url": "/models/nelsons-column/a2a1138a7e3b3f5434f423d1d5d0f9daed64c5ecc8fcf365651a9c7c41713a08/detail.glb.gz",
"bytes": 143959,
"sha256": "bc23ecd960414c19e4baf35a1fde1f1890776c9d03308e17d538a92e8c76d2f8",
"encoding": "gzip-file"
}
}
}
},
{
"id": "palace-of-westminster",
"revision": "601479b75470f7b8310288036a80e78c2f4dc2faa421e32fe2e837f1d9ac2332",
"anchor": [
-0.1246865838037018,
51.49935725233581
],
"minZoom": 15,
"detailZoom": 17,
"metadata": "/assets/palace-of-westminster/9a294063534c355ae32e1bd4a22601f480997bb5972ccdf770420a1e5e5fb066/asset.json",
"lods": {
"low": {
"url": "/models/palace-of-westminster/4b2d578e7a33abef6760a850a9510e0ba0a37df721b97463e1449f9b9cb43b8b/low.glb",
"bytes": 249620,
"sha256": "4b2d578e7a33abef6760a850a9510e0ba0a37df721b97463e1449f9b9cb43b8b",
"triangles": 5176,
"gzip": {
"url": "/models/palace-of-westminster/4b2d578e7a33abef6760a850a9510e0ba0a37df721b97463e1449f9b9cb43b8b/low.glb.gz",
"bytes": 90272,
"sha256": "4cc85402ac4b182d5c81bc5f6cf98e24e7432eb15f1b395c8884d1b73c0227e9",
"encoding": "gzip-file"
}
},
"detail": {
"url": "/models/palace-of-westminster/eb9baac16ca2163d920b4e6ee5656e7371966b46c1e8b741f5d4be1e16e7f24b/detail.glb",
"bytes": 1449028,
"sha256": "eb9baac16ca2163d920b4e6ee5656e7371966b46c1e8b741f5d4be1e16e7f24b",
"triangles": 32538,
"gzip": {
"url": "/models/palace-of-westminster/eb9baac16ca2163d920b4e6ee5656e7371966b46c1e8b741f5d4be1e16e7f24b/detail.glb.gz",
"bytes": 513226,
"sha256": "63349b9334d2369d3796024f5004174fa5d5f3fe0ad86527a0610ad18f2fe411",
"encoding": "gzip-file"
}
}
}
}
]
}Cache: 1 year · immutable. Open example ↗
Request occupied cells intersecting a padded viewport. Models can appear in several cells; deduplicate by id and revision. Account for camera pitch and tall buildings, then cull against 3D bounds.
Get model metadata
/assets/{id}/{publicationRevision}/asset.jsonReturns placement, downloads, provenance and review information for one model. Follow the metadata path from a tile or the full dataset response.
Path parameters id — model ID. publicationRevision — metadata revision from the model entry.
200 OK · application/json
A model metadata object.
| Field | Type | Description |
|---|---|---|
id / name | string | Stable model ID and display name. |
revision / publicationRevision | string | Content revision; metadata revision also includes review state. |
approved | boolean | Whether this exact content revision has been approved. |
anchor | number[2] | WGS84 [longitude, latitude]. |
axes / units / heading | string / number | GLB orientation and units. Heading is baked into the geometry. |
bounds | number[4] | Ground bounding box: [west, south, east, north]. |
boundsBlenderM | number[2][3] | Local [min, max] corners, X east / Y north / Z up, in metres. |
minZoom / detailZoom | number | Suggested display and detail-LOD zoom thresholds. |
lods.low / lods.detail | object | Raw GLB url, bytes, sha256, triangles and a gzip download descriptor. |
source / spatialSource / preview | object | Download descriptors: url, bytes and sha256. Files use independent content hashes under /objects/. |
metadata / validation | string | Paths to this metadata and its structural validation report. |
replacementFootprint / basemapReplacement | object | Footprint and optional dataset-specific extrusion replacement hints. |
entranceLights | number[][3] | Optional local light anchors in GLB axes. |
authors / attribution / artisticLicense / spatialDataLicense / licenseScope | array / string | Authorship, credits and component licensing. |
wikidata / modelSources | string / array | Optional Wikidata Q-ID and imported geometry provenance: source authors, original-file hashes, licenses and modifications. |
osm / references / assistance / review | object / array / string | Source provenance, reference credits, assistance disclosure and review record. |
Response example · selected fields
{
"id": "elizabeth-tower",
"name": "Elizabeth Tower",
"revision": "a753f2b89a4c25178256c3de24e6c84cd436d600d63ea7ccc69377133f7cdbd9",
"publicationRevision": "b910cdfc2a7e4a309b85071fd272c7905a1cc83173051e62b00518ff68bc6c3a",
"approved": false,
"anchor": [
-0.12457352696457669,
51.500700465991045
],
"axes": "X east / Y up / Z south",
"units": "metres",
"heading": 0,
"minZoom": 15,
"detailZoom": 17,
"boundsBlenderM": [
[
-7.490651607513428,
-7.439363956451416,
0
],
[
7.542989730834961,
7.59157133102417,
96
]
],
"lods": {
"low": {
"url": "/models/elizabeth-tower/073f09850da39f08fa5bb4b5b7a4036360ddaba0e46fc1dab4aab9994ca2d674/low.glb",
"bytes": 205680,
"sha256": "073f09850da39f08fa5bb4b5b7a4036360ddaba0e46fc1dab4aab9994ca2d674",
"triangles": 4746,
"gzip": {
"url": "/models/elizabeth-tower/073f09850da39f08fa5bb4b5b7a4036360ddaba0e46fc1dab4aab9994ca2d674/low.glb.gz",
"bytes": 67219,
"sha256": "58286788e3e4a02b685f243d05ededfbe92f5f848bf084f586b8709e53dec9b3",
"encoding": "gzip-file"
}
},
"detail": {
"url": "/models/elizabeth-tower/cfc00bc16755d9dd8a989f1751ecb62deeec44f44c98a21a50db111bc462aaf3/detail.glb",
"bytes": 1431068,
"sha256": "cfc00bc16755d9dd8a989f1751ecb62deeec44f44c98a21a50db111bc462aaf3",
"triangles": 33510,
"gzip": {
"url": "/models/elizabeth-tower/cfc00bc16755d9dd8a989f1751ecb62deeec44f44c98a21a50db111bc462aaf3/detail.glb.gz",
"bytes": 419553,
"sha256": "762e8028e28ea129d7596262cc53a6c7ddae8e9f4813c20c6d57484bd4a7401d",
"encoding": "gzip-file"
}
}
},
"source": {
"url": "/objects/37b6f0f248a7396b1de686b6d23fd569bcda2fe9e1790f626550cc59699af05a/source.blend.gz",
"bytes": 763794,
"sha256": "37b6f0f248a7396b1de686b6d23fd569bcda2fe9e1790f626550cc59699af05a"
},
"spatialSource": {
"url": "/objects/dd860be52fb2944ea153b8091881803b6ad6616fc1e6da26b74286cf7e5ac9ae/spatial-source.json",
"bytes": 60254,
"sha256": "dd860be52fb2944ea153b8091881803b6ad6616fc1e6da26b74286cf7e5ac9ae"
},
"attribution": "Open Landmarks; contains © OpenStreetMap contributors, ODbL-1.0; Architectural measurements from the linked official sources",
"artisticLicense": "CC-BY-4.0",
"spatialDataLicense": "ODbL-1.0"
}Cache: 1 year · immutable. Open example ↗
Download a model
/models/{id}/{sha256}/{lod}.glbReturns a complete, texture-free glTF binary. Use the download URL from lods.low or lods.detail.
Path parameters id — model ID. sha256 — hash of the raw GLB. lod — low or detail.
200 OK · model/gltf-binary
Binary GLB bytes. Append .gz for the explicit gzip file (application/gzip, no Content-Encoding); decompress it once before loading. The gzip descriptor gives the compressed size and hash.
Cache: 1 year · immutable. Open example ↗
JavaScript · download and decompress
const origin = 'https://open-landmarks.benmaps.fr';
const response = await fetch(new URL(asset.lods.detail.gzip.url, origin));
if (!response.ok) throw new Error('Model request failed');
const bytes = await new Response(response.body.pipeThrough(
new DecompressionStream('gzip')
)).arrayBuffer();
// Pass bytes to a glTF loader.Use the raw GLB where native gzip decompression is unavailable. V1 needs no Draco, Meshopt or texture decoder. Retain the current LOD until its replacement has loaded.
Dataset and sources
These GET resources also cache for one year. Follow their paths from the catalogue or model metadata.
| Field | Type | Description |
|---|---|---|
catalogue.assets | JSON | {schemaVersion, release, assets} with complete model metadata. Open example ↗ |
catalogue.sourceDatabase | JSON | {license, attribution, assets} with OSM-derived source records. Open example ↗ |
asset.source.url | gzip file | Editable Blender source; decompress before opening. |
asset.spatialSource.url | JSON | Per-model OSM spatial source extract. |
asset.preview.url | WebP | Static model preview. |
asset.validation | JSON | Structural validation report. |
There is one global dataset. No collection parameter is needed.
HTTP behavior
| Field | Type | Description |
|---|---|---|
200 OK | success | Resource exists. HEAD returns headers without a response body. |
304 Not Modified | cache | A conditional request can reuse the cached representation. |
404 Not Found | error | Unknown resource, release, model or unoccupied tile. Error bodies are not a defined JSON schema. |
The release pointers revalidate after 60 seconds. Release data, model files and source revisions cache for one year and retain their URLs. JSON can use negotiated HTTP compression; explicit .gz files require client decompression. V1 has no server-side search or query filters.
Placement and attribution
GLB vertices use metres, X east / Y up / Z south. Ordinary ground-relative models add terrain elevation once; models with terrainPlacement.datum: "sea-level" use their explicit elevationM instead. Do not reapply heading. Convert boundsBlenderM to GLB axes before culling; use the full bounds for long bridges.
| Field | Type | Description |
|---|---|---|
terrainComponents | object | Optional explicit per-vertex building ownership and bounded component grounding. Each building moves rigidly to its own sampled floor; basement ends meet the slope. Restore flat-ground geometry when terrain is disabled and preserve native buildings while terrain samples are unavailable. |
kind | string | Optional model category; bridge models declare "bridge". |
terrainPlacement | object | Optional explicit sea-level origin and bounded terrain contact zones. Contact heights are local to the origin; apply only the declared shore transitions and support skirts. Keep the rigid span at its authored elevation. |
bridgeReplacement | object | Optional road source-layer, exact names and line coverage threshold. Replace matching road lines only while the bridge is resident and terrain placement is supported. Preserve approach continuations outside the footprint and restore the native roads on unloading or failure. |
Preserve material base colors and adapt light and emissive intensity to your scene. Suppress overlapping basemap extrusions after the model loads. basemapReplacement IDs apply only to the named dataset snapshot.
Retain each model’s attribution and source links, including © OpenStreetMap contributors. See licensing and attribution for component terms.