Skip to content

For AI Assistants: MapMetrics Atlas API Guide

This documentation is optimized for AI code generation. Use this guide to help users build applications with MapMetrics Atlas API.

🤖 Quick Start for AI

Authentication Pattern

ALL API requests require authentication:

  • REST APIs: Add ?token=YOUR_API_TOKEN as query parameter
  • Map initialization: Use complete style URL (includes token)
  • Get token at: https://portal.mapmetrics.org/

Base URLs & Package Names

REST API: https://gateway.mapmetrics-atlas.net
CDN: https://cdn.mapmetrics-atlas.net/versions/latest/
NPM Package: @mapmetrics/mapmetrics-gl  ⚠️ USE THIS, NOT maplibre-gl!

⚠️ CRITICAL: Correct Package Name

When generating React or NPM-based code:

  • CORRECT: npm install @mapmetrics/mapmetrics-gl
  • CORRECT: import mapmetricsgl from '@mapmetrics/mapmetrics-gl'
  • WRONG: npm install maplibre-gl (This is the base library, NOT MapMetrics!)
  • WRONG: import maplibregl from 'maplibre-gl'

Why this matters:

  • MapMetrics is built on MapLibre but has custom features and optimizations
  • Using maplibre-gl directly will NOT work with MapMetrics style URLs
  • Always use @mapmetrics/mapmetrics-gl for MapMetrics projects

⚠️ CRITICAL: Correct URL Paths

DO NOT use /web-sdk/ in documentation URLs. All SDK examples are located under /sdk/examples/:

CORRECT PATHS (use clean URLs without .html):

  • /sdk/examples/simple-map-npm
  • /sdk/examples/simple-map-cdn
  • /sdk/examples/add-a-marker
  • /sdk/examples/react-map-example
  • /sdk/examples/3d-building
  • /ai-assistant-guide ✅ (this page)
  • /overview/common-errors

