Raster maps guide

A practical guide with examples: raster tiles with Leaflet and MapLibre, switching to the orthophoto, a WMTS connection in QGIS, and the EPSG:3301 layers with OpenLayers.

Base URL: the raster maps live at https://pump.elemroot.com (like the geoservices): not at api.elemroot.com, which hosts the vector maps.
Contents

Authentication

Every request needs the key parameter and the key must include the raster service. Without a key, or with an invalid one, the service responds with 403 (body {"error":"invalid_api_key"}). A key may be bound to an origin: then it only works from the allowed web page (the browser sends Origin/Referer). The docs_โ€ฆ key used in the examples is a rate-limited demo key (too many requests โ†’ 429); for your own application request a personal key.

curl -s -o tile.png \
  'https://pump.elemroot.com/xyz/eestig/12/2329/1202.png?key=docs_382d376eaaa6d004b7b93b7d'

Layers and grids

LayerContentsGridFormatMax zoom
eestigElemroot map of EstoniaEPSG:3857png18
eestio3857Maa-amet orthophotoEPSG:3857jpeg18
eestiElemroot map of EstoniaEPSG:3301 (L-EST97)png18
eestioMaa-amet orthophotoEPSG:3301 (L-EST97)jpeg15

Which grid should I pick? On the web use the EPSG:3857 layers (eestig, eestio3857); they use the standard Web Mercator grid that Leaflet and MapLibre understand without extra libraries. The EPSG:3301 layers use the Estonian national L-EST97 grid: you need them in GIS software (via WMTS) or when your application works in L-EST97 coordinates; on the web they require OpenLayers + proj4 or Leaflet + Proj4Leaflet (see below).

Quickstart: Leaflet

The simplest way to put a raster map on a page (working full example: Leaflet + EPSG:3301):

<div id="map" style="height: 400px"></div>
<script>
  const map = L.map('map').setView([59.437, 24.7536], 12); // Tallinn

  L.tileLayer('https://pump.elemroot.com/xyz/eestig/{z}/{x}/{y}.png?key=docs_382d376eaaa6d004b7b93b7d', {
    maxZoom: 18,
    attribution: 'ยฉ Elemroot'
  }).addTo(map);
</script>

For the orthophoto switch the layer: eestio3857/{z}/{x}/{y}.jpeg (attribution ยฉ Maa-amet).

MapLibre GL JS

In MapLibre raster tiles are a raster-type source. This works well when you want to show the orthophoto next to (or under) the vector map:

const map = new maplibregl.Map({
  container: 'map',
  style: {
    version: 8,
    sources: {
      orto: {
        type: 'raster', tileSize: 256, maxzoom: 18,
        tiles: ['https://pump.elemroot.com/xyz/eestio3857/{z}/{x}/{y}.jpeg?key=docs_382d376eaaa6d004b7b93b7d'],
        attribution: 'ยฉ Maa-amet'
      }
    },
    layers: [{ id: 'orto', type: 'raster', source: 'orto' }]
  },
  center: [24.7536, 59.4370],
  zoom: 12
});

Live demo with a layer switcher (map โ†” orthophoto): the "Raster map with layer switcher" example.

WMTS and QGIS

WMTS is a self-describing standard: the capabilities document lists the layers, grids and tile URLs. Give your GIS software the capabilities URL with your key: the key is carried into the tile URLs automatically:

https://pump.elemroot.com/wmts/1.0.0/WMTSCapabilities.xml?key=docs_382d376eaaa6d004b7b93b7d

In QGIS:

  1. Layer โ†’ Add Layer โ†’ Add WMS/WMTS Layer โ†’ New
  2. Paste the capabilities URL above (with your own key) into the URL field
  3. Connect: pick a layer (e.g. eesti with the est3301 grid, or eestig with webmerc) โ†’ Add

The EPSG:3301 layers arrive in QGIS in their native projection without reprojection; prefer them for an L-EST97 workflow.

The WMTS REST tile URL is /wmts/{layer}/{grid}/{z}/{x}/{y}.{ext} (TileMatrix/TileCol/TileRow; in the capabilities the TileMatrix IDs are zero-padded 00โ€ฆ20, but a plain 6 works too). Unlike the XYZ endpoint, the extension is mandatory here and must match the layer format: .png for map layers, .jpeg for the orthophoto (eestio, eestio3857). A wrong extension, wrong grid, unknown layer or a tile outside the grid returns 400 with an OGC ExceptionReport XML (InvalidParameterValue / TileOutOfRange). The interface is REST-only (no KVP GetTile); the capabilities document carries the key into the tile templates.

EPSG:3301 layers on the web (OpenLayers)

eesti and eestio live in the Estonian national grid: bbox [-211000, 5732000, 1325000, 7268000], initial resolution 6000 m/px, halving at every zoom level. XYZ axis order (row 0 is in the north). An OpenLayers + proj4 example (working full example: OpenLayers + EPSG:3301; the same grid with Leaflet: Leaflet + Proj4Leaflet):

proj4.defs('EPSG:3301',
  '+proj=lcc +lat_1=59.33333333333334 +lat_2=58 +lat_0=57.51755393055556 ' +
  '+lon_0=24 +x_0=500000 +y_0=6375000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs');
