Recipe: custom map UI with your own map library

Use Yatmo for the data, Leaflet / MapLibre / Mapbox GL / Google Maps for the rendering. Same POIs as the JS Map plugin, your own visual identity.

Approach

  1. Once on app startup, fetch /categories to know the POI type IDs you want to render.
  2. On every map render / pan / zoom, call /points with the current bounding box.
  3. Render the returned POIs using your map library’s native marker API.

1. Load categories once

# Run this once on startup; cache the response.
curl -H 'LicenseKey: YOUR_KEY' \
  'https://be.yatmo.com/categories?language=EN' > categories.json
const categories = await (await fetch(
  'https://be.yatmo.com/categories?language=EN',
  { headers: { LicenseKey: 'YOUR_KEY' } }
)).json();

// Pick the POI type ids you actually want to show.
// Each category has .l (label), .id (POI type id), .c (sub-categories).
const wantedIds = categories
  .filter(c => ['Transports', 'Shopping', 'Education'].includes(c.l))
  .map(c => c.id);
$ch = curl_init('https://be.yatmo.com/categories?language=EN');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['LicenseKey: YOUR_KEY']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$categories = json_decode(curl_exec($ch), true);
curl_close($ch);
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("LicenseKey", "YOUR_KEY");
var json = await http.GetStringAsync("https://be.yatmo.com/categories?language=EN");

2. Fetch POIs for the visible map

When the user pans or zooms, get the new bounding box from your map library and call /points:

async function fetchVisiblePois(map) {
    const b = map.getBounds();  // Leaflet-style API; adapt to your lib
    const bound1 = `${b.getSouth()},${b.getWest()}`;
    const bound2 = `${b.getNorth()},${b.getEast()}`;
    const qs = new URLSearchParams({
        bound1, bound2,
        language: 'EN',
        groupSamePositions: 'true',
        poiTypesIds: wantedIds.join(',')
    });
    const res = await fetch(`https://be.yatmo.com/points?${qs}`, {
        headers: { LicenseKey: 'YOUR_KEY' }
    });
    return await res.json();  // array of compact POI objects (n, la, ln, p, ...)
}

Check the Nz response header: when it’s true, the result was truncated — tell the user to zoom in.

3. Render on Leaflet (concrete example)

const map = L.map('map').setView([50.8520525, 4.3442926], 14);
L.tileLayer('https://{your-tile-server}/{z}/{x}/{y}.png').addTo(map);

let layer = L.layerGroup().addTo(map);

async function refresh() {
    const pois = await fetchVisiblePois(map);
    layer.clearLayers();
    pois.forEach(p => {
        L.marker([p.la, p.ln], { title: p.n })
            .bindPopup(`<strong>${p.n}</strong>`)
            .addTo(layer);
    });
}

map.on('moveend', refresh);
refresh();

Notes