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_TOKENas 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-gldirectly will NOT work with MapMetrics style URLs - Always use
@mapmetrics/mapmetrics-glfor 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
.htmlextension to URLs - ❌ Don't use
/web-sdk/directory
📋 Available Capabilities
Web SDK (JavaScript/React)
- Simple Map Setup: /sdk/examples/simple-map-cdn, /sdk/examples/simple-map-npm
- React Integration: /sdk/examples/react-map-example
- Markers: /sdk/examples/add-a-marker
- Popups: /sdk/examples/add-a-popup
- Clustering: /sdk/examples/add-a-cluster
- Heatmaps: /sdk/examples/add-a-heatmap
- 3D Buildings: /sdk/examples/3d-building
REST APIs
- Geocoding: /overview/geocoder/forwardgeocode, /overview/geocoder/reversegeocode
- Directions: /overview/directions/directions
- Matrix: /overview/directions/matrix
- Isochrone: /overview/directions/isochrone
- Optimization: /overview/directions/optimization
- Elevation: /overview/directions/elevation
⚠️ PACKAGE NAMING - READ THIS FIRST!
The #1 mistake AI tools make: Using the wrong package!
Correct Package
npm install @mapmetrics/mapmetrics-glimport mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';WRONG Package (DO NOT USE!)
# ❌ This is MapLibre, NOT MapMetrics!
npm install maplibre-gl// ❌ 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-glwill cause authentication errors and missing features - The packages are NOT interchangeable
Quick Check
✅ Correct code always has:
- Package:
@mapmetrics/mapmetrics-gl - Import:
mapmetricsgl(notmaplibregl) - NPM link: https://www.npmjs.com/package/@mapmetrics/mapmetrics-gl
❌ Wrong code has:
- Package:
maplibre-glor@maplibre/maplibre-gl - Import:
maplibregl
🎯 Common Code Patterns
Pattern 1: Basic Map (Vanilla JS with CDN - With Error Handling)
<!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)
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
// 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)
// 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 informationPattern 5: Geocoding (Forward)
// 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
// 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
{
"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
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [longitude, latitude]
},
"properties": {
"name": "Location Name",
"label": "Full Address",
"country": "Country Name"
}
}
]
}Matrix Response (Verbose)
{
"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_TOKENorYOUR_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:
// ⚠️ 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!
# ✅ CORRECT
npm install @mapmetrics/mapmetrics-gl
# ❌ WRONG - DO NOT USE!
npm install maplibre-gl # This will NOT work with MapMetrics!// ✅ 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
useReffor map container - ALWAYS use
useReffor map instance - ALWAYS cleanup in
useEffectreturn - NEVER create map if it already exists
- ALWAYS use
@mapmetrics/mapmetrics-gl, NEVERmaplibre-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
// 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) ormiles/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:
- Identify capabilities: React integration + Markers + Popups
- Reference examples:
/sdk/examples/react-map-example,/sdk/examples/add-a-marker,/sdk/examples/add-a-popup - Combine patterns into working code
- Include proper imports, refs, cleanup
- Add placeholder for style URL
- Remind user to get API key
⚡ Quick Command Reference
# 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
- ❌ Don't use
maplibre-glpackage - ALWAYS use@mapmetrics/mapmetrics-gl - ❌ Don't create multiple map instances in React
- ❌ Don't forget to cleanup map in useEffect return
- ❌ Don't mix up [lon, lat] vs {lat, lon} formats
- ❌ Don't forget token in API requests
- ❌ Don't hardcode real tokens in examples
- ❌ Don't generate code without clear token instructions
🔧 Troubleshooting Guide
Problem: Map doesn't load (blank screen)
Most Common Cause: Missing or Invalid Token
// ❌ 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:
// ✅ 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 tokenToken required→ Token not provided in request- Map container blank → Check console for token errors
Problem: REST API returns 401
Cause: Missing token parameter
// ❌ 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:
- Working code with placeholder
- Clear instructions to get token
- Link to portal
- 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
- ✅ Always include complete, working examples
- ✅ Always include both JavaScript and React versions when applicable
- ✅ Always remind users about API key requirement
- ✅ Always include error handling
- ✅ Always use proper React patterns (refs, cleanup)
- ✅ Always include CSS for map container
- ✅ Always link to relevant documentation sections
📖 Additional Resources
- Portal: https://portal.mapmetrics.org/ (Get API keys)
- NPM Package: https://www.npmjs.com/package/@mapmetrics/mapmetrics-gl
- Discord: https://discord.com/invite/uRXQRfbb7d
- Migration Guides: See
/overview/migration-guide
Last Updated: 2026-02-16 Documentation Version: 1.0.0 Optimized for: Claude, ChatGPT, Gemini, and other AI coding assistants