# Mapsi API Documentation for LLMs # Last Updated: April 2026 # Base URL: https://mapsi.dev ## Overview Mapsi provides enterprise-grade geocoding and mapping APIs with global coverage. All APIs support worldwide address search. Country codes are OPTIONAL. All API endpoints use the /v1/ prefix. ## Authentication All requests require an API key in the header: X-API-Key: your_api_key_here ## Rate Limits | Plan | Rate Limit | Daily Limit | Batch Size (Geocode) | |------------|-------------|----------------|----------------------| | Free | 2 req/sec | 1,000/day | 10 records | | Growth | 15 req/sec | 35,000/day | 5,000 records | | Business | 25 req/sec | 140,000/day | 30,000 records | | Enterprise | 100 req/sec | Custom | 100,000 records | --- ## API Endpoints ### 1. Geocoding API (Forward Geocode) Convert addresses to coordinates. **Endpoint:** GET /v1/geocode **Parameters:** - q (required): Address or place name to geocode - countries (optional): Comma-separated ISO country codes (max 4). Example: FR,DE - limit (optional): Max results (default: 5, max: 25) - lang (optional): Response language (default: en) **Example:** ``` GET /v1/geocode?q=Eiffel+Tower+Paris&limit=5 X-API-Key: YOUR_API_KEY ``` **Response:** Mapsi JSON response with results array. **Example Response:** ```json { "success": true, "results": [ { "formatted_address": "Tour-Eiffel, Paris, France", "city": "Paris", "country_code": "FR", "country": "France", "coordinates": { "lat": 48.859902, "lon": 2.293029 }, "lat": 48.859902, "lon": 2.293029, "confidence": 1, "layer": "venue", "source": "openstreetmap" } ], "query": "eiffel tower paris", "total_results": 1, "lang": "en" } ``` --- ### 2. Places Autocomplete API Get real-time place suggestions as users type. **Endpoint:** GET /v1/autocomplete **Parameters:** - text (required): Partial address or place name - countries (optional): Comma-separated ISO country codes (max 4) - limit (optional): Max suggestions (default: 5, max: 10) - focus.lat / focus.lon (optional): Bias results toward this location **Example:** ``` GET /v1/autocomplete?text=main+str&limit=5 X-API-Key: YOUR_API_KEY ``` **Caching:** Results cached at app layer (60s) and CDN edge (30s). No credits charged on cache hit. **Example Response:** ```json { "success": true, "suggestions": [ { "text": "Main Street, Springfield, IL, USA", "place_id": "mapsi_way/12345", "main_text": "Main Street", "secondary_text": "Springfield, IL, USA", "type": "street", "coordinates": { "lat": 39.7817, "lon": -89.6501 }, "confidence": 0.9 } ], "query": "main str", "total_results": 1 } ``` --- ### 3. Reverse Geocoding API Convert coordinates to structured address components. **Endpoint:** GET /v1/reverse **Parameters:** - lat (required): Latitude coordinate (-90 to 90) - lon (required): Longitude coordinate (-180 to 180) - limit (optional): Max results (default: 1, max: 10) - countries (optional): Filter to specific country **Example:** ``` GET /v1/reverse?lat=48.8584&lon=2.2945 X-API-Key: YOUR_API_KEY ``` --- ### 4. Places API Search a global POI dataset by keyword and proximity. **Endpoint:** GET /v1/places **Parameters:** - q (required): Search keyword (e.g., "restaurant", "hospital") - lat (required): Centre latitude for proximity search - lon (required): Centre longitude for proximity search - limit (optional): Max results (default: 10, max: 20) - radius (optional): Search radius in metres - countries (optional): Filter to specific country **Example:** ``` GET /v1/places?q=cafe&lat=48.8584&lon=2.2945 X-API-Key: YOUR_API_KEY ``` --- ### 5. Batch Geocoding API Geocode up to 30,000 addresses asynchronously in a single request. **Endpoint:** POST /v1/batch/geocode **Request Body (JSON):** - addresses (required): Array of address strings - countries (optional): Comma-separated ISO country codes - limit (optional): Results per address (default: 1) **Example:** ``` POST /v1/batch/geocode Content-Type: application/json X-API-Key: YOUR_API_KEY { "addresses": ["Eiffel Tower, Paris", "Big Ben, London"], "limit": 1 } ``` **Note:** Synchronous — returns results directly in the response. **Batch size limits by plan:** - Free: 10 records - Growth: 5,000 records - Business: 30,000 records - Enterprise: 100,000 records --- ### 6. Reverse Batch Geocoding API Convert multiple coordinate pairs into structured addresses in a single synchronous request. **Endpoint:** POST /v1/batch/reverse **Request Body (JSON):** - points (required): Array of objects with lat and lon properties - points[].lat (required): Latitude (-90 to 90) - points[].lon (required): Longitude (-180 to 180) - points[].id (optional): Client-provided ID returned in response for matching **Batch size limits by plan:** - Free: 10 points - Growth: 250 points - Business: 500 points - Enterprise: 1,000 points **Credits:** 1 credit per 2 points (rounded up). 100 points = 50 credits. **Example:** ``` POST /v1/batch/reverse Content-Type: application/json X-API-Key: YOUR_API_KEY { "points": [ {"lat": 48.8584, "lon": 2.2945, "id": "paris"}, {"lat": 51.5074, "lon": -0.1278, "id": "london"}, {"lat": 40.7128, "lon": -74.0060, "id": "nyc"} ] } ``` **Response:** ```json { "success": true, "points_count": 3, "success_count": 3, "fail_count": 0, "results": [ { "index": 0, "id": "paris", "lat": 48.8584, "lon": 2.2945, "success": true, "address": "Champ de Mars, Paris, France", "components": { "street": "Champ de Mars", "city": "Paris", "country": "France", "country_code": "FR", "postcode": "75007" }, "confidence": 0.9 } ] } ``` **Note:** Synchronous — results returned directly, no polling required. --- ### 7. Point-in-Polygon API (Admin Hierarchy) Resolve the full administrative hierarchy for any coordinate using Who's On First boundary data. **Endpoint:** GET /v1/pip **Parameters:** - lat (required): Latitude (-90 to 90) - lon (required): Longitude (-180 to 180) **Example:** ``` GET /v1/pip?lat=48.8584&lon=2.2945 X-API-Key: YOUR_API_KEY ``` **Response Fields:** - continent: Continent name - country: Country name - country_code: ISO 3166-1 alpha-2 code (e.g., "FR") - region: State or province - locality: City or town - neighbourhood: Neighbourhood name (where available) **Response Example:** ```json { "success": true, "coordinates": { "lat": 48.8584, "lon": 2.2945 }, "hierarchy": { "continent": { "name": "Europe" }, "country": { "name": "France", "abbr": "FRA" }, "state": { "name": "Paris", "abbr": "VP" }, "city": { "name": "Paris" }, "neighbourhood": { "name": "Gros Caillou" } }, "country": "France", "country_code": "FRA", "state": "Paris", "city": "Paris", "neighbourhood": "Gros Caillou" } ``` --- ### 8. Timezone API Resolve the IANA timezone identifier and UTC offset for any coordinate. **Endpoint:** GET /v1/timezone **Parameters:** - lat (required): Latitude (-90 to 90) - lon (required): Longitude (-180 to 180) **Example:** ``` GET /v1/timezone?lat=48.8584&lon=2.2945 X-API-Key: YOUR_API_KEY ``` **Response Fields:** - timezone: IANA timezone identifier (e.g., "Europe/Paris") - utc_offset: Current UTC offset (e.g., "+01:00") - dst: Whether DST is currently active (boolean) - current_time: Human-readable current time in that timezone **Response Example:** ```json { "success": true, "coordinates": { "lat": 48.8584, "lon": 2.2945 }, "timezone": "Europe/Paris", "utc_offset": "+01:00", "dst": true, "current_time": "Wednesday, March 11, 2026 at 2:00:04 PM GMT+1" } ``` --- ### 9. Address Normalization API Parse raw address strings into structured components and normalised variants using the Libpostal engine. **Endpoint:** POST /v1/normalize **Request Body (JSON):** - address (required): Raw address string to parse and normalise **Example:** ``` POST /v1/normalize Content-Type: application/json X-API-Key: YOUR_API_KEY {"address": "123 main st new york ny 10001"} ``` **Response Fields:** - parsed: Object with structured address components (house_number, road, city, state, postcode, country) - normalized: Array of normalised address string variants (Libpostal expansions) - input: Original address string supplied **Response Example:** ```json { "success": true, "input": "123 main st new york ny 10001", "parsed": { "house_number": "123", "road": "main street", "city": "new york", "state": "ny", "postcode": "10001" }, "normalized": [ "123 main street new york new york 10001", "123 main street new york ny 10001" ] } ``` **Use Case:** Run addresses through /v1/normalize before sending to batch geocoding to improve match rates. Libpostal handles abbreviations (St → Street), transliterations, and international address formats. --- ### 10. Static Maps API Generate static map images (PNG) with optional markers. **Endpoint:** GET /v1/static-map **Parameters:** - lat (required): Centre latitude - lon (required): Centre longitude - zoom (optional): Zoom level 1–18 (default: 13) - width (optional): Image width in pixels (default: 600) - height (optional): Image height in pixels (default: 400) - marker (optional): Add a marker at lat,lon **Example:** ``` GET /v1/static-map?lat=48.8584&lon=2.2945&zoom=15&width=600&height=400 X-API-Key: YOUR_API_KEY ``` --- ### 11. Map Tiles API Global vector tiles (PBF) served via the Protomaps/Martin tile server. Compatible with MapLibre GL, Leaflet, and OpenLayers. **Endpoints:** - GET /v1/tiles — tile service info and TileJSON (1 credit per call) - GET /v1/tiles/sources — list available tile sources - GET /v1/tiles/planet/{z}/{x}/{y}?key={api_key} — API-key-authenticated tile endpoint (browser-direct, no server proxy needed) - GET /v1/tiles/styles?style={name} — get a complete MapLibre GL style JSON with fonts, sprites, and tile URLs pre-configured (auth required) **API key required for all tile and style endpoints.** Pass via X-API-Key header or ?key= query parameter. **Tile URL (browser-direct):** ``` GET /v1/tiles/planet/{z}/{x}/{y}?key=YOUR_API_KEY ``` Tiles are authenticated using the standard API key. No server-side proxy required. Individual tile fetches are not separately metered — 1 credit is charged per /v1/tiles TileJSON fetch (map session). **Style endpoint — one URL, everything included:** ``` GET /v1/tiles/styles?style=light&key=YOUR_API_KEY ``` The style response embeds the API key in all tile URLs. Pass the URL directly to MapLibre as the style property — no extra configuration needed. **Simplest possible MapLibre integration:** ```js new maplibregl.Map({ container: 'map', style: 'https://mapsi.dev/v1/tiles/styles?style=light&key=YOUR_API_KEY' }) ``` **Available Styles (GET /v1/tiles/styles?style={name}):** - light — clean light theme, protomaps-calibrated (default) - dark — dark navy theme, protomaps-calibrated - white — minimal white, protomaps-calibrated, ideal for data overlays - grayscale — fully desaturated, protomaps-calibrated, ideal for analytics/print - black — dark minimal, protomaps-calibrated, high contrast - streets — road-focused, colour-coded highways (orange motorways, yellow majors), custom - topo — topographic paper-map aesthetic, earthy tones, custom - liberty — 3D building extrusion at zoom 14+, vibrant road colours, custom **Fonts (public, no auth):** ``` GET /fonts/{fontstack}/{range}.pbf ``` MapLibre glyphs URL: https://mapsi.dev/fonts/{fontstack}/{range}.pbf Self-hosted OpenMapTiles v4.0.0 fonts (57 families). No external CDN dependency. Available Noto Sans variants: Noto Sans Regular, Noto Sans Bold, Noto Sans Italic. Note: the style endpoint automatically substitutes any font not on disk (e.g. Noto Sans Medium → Noto Sans Bold). Clients always receive a fully working style — no font configuration required. **Sprites (public, no auth):** ``` GET /sprites/v1/{theme}.png (and .json, @2x.png, @2x.json) ``` MapLibre sprite base URL: https://mapsi.dev/sprites/v1/{theme} Protomaps v4 sprite sheet — POI icons (hospitals, bus stops, shops, temples, etc.) All four file variants (.png, .json, @2x.png, @2x.json) are served for all 5 themes (light, dark, white, grayscale, black). **Style response format:** Cache-Control: private, no-store (response contains caller's API key in tile URLs) Content-Type: application/json Full MapLibre GL Style Spec v8 object with sources, layers, glyphs, and sprite pre-filled. --- ## Response Format ### Geocoding APIs (geocode, reverse) Return Mapsi JSON with results array: ```json { "success": true, "results": [ { "formatted_address": "Eiffel Tower, Paris, France", "house_number": null, "street": null, "city": "Paris", "region": "Paris", "country_code": "FR", "country": "France", "coordinates": { "lat": 48.859902, "lon": 2.293029 }, "lat": 48.859902, "lon": 2.293029, "confidence": 1, "accuracy": "point", "layer": "venue", "source": "openstreetmap" } ], "query": "eiffel tower paris", "total_results": 1, "lang": "en" } ``` ### Autocomplete API Returns suggestions array: ```json { "success": true, "suggestions": [ { "text": "Eiffel Tower, Paris, France", "place_id": "mapsi_node/4532598850", "main_text": "Eiffel Tower", "secondary_text": "Paris, France", "type": "venue", "coordinates": { "lat": 48.859902, "lon": 2.293029 }, "confidence": 1 } ], "query": "eiffel tow", "total_results": 1 } ``` ### Error Response ```json { "success": false, "error": "Missing required parameter: q (query)", "code": "MISSING_QUERY" } ``` --- ## Response Headers (all authenticated endpoints) - X-RateLimit-Limit: Max requests per second for your plan - X-RateLimit-Remaining: Remaining requests in current window - X-RateLimit-Reset: Unix timestamp when the limit resets - X-RateLimit-Burst: Burst capacity - X-Credits-Remaining: Credits remaining in your account --- ## Country Codes Country codes use ISO 3166-1 alpha-2 format (2-letter codes). Examples: US, GB, FR, DE, IT, ES, NL, BE, CH, AT, AU, CA, IN, JP, CN, BR **Note:** Country codes are OPTIONAL for all APIs. If omitted, search is global. --- ## Code Examples ### JavaScript — Reverse Batch Geocoding ```javascript const response = await fetch('https://mapsi.dev/v1/batch/reverse', { method: 'POST', headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ points: [ { lat: 48.8584, lon: 2.2945 }, { lat: 51.5074, lon: -0.1278 } ] }) }); const data = await response.json(); data.results.forEach(r => console.log(r.address)); ``` ### JavaScript — Point-in-Polygon ```javascript const response = await fetch( 'https://mapsi.dev/v1/pip?lat=48.8584&lon=2.2945', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); console.log(data.country, data.region, data.locality); ``` ### JavaScript — Timezone ```javascript const response = await fetch( 'https://mapsi.dev/v1/timezone?lat=48.8584&lon=2.2945', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); console.log(data.timezone); // "Europe/Paris" console.log(data.utc_offset); // "+01:00" console.log(data.dst); // true console.log(data.current_time); ``` ### JavaScript — Address Normalization ```javascript const response = await fetch('https://mapsi.dev/v1/normalize', { method: 'POST', headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ address: '123 main st new york ny 10001' }) }); const data = await response.json(); console.log(data.parsed.road); // "main street" console.log(data.normalized[0]); // "123 main street new york ny 10001" ``` ### Python — Reverse Batch Geocoding ```python import requests response = requests.post( "https://mapsi.dev/v1/batch/reverse", json={"points": [{"lat": 48.8584, "lon": 2.2945}, {"lat": 51.5074, "lon": -0.1278}]}, headers={"X-API-Key": "YOUR_API_KEY"} ) for r in response.json()["results"]: print(f"{r['lat']},{r['lon']} -> {r['address']}") ``` ### Python — Point-in-Polygon ```python import requests response = requests.get( "https://mapsi.dev/v1/pip", params={"lat": 48.8584, "lon": 2.2945}, headers={"X-API-Key": "YOUR_API_KEY"} ) data = response.json() print(f"{data['country']} / {data['region']} / {data['locality']}") ``` ### Python — Timezone ```python import requests response = requests.get( "https://mapsi.dev/v1/timezone", params={"lat": 48.8584, "lon": 2.2945}, headers={"X-API-Key": "YOUR_API_KEY"} ) data = response.json() print(f"Timezone: {data['timezone']}, Offset: {data['utc_offset']}") ``` ### Python — Address Normalization ```python import requests response = requests.post( "https://mapsi.dev/v1/normalize", json={"address": "123 main st new york ny 10001"}, headers={"X-API-Key": "YOUR_API_KEY"} ) data = response.json() print(data["parsed"]) # {'house_number': '123', 'road': 'main street', ...} print(data["normalized"]) # ['123 main street new york ny 10001', ...] ``` --- --- ## Coming Soon APIs The following APIs are in development and not yet available. Do not attempt to call these endpoints — they will return errors until released. Documentation below reflects the planned API design. --- ### Route API [COMING SOON] Point-to-point routing for car, truck, bicycle, and pedestrian profiles. Returns turn-by-turn directions, total distance, duration, and full route geometry in GeoJSON LineString format. Supports multi-stop waypoints. **Endpoint:** GET /v1/route **Parameters:** - origin (required): Comma-separated lat,lon of the start point. Example: 48.8584,2.2945 - destination (required): Comma-separated lat,lon of the end point. Example: 51.5074,-0.1278 - waypoints (optional): Pipe-separated intermediate stops. Example: 50.8503,4.3517|47.3769,8.5417 - profile (optional): Routing profile. Options: car (default), truck, bicycle, pedestrian - steps (optional): Include turn-by-turn instructions (default: true) - geometry (optional): Route geometry format. Options: geojson (default), polyline - lang (optional): Language for turn instructions (default: en) - units (optional): Distance units. Options: metric (default), imperial **Example:** ``` GET /v1/route?origin=48.8584,2.2945&destination=51.5074,-0.1278&profile=car X-API-Key: YOUR_API_KEY ``` **Example Response:** ```json { "success": true, "profile": "car", "distance_meters": 457823, "duration_seconds": 14220, "duration_text": "3 hours 57 minutes", "distance_text": "457.8 km", "geometry": { "type": "LineString", "coordinates": [[2.2945, 48.8584], [2.3100, 48.8700], ["..."], [-0.1278, 51.5074]] }, "legs": [ { "distance_meters": 457823, "duration_seconds": 14220, "steps": [ { "instruction": "Head north on Champ de Mars", "distance_meters": 320, "duration_seconds": 38, "maneuver": "depart", "road_name": "Champ de Mars" }, { "instruction": "Turn right onto Quai Branly", "distance_meters": 890, "duration_seconds": 102, "maneuver": "turn_right", "road_name": "Quai Branly" } ] } ], "waypoints": [ {"lat": 48.8584, "lon": 2.2945, "name": "Origin"}, {"lat": 51.5074, "lon": -0.1278, "name": "Destination"} ] } ``` **Credits:** 1 credit per route request regardless of distance or number of waypoints. **JavaScript Example:** ```javascript const response = await fetch( 'https://mapsi.dev/v1/route?origin=48.8584,2.2945&destination=51.5074,-0.1278&profile=car', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); console.log(`Distance: ${data.distance_text}, Duration: ${data.duration_text}`); data.legs[0].steps.forEach(step => console.log(step.instruction)); ``` **Python Example:** ```python import requests response = requests.get( 'https://mapsi.dev/v1/route', params={'origin': '48.8584,2.2945', 'destination': '51.5074,-0.1278', 'profile': 'car'}, headers={'X-API-Key': 'YOUR_API_KEY'} ) data = response.json() print(f"Distance: {data['distance_text']}, Duration: {data['duration_text']}") ``` --- ### Matrix API [COMING SOON] Computes travel times and distances between multiple origin–destination pairs simultaneously, returning a full N×M matrix in a single request. Designed for logistics optimisation, fleet routing, and delivery planning. **Endpoint:** POST /v1/matrix **Request Body (JSON):** - sources (required): Array of objects with lat and lon. Max 25 sources. - targets (required): Array of objects with lat and lon. Max 25 targets. - profile (optional): car (default), truck, bicycle, pedestrian - units (optional): metric (default), imperial **Batch size limits by plan:** - Free: 5×5 (25 pairs) - Growth: 10×10 (100 pairs) - Business: 25×25 (625 pairs) - Enterprise: custom **Example:** ``` POST /v1/matrix Content-Type: application/json X-API-Key: YOUR_API_KEY { "sources": [ {"lat": 48.8584, "lon": 2.2945}, {"lat": 51.5074, "lon": -0.1278} ], "targets": [ {"lat": 52.5200, "lon": 13.4050}, {"lat": 41.9028, "lon": 12.4964} ], "profile": "car" } ``` **Example Response:** ```json { "success": true, "profile": "car", "sources_count": 2, "targets_count": 2, "durations": [ [36540, 12780], [34200, 15360] ], "distances": [ [1041230, 1426500], [1014780, 1438900] ], "durations_text": [ ["10h 9m", "3h 33m"], ["9h 30m", "4h 16m"] ], "sources": [ {"lat": 48.8584, "lon": 2.2945}, {"lat": 51.5074, "lon": -0.1278} ], "targets": [ {"lat": 52.5200, "lon": 13.4050}, {"lat": 41.9028, "lon": 12.4964} ] } ``` **Note:** durations[i][j] = travel time in seconds from source i to target j. distances[i][j] = distance in metres. **Credits:** 1 credit per source-target pair. A 5×5 matrix costs 25 credits. **JavaScript Example:** ```javascript const response = await fetch('https://mapsi.dev/v1/matrix', { method: 'POST', headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ sources: [{ lat: 48.8584, lon: 2.2945 }, { lat: 51.5074, lon: -0.1278 }], targets: [{ lat: 52.5200, lon: 13.4050 }, { lat: 41.9028, lon: 12.4964 }], profile: 'car' }) }); const data = await response.json(); // data.durations[0][1] = seconds from Paris to Rome console.log(`Paris → Rome: ${data.durations_text[0][1]}`); ``` **Python Example:** ```python import requests response = requests.post( 'https://mapsi.dev/v1/matrix', json={ 'sources': [{'lat': 48.8584, 'lon': 2.2945}, {'lat': 51.5074, 'lon': -0.1278}], 'targets': [{'lat': 52.5200, 'lon': 13.4050}, {'lat': 41.9028, 'lon': 12.4964}], 'profile': 'car' }, headers={'X-API-Key': 'YOUR_API_KEY'} ) data = response.json() print(data['durations_text']) # [['10h 9m', '3h 33m'], ['9h 30m', '4h 16m']] ``` --- ### Isochrone API [COMING SOON] Generates reachability polygons (isochrones) showing all areas accessible within specified travel times or distances from an origin point. Returns GeoJSON FeatureCollection with one polygon per contour. **Endpoint:** GET /v1/isochrone **Parameters:** - lat (required): Origin latitude - lon (required): Origin longitude - time (optional): Comma-separated travel time contours in minutes. Example: 10,20,30. Max 5 contours. - distance_km (optional): Comma-separated distance contours in km. Example: 5,10,20. Cannot combine with time. - profile (optional): car (default), bicycle, pedestrian - denoise (optional): Smoothing factor 0.0–1.0 (default: 0.5). Higher = smoother polygons. **Example:** ``` GET /v1/isochrone?lat=48.8584&lon=2.2945&time=10,20,30&profile=car X-API-Key: YOUR_API_KEY ``` **Example Response:** ```json { "success": true, "origin": {"lat": 48.8584, "lon": 2.2945}, "profile": "car", "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "contour_minutes": 10, "color": "#3b82f6", "opacity": 0.33 }, "geometry": { "type": "Polygon", "coordinates": [[[2.1800, 48.8400], [2.2100, 48.9200], ["..."], [2.1800, 48.8400]]] } }, { "type": "Feature", "properties": { "contour_minutes": 20, "color": "#2563eb", "opacity": 0.33 }, "geometry": { "type": "Polygon", "coordinates": [[[2.0500, 48.7800], ["..."], [2.0500, 48.7800]]] } } ] } ``` **Credits:** 1 credit per request regardless of number of contours. **JavaScript Example:** ```javascript const response = await fetch( 'https://mapsi.dev/v1/isochrone?lat=48.8584&lon=2.2945&time=10,20,30&profile=car', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); // data.features is a GeoJSON FeatureCollection — pass directly to MapLibre or Leaflet ``` **Python Example:** ```python import requests response = requests.get( 'https://mapsi.dev/v1/isochrone', params={'lat': 48.8584, 'lon': 2.2945, 'time': '10,20,30', 'profile': 'car'}, headers={'X-API-Key': 'YOUR_API_KEY'} ) geojson = response.json() print(f"Returned {len(geojson['features'])} contour polygons") ``` --- ### Elevation API [COMING SOON] Returns SRTM 30m resolution elevation data (height above sea level in metres) for any coordinate or batch of coordinates. Global coverage including high-altitude and remote regions. **Endpoint:** GET /v1/elevation (single point) — POST /v1/elevation (batch) **Parameters (GET — single point):** - lat (required): Latitude (-90 to 90) - lon (required): Longitude (-180 to 180) **Request Body (POST — batch):** - points (required): Array of objects with lat and lon. Max 512 points per request. **Batch size limits by plan:** - Free: 10 points - Growth: 128 points - Business: 512 points - Enterprise: 2,000 points **Example (single):** ``` GET /v1/elevation?lat=45.8325&lon=6.8652 X-API-Key: YOUR_API_KEY ``` **Example Response (single):** ```json { "success": true, "lat": 45.8325, "lon": 6.8652, "elevation_m": 4808, "source": "srtm30" } ``` **Example (batch):** ``` POST /v1/elevation Content-Type: application/json X-API-Key: YOUR_API_KEY { "points": [ {"lat": 45.8325, "lon": 6.8652}, {"lat": 27.9881, "lon": 86.9250}, {"lat": 48.8584, "lon": 2.2945} ] } ``` **Example Response (batch):** ```json { "success": true, "points_count": 3, "results": [ {"lat": 45.8325, "lon": 6.8652, "elevation_m": 4808, "source": "srtm30"}, {"lat": 27.9881, "lon": 86.9250, "elevation_m": 8849, "source": "srtm30"}, {"lat": 48.8584, "lon": 2.2945, "elevation_m": 54, "source": "srtm30"} ] } ``` **Credits:** 1 credit per point. Single GET = 1 credit. Batch POST = 1 credit per point in the array. **JavaScript Example:** ```javascript // Single point const response = await fetch( 'https://mapsi.dev/v1/elevation?lat=45.8325&lon=6.8652', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); console.log(`Mont Blanc elevation: ${data.elevation_m}m`); // Batch const batchResponse = await fetch('https://mapsi.dev/v1/elevation', { method: 'POST', headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ points: [{ lat: 45.8325, lon: 6.8652 }, { lat: 27.9881, lon: 86.9250 }] }) }); const batch = await batchResponse.json(); batch.results.forEach(p => console.log(`${p.lat},${p.lon} → ${p.elevation_m}m`)); ``` **Python Example:** ```python import requests # Batch elevation lookup response = requests.post( 'https://mapsi.dev/v1/elevation', json={'points': [{'lat': 45.8325, 'lon': 6.8652}, {'lat': 27.9881, 'lon': 86.9250}]}, headers={'X-API-Key': 'YOUR_API_KEY'} ) for pt in response.json()['results']: print(f"{pt['lat']},{pt['lon']} → {pt['elevation_m']}m") ``` --- ### Nearest Road API [COMING SOON] Identifies the closest road segment to any coordinate. Returns the road name, OSM highway classification, posted speed limit (where available), and the precise snapped point on the road geometry. **Endpoint:** GET /v1/nearest-road **Parameters:** - lat (required): Latitude (-90 to 90) - lon (required): Longitude (-180 to 180) - limit (optional): Number of nearest roads to return (default: 1, max: 5) - radius (optional): Search radius in metres (default: 200, max: 2000) **Example:** ``` GET /v1/nearest-road?lat=48.8584&lon=2.2945&limit=1 X-API-Key: YOUR_API_KEY ``` **Example Response:** ```json { "success": true, "input": {"lat": 48.8584, "lon": 2.2945}, "results": [ { "road_name": "Champ de Mars", "ref": null, "highway": "pedestrian", "surface": "paved", "speed_limit_kmh": null, "oneway": false, "snapped_point": {"lat": 48.8582, "lon": 2.2947}, "distance_m": 24.3, "osm_way_id": 4530932, "source": "openstreetmap" } ] } ``` **Response Fields:** - road_name: Street name from OSM (null if unnamed) - ref: Road reference number (e.g., "A1", "M25") - highway: OSM highway classification (motorway, trunk, primary, secondary, residential, pedestrian, etc.) - speed_limit_kmh: Posted speed limit where available in OSM, null otherwise - oneway: Whether the road is one-way - snapped_point: Nearest point on the road geometry - distance_m: Distance in metres from input coordinate to snapped point - osm_way_id: OpenStreetMap way ID for the road segment **Credits:** 1 credit per request. **JavaScript Example:** ```javascript const response = await fetch( 'https://mapsi.dev/v1/nearest-road?lat=48.8584&lon=2.2945', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); const road = data.results[0]; console.log(`${road.road_name} (${road.highway}), ${road.distance_m}m away`); console.log(`Snapped: ${road.snapped_point.lat}, ${road.snapped_point.lon}`); ``` **Python Example:** ```python import requests response = requests.get( 'https://mapsi.dev/v1/nearest-road', params={'lat': 48.8584, 'lon': 2.2945, 'limit': 3}, headers={'X-API-Key': 'YOUR_API_KEY'} ) for road in response.json()['results']: print(f"{road['road_name']} ({road['highway']}) — {road['distance_m']}m") ``` --- ### Map Matching API [COMING SOON] Snaps a sequence of raw GPS coordinates to the road network, correcting GPS drift and map-aligning vehicle telemetry into accurate road-following trajectories. Accepts timestamps for speed-aware matching. **Endpoint:** POST /v1/match **Request Body (JSON):** - points (required): Array of GPS point objects. Minimum 2 points, maximum 500 per request. - points[].lat (required): Latitude - points[].lon (required): Longitude - points[].timestamp (optional): Unix timestamp in seconds (enables speed-aware matching) - profile (optional): car (default), bicycle, pedestrian - geometry (optional): Output geometry format. geojson (default), polyline **Batch size limits by plan:** - Free: 50 points - Growth: 200 points - Business: 500 points - Enterprise: 2,000 points **Example:** ``` POST /v1/match Content-Type: application/json X-API-Key: YOUR_API_KEY { "points": [ {"lat": 48.8584, "lon": 2.2945, "timestamp": 1741000000}, {"lat": 48.8591, "lon": 2.2962, "timestamp": 1741000015}, {"lat": 48.8601, "lon": 2.2980, "timestamp": 1741000032} ], "profile": "car" } ``` **Example Response:** ```json { "success": true, "profile": "car", "confidence": 0.94, "distance_meters": 182, "duration_seconds": 32, "matched_points": [ {"lat": 48.8583, "lon": 2.2946, "original_lat": 48.8584, "original_lon": 2.2945, "distance_from_original_m": 1.2}, {"lat": 48.8590, "lon": 2.2963, "original_lat": 48.8591, "original_lon": 2.2962, "distance_from_original_m": 0.8}, {"lat": 48.8600, "lon": 2.2981, "original_lat": 48.8601, "original_lon": 2.2980, "distance_from_original_m": 1.1} ], "matched_roads": [ {"road_name": "Quai Branly", "highway": "primary", "distance_m": 182} ], "geometry": { "type": "LineString", "coordinates": [[2.2946, 48.8583], [2.2963, 48.8590], [2.2981, 48.8600]] } } ``` **Credits:** 1 credit per 10 points (rounded up). 50 points = 5 credits. **JavaScript Example:** ```javascript const response = await fetch('https://mapsi.dev/v1/match', { method: 'POST', headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ points: [ { lat: 48.8584, lon: 2.2945, timestamp: 1741000000 }, { lat: 48.8591, lon: 2.2962, timestamp: 1741000015 }, { lat: 48.8601, lon: 2.2980, timestamp: 1741000032 } ], profile: 'car' }) }); const data = await response.json(); console.log(`Matched ${data.matched_points.length} points with confidence ${data.confidence}`); ``` **Python Example:** ```python import requests response = requests.post( 'https://mapsi.dev/v1/match', json={ 'points': [ {'lat': 48.8584, 'lon': 2.2945, 'timestamp': 1741000000}, {'lat': 48.8591, 'lon': 2.2962, 'timestamp': 1741000015}, {'lat': 48.8601, 'lon': 2.2980, 'timestamp': 1741000032} ], 'profile': 'car' }, headers={'X-API-Key': 'YOUR_API_KEY'} ) data = response.json() print(f"Confidence: {data['confidence']}, Distance: {data['distance_meters']}m") ``` --- ### H3 API [COMING SOON] Converts coordinates to Uber's H3 hexagonal hierarchical grid cell identifiers for spatial aggregation, heatmaps, and density analysis. Supports all H3 resolutions from 0 (coarsest, ~4M km²) to 15 (finest, ~1m²). **Endpoint:** GET /v1/h3 **Parameters:** - lat (required): Latitude (-90 to 90) - lon (required): Longitude (-180 to 180) - resolution (optional): H3 resolution 0–15 (default: 9, approx 0.1 km²) - return_boundary (optional): Include hex cell boundary polygon (default: false) - return_neighbors (optional): Include the 6 neighbouring cell IDs (default: false) **Example:** ``` GET /v1/h3?lat=48.8584&lon=2.2945&resolution=9&return_boundary=true X-API-Key: YOUR_API_KEY ``` **Example Response:** ```json { "success": true, "lat": 48.8584, "lon": 2.2945, "resolution": 9, "cell_id": "891fb466537ffff", "center": {"lat": 48.8581, "lon": 2.2942}, "area_km2": 0.105, "boundary": { "type": "Polygon", "coordinates": [[ [2.2875, 48.8532], [2.2946, 48.8496], [2.3017, 48.8532], [2.3017, 48.8630], [2.2946, 48.8666], [2.2875, 48.8630], [2.2875, 48.8532] ]] } } ``` **Resolution reference (common levels):** - 5: ~252 km² (city scale) - 7: ~5.16 km² (district scale) - 9: ~0.105 km² (neighbourhood scale) — default - 11: ~0.001 km² (block scale) - 13: ~43 m² (building scale) **Credits:** 1 credit per request. **JavaScript Example:** ```javascript const response = await fetch( 'https://mapsi.dev/v1/h3?lat=48.8584&lon=2.2945&resolution=9', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); console.log(`H3 cell: ${data.cell_id} (resolution ${data.resolution})`); console.log(`Area: ${data.area_km2} km²`); ``` **Python Example:** ```python import requests response = requests.get( 'https://mapsi.dev/v1/h3', params={'lat': 48.8584, 'lon': 2.2945, 'resolution': 9}, headers={'X-API-Key': 'YOUR_API_KEY'} ) data = response.json() print(f"H3 cell ID: {data['cell_id']}") print(f"Center: {data['center']['lat']}, {data['center']['lon']}") ``` --- ### Boundary API [COMING SOON] Retrieves administrative boundary polygons in GeoJSON format for any administrative level — country, region/state, county, city, or neighbourhood. Backed by Who's On First and OpenStreetMap boundary data. **Endpoint:** GET /v1/boundary **Parameters:** - name (optional): Place name to look up (e.g., "Paris", "France", "California") - country_code (optional): ISO 3166-1 alpha-2 country code to retrieve country boundary - lat / lon (optional): Coordinate — returns the boundary of the smallest admin unit containing this point - level (optional): Administrative level to return. Options: country, region, county, city, neighbourhood (default: auto — returns smallest containing boundary for lat/lon, or best match for name) - simplified (optional): Return simplified polygon (smaller response, less detail). Default: false. **Note:** At least one of name, country_code, or lat+lon is required. **Example:** ``` GET /v1/boundary?name=Paris&level=city X-API-Key: YOUR_API_KEY ``` **Example Response:** ```json { "success": true, "type": "Feature", "properties": { "name": "Paris", "name_local": "Paris", "level": "city", "country": "France", "country_code": "FR", "region": "Île-de-France", "population": 2161000, "area_km2": 105.4, "wof_id": 101751119, "osm_id": "relation/7444" }, "geometry": { "type": "Polygon", "coordinates": [[[2.2242, 48.8156], [2.4699, 48.8156], [2.4699, 48.9022], [2.2242, 48.9022], [2.2242, 48.8156]]] } } ``` **Credits:** 1 credit per request. **JavaScript Example:** ```javascript // Get boundary of France const response = await fetch( 'https://mapsi.dev/v1/boundary?country_code=FR&level=country', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); // data is a GeoJSON Feature — pass directly to MapLibre or Leaflet // Get boundary containing a coordinate const cityResponse = await fetch( 'https://mapsi.dev/v1/boundary?lat=48.8584&lon=2.2945&level=city', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const city = await cityResponse.json(); console.log(`City: ${city.properties.name}, Area: ${city.properties.area_km2} km²`); ``` **Python Example:** ```python import requests # Boundary by name response = requests.get( 'https://mapsi.dev/v1/boundary', params={'name': 'Berlin', 'level': 'city'}, headers={'X-API-Key': 'YOUR_API_KEY'} ) data = response.json() print(f"{data['properties']['name']}: {data['properties']['area_km2']} km²") ``` --- ### Coverage API [COMING SOON] Queries geocoding data availability and precision levels for specific regions before committing large batch workloads. Returns a quality score, data sources present, and last-updated timestamps per country or bounding box. **Endpoint:** GET /v1/coverage **Parameters:** - country_code (optional): ISO 3166-1 alpha-2 country code - bbox (optional): Bounding box as min_lon,min_lat,max_lon,max_lat (e.g., -0.5,51.3,0.3,51.7) - detail (optional): Level of detail. Options: summary (default), full **Note:** At least one of country_code or bbox is required. **Example:** ``` GET /v1/coverage?country_code=DE X-API-Key: YOUR_API_KEY ``` **Example Response:** ```json { "success": true, "country_code": "DE", "country": "Germany", "overall_score": 0.97, "grade": "A", "address_coverage": { "score": 0.98, "description": "Excellent — near-complete address-level coverage", "sources": ["openaddresses", "openstreetmap"], "record_count_approx": 42000000, "last_updated": "2026-02" }, "poi_coverage": { "score": 0.95, "description": "Excellent — comprehensive POI data", "sources": ["openstreetmap"], "last_updated": "2026-02" }, "road_coverage": { "score": 0.99, "description": "Excellent — complete road network", "sources": ["openstreetmap"], "last_updated": "2026-02" }, "notes": [] } ``` **Coverage grades:** - A (0.90–1.0): Excellent — production-ready for bulk processing - B (0.75–0.89): Good — minor gaps in rural areas - C (0.50–0.74): Moderate — significant rural gaps, urban areas well-covered - D (0.25–0.49): Limited — urban centres only - F (0.0–0.24): Sparse — not recommended for bulk geocoding **Credits:** 1 credit per request. **JavaScript Example:** ```javascript const response = await fetch( 'https://mapsi.dev/v1/coverage?country_code=IN', { headers: { 'X-API-Key': 'YOUR_API_KEY' } } ); const data = await response.json(); console.log(`India geocoding coverage: Grade ${data.grade} (${data.overall_score})`); console.log(`Address records: ~${data.address_coverage.record_count_approx.toLocaleString()}`); ``` **Python Example:** ```python import requests response = requests.get( 'https://mapsi.dev/v1/coverage', params={'country_code': 'IN'}, headers={'X-API-Key': 'YOUR_API_KEY'} ) data = response.json() print(f"Grade: {data['grade']}, Score: {data['overall_score']}") print(f"Address sources: {data['address_coverage']['sources']}") --- ## Support Email: support@mapsi.dev Sales: sales@mapsi.dev Website: https://mapsi.dev Documentation: https://mapsi.dev/docs © 2026 Mapsi.dev — A unit of AlgoLayer Technologies. All rights reserved.