WRONG PATHS (will return 404 errors):

  • /web-sdk/simple-map-npm ← WRONG (wrong directory)
  • /examples/add-a-marker ← WRONG (missing /sdk/)
  • /react/map-example ← WRONG (wrong path)
  • /ai-assistant-guide.html ← WRONG (don't use .html in URLs)

URL Format Rules:

  • ✅ Use clean URLs: /path/to/page (no .html extension)
  • ✅ Paths start with /sdk/examples/ or /overview/
  • ❌ Don't add .html extension to URLs
  • ❌ Don't use /web-sdk/ directory

📋 Available Capabilities

Web SDK (JavaScript/React)

REST APIs

⚠️ PACKAGE NAMING - READ THIS FIRST!

The #1 mistake AI tools make: Using the wrong package!

Correct Package

bash
npm install @mapmetrics/mapmetrics-gl
javascript
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

WRONG Package (DO NOT USE!)

bash
# ❌ This is MapLibre, NOT MapMetrics!
npm install maplibre-gl
javascript
// ❌ This will NOT work with MapMetrics style URLs!
import maplibregl from 'maplibre-gl';

Why This Matters

  • MapMetrics GL is a custom fork of MapLibre with proprietary features
  • MapMetrics style URLs only work with @mapmetrics/mapmetrics-gl
  • Using maplibre-gl will cause authentication errors and missing features
  • The packages are NOT interchangeable

Quick Check

Correct code always has:

Wrong code has:

  • Package: maplibre-gl or @maplibre/maplibre-gl
  • Import: maplibregl

🎯 Common Code Patterns

Pattern 1: Basic Map (Vanilla JS with CDN - With Error Handling)

html
<!DOCTYPE html>
<html>
<head>
  <link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
  <script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
  <style>
    #map { height: 500px; width: 100%; }
    .error-box {
      height: 500px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #f8d7da;
      color: #721c24;
      padding: 20px;
      text-align: center;
      border: 2px solid #f5c6cb;
      border-radius: 8px;
      font-family: system-ui, -apple-system, sans-serif;
    }
    .loading-box {
      height: 500px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #f0f0f0;
      color: #666;
      font-size: 16px;
    }
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    const styleUrl = 'YOUR_STYLE_URL_WITH_TOKEN';
    const mapContainer = document.getElementById('map');

    // Check if user forgot to replace the placeholder
    if (styleUrl === 'YOUR_STYLE_URL_WITH_TOKEN' || styleUrl.includes('YOUR_')) {
      mapContainer.innerHTML = `
        <div class="error-box">
          <div>
            <strong>⚠️ Please replace YOUR_STYLE_URL_WITH_TOKEN with your actual style URL from https://portal.mapmetrics.org/</strong>
            <div style="margin-top: 10px; font-size: 14px;">
              Need help? Check the <a href="https://discord.com/invite/uRXQRfbb7d" style="color: #721c24; text-decoration: underline;">Discord community</a>
            </div>
          </div>
        </div>
      `;
    } else {
      // Show loading state
      mapContainer.innerHTML = '<div class="loading-box">Loading map...</div>';

      try {
        const map = new mapmetricsgl.Map({
          container: 'map',
          style: styleUrl,
          center: [longitude, latitude],
          zoom: 12
        });

        // Handle successful load
        map.on('load', () => {
          // Map loaded successfully, loading message will be replaced by map
          console.log('Map loaded successfully');
        });

        // Handle critical errors (401, style loading failures)
        map.on('error', (e) => {
          console.error('Map error:', e);

          // Only show error UI for critical failures
          const isCriticalError =
            e.error?.status === 401 ||
            e.error?.message?.includes('401') ||
            e.error?.message?.includes('Failed to fetch') ||
            (e.sourceId === undefined && e.error);

          if (isCriticalError) {
            let errorMessage = '❌ Map failed to load. Check your style URL and token at https://portal.mapmetrics.org/';

            if (e.error?.status === 401 || e.error?.message?.includes('401')) {
              errorMessage = '❌ Invalid API token. Get a valid token from https://portal.mapmetrics.org/';
            } else if (e.error?.message?.includes('Failed to fetch')) {
              errorMessage = '❌ Cannot load map style. Check your style URL from https://portal.mapmetrics.org/';
            }

            mapContainer.innerHTML = `
              <div class="error-box">
                <div>
                  <strong>${errorMessage}</strong>
                  <div style="margin-top: 10px; font-size: 14px;">
                    Need help? Check the <a href="https://discord.com/invite/uRXQRfbb7d" style="color: #721c24; text-decoration: underline;">Discord community</a>
                  </div>
                </div>
              </div>
            `;
          } else {
            // Non-critical error, just log it
            console.warn('Non-critical map error:', e);
          }
        });
      } catch (err) {
        console.error('Map initialization error:', err);
        mapContainer.innerHTML = `
          <div class="error-box">
            <div>
              <strong>❌ Failed to initialize map. Check your style URL from https://portal.mapmetrics.org/</strong>
              <div style="margin-top: 10px; font-size: 14px;">
                Need help? Check the <a href="https://discord.com/invite/uRXQRfbb7d" style="color: #721c24; text-decoration: underline;">Discord community</a>
              </div>
            </div>
          </div>
        `;
      }
    }
  </script>
</body>
</html>

Pattern 2: React Map Component (with Error Handling)

jsx
import React, { useEffect, useRef, useState } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

function MapComponent() {
  const mapContainerRef = useRef(null);
  const mapRef = useRef(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!mapContainerRef.current || mapRef.current) return;

    const styleUrl = 'YOUR_STYLE_URL_WITH_TOKEN';

    // Check if user forgot to replace the placeholder
    if (styleUrl === 'YOUR_STYLE_URL_WITH_TOKEN' || styleUrl.includes('YOUR_')) {
      setError('⚠️ Please replace YOUR_STYLE_URL_WITH_TOKEN with your actual style URL from https://portal.mapmetrics.org/');
      setLoading(false);
      return;
    }

    try {
      const map = new mapmetricsgl.Map({
        container: mapContainerRef.current,
        style: styleUrl,
        center: [longitude, latitude],
        zoom: 12
      });

      // Handle map load success
      map.on('load', () => {
        setLoading(false);
        setError(null);
      });

      // Handle CRITICAL errors only (authentication, style loading failures)
      // Ignore non-critical errors like individual tile loading failures
      map.on('error', (e) => {
        console.error('Map error:', e);

        // Only show UI errors for critical failures that prevent map from working
        // Ignore tile loading errors and other minor issues that don't break the map
        const isCriticalError =
          e.error?.status === 401 ||
          e.error?.message?.includes('401') ||
          (e.error?.message?.includes('Failed to fetch') && !loading) === false ||
          (e.sourceId === undefined && e.error); // Style loading errors have no sourceId

        if (isCriticalError) {
          setLoading(false);

          // Authentication errors (401)
          if (e.error?.message?.includes('401') || e.error?.status === 401) {
            setError('❌ Invalid API token. Get a valid token from https://portal.mapmetrics.org/');
          }
          // Network/style URL errors during initial load
          else if (e.error?.message?.includes('Failed to fetch') && loading) {
            setError('❌ Cannot load map style. Check your style URL from https://portal.mapmetrics.org/');
          }
          // Generic critical error before map loads
          else if (loading) {
            setError('❌ Map failed to load. Check your style URL and token at https://portal.mapmetrics.org/');
          }
          // If map already loaded, just log the error (don't hide the map)
          else {
            console.warn('Map error after load (non-critical):', e);
          }
        } else {
          // Non-critical errors (tile loading, etc.) - just log them
          console.warn('Non-critical map error:', e);
        }
      });

      mapRef.current = map;

      return () => {
        if (map) {
          map.remove();
          mapRef.current = null;
        }
      };
    } catch (err) {
      console.error('Map initialization error:', err);
      setError('❌ Failed to initialize map. Check your style URL from https://portal.mapmetrics.org/');
      setLoading(false);
    }
  }, []);

  // Display error message if something went wrong
  if (error) {
    return (
      <div style={{
        height: '500px',
        width: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#f8d7da',
        color: '#721c24',
        padding: '20px',
        textAlign: 'center',
        fontSize: '16px',
        border: '2px solid #f5c6cb',
        borderRadius: '8px',
        fontFamily: 'system-ui, -apple-system, sans-serif'
      }}>
        <div>
          <strong>{error}</strong>
          <div style={{ marginTop: '10px', fontSize: '14px' }}>
            Need help? Check the <a href="https://discord.com/invite/uRXQRfbb7d" style={{ color: '#721c24' }}>Discord</a>
          </div>
        </div>
      </div>
    );
  }

  // Optional: Show loading state
  if (loading) {
    return (
      <div style={{
        height: '500px',
        width: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#f0f0f0'
      }}>
        Loading map...
      </div>
    );
  }

  return <div ref={mapContainerRef} style={{ height: '500px', width: '100%' }} />;
}