ol.proj.proj4.register(proj4);

const extent = [-211000, 5732000, 1325000, 7268000];
const resolutions = [];
for (let z = 0; z <= 18; z++) resolutions[z] = 6000 / Math.pow(2, z);

const map = new ol.Map({
  target: 'map',
  layers: [new ol.layer.Tile({
    source: new ol.source.XYZ({
      url: 'https://pump.elemroot.com/xyz/eesti/{z}/{x}/{y}.png?key=docs_382d376eaaa6d004b7b93b7d',
      projection: 'EPSG:3301',
      tileGrid: new ol.tilegrid.TileGrid({
        extent, resolutions, tileSize: 256,
        origin: [extent[0], extent[3]]   // NW corner = XYZ axis order
      }),
      attributions: 'ยฉ Elemroot'
    })
  })],
  view: new ol.View({
    projection: 'EPSG:3301',
    center: [542000, 6589000],           // Tallinn in L-EST97
    resolution: 6000 / Math.pow(2, 12)
  })
});

Parameters

* = required; the tables are generated from the OpenAPI YAML.

XYZ: /xyz/{layer}/{z}/{x}/{y}.png

ParamMeaningAllowed values / exampleDefault
{layer} *Layereestig, eestio3857 (EPSG:3857) ยท eesti, eestio (EPSG:3301); unknown โ†’ 404โ€”
{z} *Zoom level (row 0 in the north)0โ€ฆmax zoom (layer table; eestio 15, others 18)โ€”
{x} *Tile column (XYZ)integer; outside the grid โ†’ 404โ€”
{y} *Tile row (XYZ, y grows southwards)integer; outside the grid โ†’ 404โ€”
key *API key (with the raster service); missing/invalid โ†’ 403 JSONdocs_382d376eaaa6d004b7b93b7d (demo, rate-limited)โ€”

WMTS REST: /wmts/{layer}/{grid}/{z}/{x}/{y}.{ext}

ParamMeaningAllowed values / exampleDefault
{layer} *Layereestig, eestio3857 (grid webmerc) ยท eesti, eestio (grid est3301); unknown โ†’ 400โ€”
{grid} *TileMatrixSet: must match the layerwebmerc or est3301; wrong โ†’ 400โ€”
{z} *TileMatrix (zoom)6 or zero-padded 06โ€”
{x} *TileColinteger; outside โ†’ 400 TileOutOfRangeโ€”
{y} *TileRow (row 0 in the north)integer; outside โ†’ 400 TileOutOfRangeโ€”
{ext} *File extension: mandatory, must match the layer formatpng (eestig, eesti) or jpeg (eestio3857, eestio); wrong โ†’ 400โ€”
key *API key (with the raster service); missing/invalid โ†’ 403 JSONdocs_382d376eaaa6d004b7b93b7d (demo, rate-limited)โ€”

When to use what

The most common tasks and the layer/endpoint for each. All rows are verified live.

TaskCombinationWhy
Map on a web page (Leaflet, MapLibre, OpenLayers)/xyz/eestig/{z}/{x}/{y}.png?key=โ€ฆstandard Web Mercator, no extra libraries
Orthophoto on the web/xyz/eestio3857/{z}/{x}/{y}.jpeg?key=โ€ฆMaa-amet orthophoto in EPSG:3857, JPEG
Orthophoto under or next to the vector mapMapLibre raster source eestio3857see the MapLibre example
GIS software (QGIS etc.)WMTS capabilities URL with your keylayers, grids and tile templates come automatically
L-EST97 application / EPSG:3301 grid/xyz/eesti/โ€ฆ or /xyz/eestio/โ€ฆ + OpenLayers proj4 / Leaflet Proj4Leafletno reprojection
Sharp, styleable and lighter mapvector mapsraster only when you need the orthophoto, the L-EST97 grid or a client without WebGL
Four pitfalls. (1) The XYZ endpoint does not check the extension, the WMTS endpoint requires it to match the layer format (.jpeg for the orthophoto). (2) Row 0 is in the north and y grows southwards: also on the EPSG:3301 grid (the NW corner is the origin). (3) The keyless 403 body is JSON although the Content-Type is the image type; don't parse the response by extension. (4) Tiles come with a 7-day Cache-Control: map updates reach the browser with a delay.

Error handling

SituationCodeMessage
Key missing, invalid or without the raster service403JSON {"error":"invalid_api_key"}
XYZ: unknown layer404unknown layer: โ€ฆ (text)
XYZ: tile outside the grid404The requested tile is outside the bounding box of the tile map. (text, not an image)
WMTS: wrong extension400OGC ExceptionReport invalid format (png). this tile set only supports (jpeg)
WMTS: wrong grid / unknown layer400InvalidParameterValue: unknown tilematrixset โ€ฆ / unknown layer โ€ฆ
WMTS: tile outside the grid400TileOutOfRange
Too many requests (demo key)429Too Many Requests
Temporary source failure (e.g. the Maa-amet WMS not responding)500no image returned from source WMS โ€ฆ; retry later

Formats and notes

API reference (Swagger UI) โ†’ All endpoints and interactive "try it out". Live example โ†’ Raster map with a layer switcher on examples.elemroot.com.