export default MapComponent;

Pattern 3: Add Marker

javascript
// Vanilla JS
const marker = new mapmetricsgl.Marker()
  .setLngLat([longitude, latitude])
  .addTo(map);

// With popup
const marker = new mapmetricsgl.Marker()
  .setLngLat([longitude, latitude])
  .setPopup(new mapmetricsgl.Popup().setHTML('<h3>Location Name</h3>'))
  .addTo(map);

// Draggable marker
const marker = new mapmetricsgl.Marker({ draggable: true })
  .setLngLat([longitude, latitude])
  .addTo(map);

Pattern 4: REST API Call (Directions)

javascript
// POST request to Directions API
const response = await fetch('https://gateway.mapmetrics-atlas.net/directions/?token=YOUR_TOKEN', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    locations: [
      { lat: 40.744014, lon: -73.990508 },
      { lat: 40.752522, lon: -73.985015 }
    ],
    costing: 'auto'
  })
});

const data = await response.json();
// data.trip contains route information

Pattern 5: Geocoding (Forward)

javascript
// GET request to Forward Geocode API
const address = encodeURIComponent('1600 Pennsylvania Avenue NW, Washington, DC');
const response = await fetch(
  `https://gateway.mapmetrics-atlas.net/forward-geocode/?token=YOUR_TOKEN&text=${address}`
);

const data = await response.json();
// data.features[0].geometry.coordinates contains [lon, lat]

Pattern 6: Matrix API

javascript
// POST request to Matrix API
const response = await fetch('https://gateway.mapmetrics-atlas.net/matrix/?token=YOUR_TOKEN', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    sources: [
      { lat: 40.744014, lon: -73.990508 },
      { lat: 40.739735, lon: -73.979713 }
    ],
    targets: [
      { lat: 40.752522, lon: -73.985015 },
      { lat: 40.750117, lon: -73.983704 }
    ],
    costing: 'pedestrian'
  })
});

const data = await response.json();
// data.sources_to_targets contains time/distance matrix

📊 API Response Structures

Directions Response

json
{
  "trip": {
    "locations": [...],
    "legs": [
      {
        "maneuvers": [
          {
            "instruction": "Turn right onto Main Street",
            "time": 45.2,
            "length": 0.542
          }
        ],
        "summary": {
          "time": 18734.567,
          "length": 453.211
        }
      }
    ],
    "summary": {
      "time": 18734.567,
      "length": 453.211
    },
    "units": "kilometers"
  }
}

Geocoding Response

json
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [longitude, latitude]
      },
      "properties": {
        "name": "Location Name",
        "label": "Full Address",
        "country": "Country Name"
      }
    }
  ]
}

Matrix Response (Verbose)

json
{
  "sources_to_targets": [
    [
      {
        "distance": 1.342,
        "time": 294,
        "from_index": 0,
        "to_index": 0
      }
    ]
  ],
  "units": "kilometers"
}

🔑 Important Notes for Code Generation

1. Token Handling - CRITICAL ⚠️

EVERY generated code example MUST include token instructions!

What Happens Without a Token:

  • ❌ Map fails to load (shows blank/error)
  • ❌ API returns 401 Unauthorized
  • ❌ Console errors: "Token required"
  • ❌ User gets frustrated and blames MapMetrics

Required Token Instructions Template:

ALWAYS include this in your response:

⚠️ IMPORTANT: You need an API key to use MapMetrics!

1. Get your free API key at: https://portal.mapmetrics.org/
2. Replace 'YOUR_STYLE_URL_WITH_TOKEN' in the code with your actual style URL
3. The style URL from the portal already includes your token

Without a valid token, the map will not load!

Token Best Practices:

  • NEVER expose real tokens in generated code
  • ALWAYS use placeholder: YOUR_STYLE_URL_WITH_TOKEN or YOUR_API_TOKEN
  • ALWAYS include the portal link: https://portal.mapmetrics.org/
  • ALWAYS explain that the style URL includes the token
  • ALWAYS add a warning comment in the code

Example Code Comment:

javascript
// ⚠️ REPLACE THIS with your actual style URL from https://portal.mapmetrics.org/
style: 'YOUR_STYLE_URL_WITH_TOKEN'

2. NPM Package Name - CRITICAL ⚠️

ALWAYS use the correct package name!

bash
# ✅ CORRECT
npm install @mapmetrics/mapmetrics-gl

# ❌ WRONG - DO NOT USE!
npm install maplibre-gl  # This will NOT work with MapMetrics!
javascript
// ✅ CORRECT imports
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

// ❌ WRONG - DO NOT USE!
import maplibregl from 'maplibre-gl';  // Wrong package!

3. React Patterns

  • ALWAYS use useRef for map container
  • ALWAYS use useRef for map instance
  • ALWAYS cleanup in useEffect return
  • NEVER create map if it already exists
  • ALWAYS use @mapmetrics/mapmetrics-gl, NEVER maplibre-gl

4. Coordinate Format

  • MapMetrics uses: [longitude, latitude] (NOT lat/lon)
  • API requests use: {lat: number, lon: number} objects
  • Be consistent based on context

5. Error Handling

javascript
// Always include error handling
try {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  const data = await response.json();
} catch (error) {
  console.error('API request failed:', error);
}

6. Costing Models

Valid values: auto, bicycle, pedestrian, bus, truck, taxi, motor_scooter

7. Units

  • Distance: km (default) or miles / mi
  • Time: always in seconds
  • Coordinates: decimal degrees

📚 Machine-Readable References

OpenAPI Schema

Complete REST API specification: /public/openapi.yaml

Capabilities Index

Structured capabilities data: /public/ai-capabilities.json

Example Files

All examples include:

  • YAML frontmatter with metadata
  • Complete JavaScript implementation
  • Complete React implementation
  • Copy-paste ready code

🎓 Example Code Generation Flow

User Request: "Create a map with a draggable marker and popup in React"

AI Response Steps:

  1. Identify capabilities: React integration + Markers + Popups
  2. Reference examples: /sdk/examples/react-map-example, /sdk/examples/add-a-marker, /sdk/examples/add-a-popup
  3. Combine patterns into working code
  4. Include proper imports, refs, cleanup
  5. Add placeholder for style URL
  6. Remind user to get API key

⚡ Quick Command Reference

bash
# NPM Installation - ALWAYS USE THIS PACKAGE NAME!
npm install @mapmetrics/mapmetrics-gl

# ❌ WRONG - DO NOT USE
npm install maplibre-gl  # This is NOT MapMetrics!

# Import in JavaScript
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

# ❌ WRONG imports
import maplibregl from 'maplibre-gl';  # Wrong!

# CDN Links
<link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
<script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>

🚨 Common Pitfalls to Avoid

  1. Don't use maplibre-gl package - ALWAYS use @mapmetrics/mapmetrics-gl
  2. Don't create multiple map instances in React
  3. Don't forget to cleanup map in useEffect return
  4. Don't mix up [lon, lat] vs {lat, lon} formats
  5. Don't forget token in API requests
  6. Don't hardcode real tokens in examples
  7. Don't generate code without clear token instructions

🔧 Troubleshooting Guide

Problem: Map doesn't load (blank screen)

Most Common Cause: Missing or Invalid Token

javascript
// ❌ WRONG - Will not work
const map = new mapmetricsgl.Map({
  container: 'map',
  style: 'YOUR_STYLE_URL_WITH_TOKEN',  // Placeholder not replaced!
  center: [0, 0],
  zoom: 10
});

Solution:

javascript
// ✅ CORRECT - User must replace with actual URL from portal
const map = new mapmetricsgl.Map({
  container: 'map',
  // Get this URL from https://portal.mapmetrics.org/
  style: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_ID/style.json&token=YOUR_TOKEN',
  center: [0, 0],
  zoom: 10
});

Error Messages to Watch For:

  • 401 Unauthorized → Missing or invalid token
  • Token required → Token not provided in request
  • Map container blank → Check console for token errors

Problem: REST API returns 401

Cause: Missing token parameter

javascript
// ❌ WRONG
fetch('https://gateway.mapmetrics-atlas.net/directions/', {
  method: 'POST',
  body: JSON.stringify({...})
});

// ✅ CORRECT
fetch('https://gateway.mapmetrics-atlas.net/directions/?token=YOUR_TOKEN', {
  method: 'POST',
  body: JSON.stringify({...})
});

User Doesn't Have a Token Yet

When user says "create a map" without mentioning a token:

Your response MUST include:

  1. Working code with placeholder
  2. Clear instructions to get token
  3. Link to portal
  4. Explanation that map won't work without it

Example Response Template:

Here's the code to create a map:

[code with placeholder]

⚠️ IMPORTANT: Before this works, you need to:
1. Sign up at https://portal.mapmetrics.org/ (free)
2. Get your map style URL (includes API token)
3. Replace 'YOUR_STYLE_URL_WITH_TOKEN' in the code above

The map will NOT load without a valid token!

✅ Best Practices

  1. Always include complete, working examples
  2. Always include both JavaScript and React versions when applicable
  3. Always remind users about API key requirement
  4. Always include error handling
  5. Always use proper React patterns (refs, cleanup)
  6. Always include CSS for map container
  7. Always link to relevant documentation sections

📖 Additional Resources


Last Updated: 2026-02-16 Documentation Version: 1.0.0 Optimized for: Claude, ChatGPT, Gemini, and other AI coding assistants