Getting Started

Mapsi provides enterprise-grade geocoding and mapping APIs with global coverage. Our APIs support worldwide address search without requiring country codes.

🌍 Global Coverage

Search addresses worldwide. Country codes are optional - use them to improve accuracy when you know the target region.

Base URL

https://mapsi.dev

Key Features

  • Global Search - No country code required
  • High Accuracy - 90%+ accuracy in major markets
  • Fast Response - Sub-100ms average response time
  • Multiple Languages - Response language support

Authentication

All API requests require authentication using your API key in the request headers:

X-API-Key: your_api_key_here

Get your API key from the Dashboard.

Rate Limits

Rate limits vary by subscription tier:

PlanRate LimitDaily LimitBatch Size
Free2 req/sec1,000/day10 records
Growth15 req/sec35,000/day5,000 records
Business25 req/sec140,000/day30,000 records
Enterprise100 req/secCustom100,000 records

Geocoding API

Convert addresses and place names into geographic coordinates with high accuracy.

Endpoint

GET /v1/geocode

Parameters

ParameterTypeRequiredDescription
qstringYesAddress or place name to geocode
countriesstringNoOptional. Comma-separated ISO country codes (max 4). Example: FR or FR,DE,IT
limitintegerNoMaximum number of results (default: 5, max: 25)
langstringNoResponse language code (default: en). Example: de, fr, es
focus.lat / focus.lonfloatNoBias results toward this location for local relevance

cURL

curl -X GET "https://mapsi.dev/v1/geocode?q=Eiffel+Tower+Paris&limit=5" \
  -H "X-API-Key: YOUR_API_KEY"

# With optional country filter:
curl -X GET "https://mapsi.dev/v1/geocode?q=Eiffel+Tower+Paris&countries=FR&limit=5" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

// Geocode an address (global search)
const response = await fetch(
  'https://mapsi.dev/v1/geocode?q=Eiffel+Tower+Paris&limit=1',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const data = await response.json();

// Extract coordinates from the first result
const { lat, lon } = data.results[0].coordinates;
const address = data.results[0].formatted_address;
console.log(`${address}: ${lat}, ${lon}`);

// With optional country filter
const responseFiltered = await fetch(
  'https://mapsi.dev/v1/geocode?q=Eiffel+Tower+Paris&countries=FR&limit=1',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);

Python

import requests

# Geocode an address (global search - no country filter)
response = requests.get(
    "https://mapsi.dev/v1/geocode",
    params={"q": "Eiffel Tower, Paris", "limit": 1},
    headers={"X-API-Key": "YOUR_API_KEY"}
)
data = response.json()

# Extract coordinates from the first result
result = data["results"][0]
lat = result["coordinates"]["lat"]
lon = result["coordinates"]["lon"]
address = result["formatted_address"]
print(f"{address}: {lat}, {lon}")

# With optional country filter
response = requests.get(
    "https://mapsi.dev/v1/geocode",
    params={"q": "Eiffel Tower, Paris", "countries": "FR", "limit": 1},
    headers={"X-API-Key": "YOUR_API_KEY"}
)

Autocomplete API

Get real-time address suggestions as users type. Perfect for address input forms.

Endpoint

GET /v1/autocomplete

Parameters

ParameterTypeRequiredDescription
textstringYesPartial address or place name (minimum 2 characters)
countriesstringNoOptional. Comma-separated ISO country codes (max 4)
limitintegerNoMaximum number of suggestions (default: 5, max: 10)
focus.lat / focus.lonfloatNoBias results toward this location for local relevance
layersstringNoFilter by type: address, venue, street, locality

cURL

curl -X GET "https://mapsi.dev/v1/autocomplete?text=main+str&limit=5" \
  -H "X-API-Key: YOUR_API_KEY"

# With optional country filter:
curl -X GET "https://mapsi.dev/v1/autocomplete?text=main+str&countries=US&limit=5" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

// Address autocomplete (global search)
const response = await fetch(
  'https://mapsi.dev/v1/autocomplete?text=main+str&limit=5',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const data = await response.json();

// Each suggestion has main_text and secondary_text
const suggestions = data.suggestions.map(s => s.text);
console.log(suggestions);

Python

import requests

# Address autocomplete
response = requests.get(
    "https://mapsi.dev/v1/autocomplete",
    params={"text": "main str", "limit": 5},
    headers={"X-API-Key": "YOUR_API_KEY"}
)
data = response.json()

# Get suggestions
suggestions = [s["text"] for s in data["suggestions"]]
print(suggestions)

Reverse Geocoding API

Convert geographic coordinates back into human-readable addresses.

Endpoint

GET /v1/reverse

Parameters

ParameterTypeRequiredDescription
latfloatYesLatitude coordinate
lonfloatYesLongitude coordinate
countriesstringNoOptional. Comma-separated ISO country codes (max 4)
limitintegerNoMaximum number of results (default: 1, max: 10)
layersstringNoFilter by layer type: address, venue, street, locality

cURL

curl -X GET "https://mapsi.dev/v1/reverse?lat=48.8584&lon=2.2945&limit=5" \
  -H "X-API-Key: YOUR_API_KEY"

# With optional country filter:
curl -X GET "https://mapsi.dev/v1/reverse?lat=48.8584&lon=2.2945&countries=FR" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

// Reverse geocode coordinates
const response = await fetch(
  'https://mapsi.dev/v1/reverse?lat=48.8584&lon=2.2945',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const data = await response.json();

// Get the address from the first result
const address = data.results[0].formatted_address;
console.log(address);

Python

import requests

# Reverse geocode coordinates
response = requests.get(
    "https://mapsi.dev/v1/reverse",
    params={"lat": 48.8584, "lon": 2.2945},
    headers={"X-API-Key": "YOUR_API_KEY"}
)
data = response.json()

# Get address from first result
address = data["results"][0]["formatted_address"]
print(address)

Places API

Find points of interest, businesses, and landmarks near any location.

Endpoint

GET /v1/places

Parameters

ParameterTypeRequiredDescription
qstringYesSearch query (e.g., "coffee", "restaurant", "hospital")
latfloatYesLatitude for search center
lonfloatYesLongitude for search center
radiusintegerNoSearch radius in metres
countriesstringNoOptional. Comma-separated ISO country codes (max 4)
limitintegerNoMaximum number of results (default: 10, max: 20)

cURL

curl -X GET "https://mapsi.dev/v1/places?q=restaurant&lat=48.8584&lon=2.2945&limit=10" \
  -H "X-API-Key: YOUR_API_KEY"

# With optional country filter:
curl -X GET "https://mapsi.dev/v1/places?q=restaurant&lat=48.8584&lon=2.2945&countries=FR" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

// Search for places nearby
const response = await fetch(
  'https://mapsi.dev/v1/places?q=restaurant&lat=48.8584&lon=2.2945',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const data = await response.json();
const places = data.places.map(p => p.name);
console.log(places);

Python

import requests

# Search for places nearby
response = requests.get(
    "https://mapsi.dev/v1/places",
    params={"q": "restaurant", "lat": 48.8584, "lon": 2.2945},
    headers={"X-API-Key": "YOUR_API_KEY"}
)
data = response.json()
places = [p["name"] for p in data["places"]]
print(places)

Static Maps API

Generate static map images with markers and custom styling.

✅ No Country Code Required

The Static Maps API does not require the countries parameter.

Endpoint

GET /v1/static-map

Parameters

ParameterTypeRequiredDescription
centerstringYesMap center as "lat,lon"
zoomintegerYesZoom level (1-20)
sizestringNoImage size as "widthxheight" (default: 600x400)

cURL

curl -X GET "https://mapsi.dev/v1/static-map?lat=48.8584&lon=2.2945&zoom=15&width=600&height=400" \
  -H "X-API-Key: YOUR_API_KEY" \
  --output map.png

JavaScript

// Get static map image URL
const mapUrl = 'https://mapsi.dev/v1/static-map?lat=48.8584&lon=2.2945&zoom=15&width=600&height=400';

// Use in HTML
const img = document.createElement('img');
img.src = mapUrl + '&api_key=YOUR_API_KEY';
document.body.appendChild(img);

Python

import requests

# Download static map image
response = requests.get(
    "https://mapsi.dev/v1/static-map",
    params={"lat": 48.8584, "lon": 2.2945, "zoom": 15, "width": 600, "height": 400},
    headers={"X-API-Key": "YOUR_API_KEY"}
)
with open("map.png", "wb") as f:
    f.write(response.content)

Batch Geocoding API

Process multiple addresses in a single request for high-throughput applications.

Endpoint

POST /v1/batch/geocode

Request Body

FieldTypeRequiredDescription
addressesarrayYesArray of address strings. Max: 5,000 (Growth) or 30,000 (Business)
countriesstringNoOptional. Comma-separated ISO country codes (max 4)
limitintegerNoResults per address (default: 1)

📊 Batch Limits by Plan

Growth: Up to 5,000 records per batch
Business: Up to 30,000 records per batch

cURL

curl -X POST "https://mapsi.dev/v1/batch/geocode" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "addresses": [
      "Eiffel Tower, Paris",
      "Big Ben, London",
      "Colosseum, Rome"
    ],
    "limit": 1
  }'

# With optional country filter:
curl -X POST "https://mapsi.dev/v1/batch/geocode" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "addresses": ["4 Avenue de la Madone, Monaco"],
    "countries": "MC",
    "limit": 1
  }'

JavaScript

// Batch geocode multiple addresses (global search)
const response = await fetch('https://mapsi.dev/v1/batch/geocode', {
  method: 'POST',
  headers: {
    'X-API-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    addresses: [
      'Eiffel Tower, Paris',
      'Big Ben, London',
      'Colosseum, Rome'
    ],
    limit: 1
  })
});
const results = await response.json();
console.log(results);

Python

import requests

# Batch geocode multiple addresses (global search)
response = requests.post(
    "https://mapsi.dev/v1/batch/geocode",
    json={
        "addresses": [
            "Eiffel Tower, Paris",
            "Big Ben, London",
            "Colosseum, Rome"
        ],
        "limit": 1
    },
    headers={"X-API-Key": "YOUR_API_KEY"}
)
results = response.json()
print(results)

Batch Reverse Geocoding API

Convert multiple coordinate pairs into structured addresses in a single synchronous request. Built for fleet tracking, IoT telemetry, and logistics pipelines.

Endpoint

POST /v1/batch/reverse

Request Body

ParameterTypeRequiredDescription
pointsarrayYesArray of objects with lat and lon properties
points[].latnumberYesLatitude (-90 to 90)
points[].lonnumberYesLongitude (-180 to 180)
points[].idstringNoOptional client-provided ID, returned in the response for matching

Batch Size Limits

PlanMax Points per Request
Free10
Growth250
Business500
Enterprise1,000

💡 Credit Charging

Credits are charged at 1 credit per 2 points (rounded up). A 100-point batch costs 50 credits.

cURL

curl -X POST "https://mapsi.dev/v1/batch/reverse" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "points": [
      {"lat": 48.8584, "lon": 2.2945},
      {"lat": 51.5074, "lon": -0.1278},
      {"lat": 40.7128, "lon": -74.0060}
    ]
  }'

JavaScript

// Batch reverse geocode multiple coordinates
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 },
      { lat: 40.7128, lon: -74.0060 }
    ]
  })
});
const data = await response.json();
data.results.forEach(r => console.log(r.address));

Python

import requests

# Batch reverse geocode multiple coordinates
response = requests.post(
    "https://mapsi.dev/v1/batch/reverse",
    json={
        "points": [
            {"lat": 48.8584, "lon": 2.2945},
            {"lat": 51.5074, "lon": -0.1278},
            {"lat": 40.7128, "lon": -74.0060}
        ]
    },
    headers={"X-API-Key": "YOUR_API_KEY"}
)
data = response.json()
for r in data["results"]:
    print(f"{r['lat']},{r['lon']} -> {r['address']}")

Point-in-Polygon API

Resolve the full administrative hierarchy for any coordinate. Returns the country, region, city, and neighbourhood that contain the given point, using Who's On First boundary data.

Endpoint

GET /v1/pip

Parameters

ParameterTypeRequiredDescription
latnumberYesLatitude (-90 to 90)
lonnumberYesLongitude (-180 to 180)

Response Fields

FieldDescription
hierarchyNested object with full admin hierarchy (continent, country, state, city, neighbourhood, etc.)
countryCountry name
country_codeISO 3166-1 alpha-3 country code (e.g., FRA)
stateState or province
cityCity or town
neighbourhoodNeighbourhood name (where available)

cURL

curl -X GET "https://mapsi.dev/v1/pip?lat=48.8584&lon=2.2945" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

// Point-in-Polygon: get admin hierarchy for a coordinate
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);        // "France"
console.log(data.state);          // "Paris"
console.log(data.city);           // "Paris"
console.log(data.neighbourhood);  // "Gros Caillou"

Python

import requests

# Get administrative hierarchy for a coordinate
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"Country: {data['country']}")
print(f"State: {data['state']}")
print(f"City: {data['city']}")
print(f"Neighbourhood: {data['neighbourhood']}")

Timezone API

Resolve the IANA timezone identifier and current UTC offset for any coordinate. DST-aware, with a longitude-based fallback for coordinates outside mapped timezone boundaries.

Endpoint

GET /v1/timezone

Parameters

ParameterTypeRequiredDescription
latnumberYesLatitude (-90 to 90)
lonnumberYesLongitude (-180 to 180)

Response Fields

FieldDescription
timezoneIANA timezone identifier (e.g., Europe/Paris)
utc_offsetCurrent UTC offset (e.g., +01:00)
dstWhether DST is currently active (boolean)
current_timeHuman-readable current time in that timezone

cURL

curl -X GET "https://mapsi.dev/v1/timezone?lat=48.8584&lon=2.2945" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

// Get timezone for a coordinate
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);  // "Thursday, March 12, 2026 at 1:00:00 PM GMT+1"

Python

import requests

# Get timezone for a coordinate
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']}")
print(f"UTC Offset: {data['utc_offset']}")
print(f"DST Active: {data['dst']}")
print(f"Current Time: {data['current_time']}")

Address Normalization API

Parse raw address strings into structured components and normalised variants using the Libpostal engine. Ideal for data cleansing and pre-processing pipelines before batch geocoding.

Endpoint

POST /v1/normalize

Request Body

ParameterTypeRequiredDescription
addressstringYesRaw address string to parse and normalise

Response Fields

FieldDescription
parsedObject containing structured address components (house_number, road, city, postcode, country, etc.)
normalizedArray of normalised address string variants expanded by Libpostal
inputThe original address string supplied

💡 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.

cURL

curl -X POST "https://mapsi.dev/v1/normalize" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"address": "123 main st new york ny 10001"}'

JavaScript

// Parse and normalize an address string
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();

// Parsed components
console.log(data.parsed.house_number);  // "123"
console.log(data.parsed.road);          // "main st"
console.log(data.parsed.city);          // "new york"
console.log(data.parsed.postcode);      // "10001"

// Normalised variants (Libpostal expansions)
console.log(data.normalized);  // ["123 main street new york ny 10001", ...]

Python

import requests

# Parse and normalize an address string
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()

# Parsed components
parsed = data["parsed"]
print(f"House number: {parsed.get('house_number')}")
print(f"Road: {parsed.get('road')}")
print(f"City: {parsed.get('city')}")
print(f"Postcode: {parsed.get('postcode')}")

# Normalised variants
for variant in data["normalized"]:
    print(variant)

Map Tiles API

Access global vector map tiles for building custom map experiences. Our tiles are derived from OpenStreetMap and Natural Earth data, delivered via a global CDN for fast loading worldwide.

GET /v1/tiles/sources

List all available tile sources

GET /v1/tiles?source=planet

Get TileJSON specification for a source

GET https://mapsi.dev/tiles/planet/{z}/{x}/{y}

Fetch vector tiles (PBF format) from CDN

Available Tile Sources

SourceTypeZoom LevelsCoverage
planetVector (PBF)0-15Global

Vector Layers

The planet source includes the following vector layers:

  • boundaries - Administrative boundaries
  • buildings - Building footprints (zoom 13+)
  • landuse - Parks, forests, etc.
  • natural - Natural features
  • places - Place labels
  • pois - Points of interest
  • roads - Road network
  • transportation - Transport features
  • water - Water bodies

Example Usage

cURL - Get Tile Sources

curl -X GET "https://mapsi.dev/v1/tiles/sources" \
  -H "X-API-Key: YOUR_API_KEY"

cURL - Get TileJSON

curl -X GET "https://mapsi.dev/v1/tiles?source=planet" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript - Using with MapLibre GL

// Initialize MapLibre GL map with Mapsi tiles
const map = new maplibregl.Map({
  container: 'map',
  style: {
    version: 8,
    sources: {
      'mapsi-planet': {
        type: 'vector',
        tiles: ['https://mapsi.dev/tiles/planet/{z}/{x}/{y}'],
        maxzoom: 15
      }
    },
    layers: [
      // Add your style layers here
      {
        id: 'water',
        type: 'fill',
        source: 'mapsi-planet',
        'source-layer': 'water',
        paint: { 'fill-color': '#a0c4ff' }
      },
      {
        id: 'roads',
        type: 'line',
        source: 'mapsi-planet',
        'source-layer': 'roads',
        paint: { 'line-color': '#888', 'line-width': 1 }
      }
    ]
  },
  center: [0, 20],
  zoom: 2
});

Python - Fetch TileJSON

import requests

# Get TileJSON specification
response = requests.get(
    "https://mapsi.dev/v1/tiles",
    params={"source": "planet"},
    headers={"X-API-Key": "YOUR_API_KEY"}
)
tilejson = response.json()
print(tilejson["data"]["tiles"])  # CDN tile URLs

Map Styles

Use the styles endpoint to get a ready-to-use MapLibre GL style JSON. Pass it directly to your map — no extra configuration needed.

GET /v1/tiles/styles?style={name}

Get a MapLibre GL style definition. Returns full style JSON ready for use.

Available Styles

StyleDescriptionBest For
lightClean light theme (default)General purpose, dashboards
darkDark navy themeNight mode, data visualisation
streetsRoad-focused with colour-coded highwaysNavigation, routing apps
grayscaleFully desaturated monochromeData overlays, print
topoTopographic paper-map aestheticOutdoor, hiking, terrain context
liberty3D building extrusion, vibrant roadsCity exploration, showcase maps

cURL - Get a Style

curl -X GET "https://mapsi.dev/v1/tiles/styles?style=streets" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript - Use a Style with MapLibre GL

// Fetch the style from Mapsi and pass directly to MapLibre
const styleResponse = await fetch(
  'https://mapsi.dev/v1/tiles/styles?style=liberty',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const style = await styleResponse.json();

const map = new maplibregl.Map({
  container: 'map',
  style: style,   // ← drop it straight in
  center: [0, 20],
  zoom: 2
});

Route API

Multi-stop routing for car, truck, bicycle, motor scooter, and pedestrian profiles. Pass 2–25 waypoints and receive total distance, duration, a per-leg breakdown, and the full route geometry as a GeoJSON LineString.

Endpoints

POST /v1/route GET /v1/route

POST accepts a waypoints array (multi-stop). GET is a convenience shorthand for point-to-point only.

POST Request Body

FieldTypeRequiredDescription
waypointsarrayYes*Ordered array of {lat, lon} stops. Min 2, max 25. First = origin, last = destination.
originobjectYes*Shorthand {lat, lon} — use instead of waypoints for simple A→B routes.
destinationobjectYes*Shorthand end point {lat, lon}. Required when using origin.
viaarrayNoIntermediate stops when using origin/destination shorthand. Array of {lat, lon}.
modestringNoauto (default), truck, bicycle, pedestrian, motor_scooter
unitsstringNokm (default) or mi

* Provide either waypoints or origin + destination.

GET Parameters

ParameterTypeRequiredDescription
origin_lat, origin_lonnumberYesStart coordinate
dest_lat, dest_lonnumberYesEnd coordinate
modestringNoTravel mode (default: auto)
unitsstringNokm or mi

Response Fields

FieldDescription
waypoint_countNumber of stops in the route
distance_kmTotal route distance in km (omitted when units=mi)
distance_miTotal route distance in miles (only when units=mi)
duration_secEstimated total travel time in seconds
legs[]Per-leg breakdown. Each leg: from, to (waypoint indices), distance_km, duration_sec
polylineGeoJSON LineString of the full route geometry
modeTravel mode used
unitsDistance units used

cURL — multi-stop (Eiffel Tower → Louvre → Notre Dame)

curl -X POST "https://mapsi.dev/v1/route" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "waypoints": [
      {"lat": 48.8584, "lon": 2.2945},
      {"lat": 48.8606, "lon": 2.3376},
      {"lat": 48.8530, "lon": 2.3499}
    ],
    "mode": "auto",
    "units": "km"
  }'

cURL — simple point-to-point (GET shorthand)

curl "https://mapsi.dev/v1/route?origin_lat=48.8584&origin_lon=2.2945&dest_lat=48.8530&dest_lon=2.3499&mode=auto" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const res = await fetch('https://mapsi.dev/v1/route', {
  method: 'POST',
  headers: { 'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    waypoints: [
      { lat: 48.8584, lon: 2.2945 },  // Eiffel Tower
      { lat: 48.8606, lon: 2.3376 },  // Louvre
      { lat: 48.8530, lon: 2.3499 }   // Notre Dame
    ],
    mode: 'auto',
    units: 'km'
  })
});
const data = await res.json();
console.log(`${data.distance_km} km — ${data.duration_sec}s`);
data.legs.forEach((leg, i) =>
  console.log(`Leg ${i+1}: ${leg.distance_km} km, ${leg.duration_sec}s`)
);

Python

import requests

payload = {
    "waypoints": [
        {"lat": 48.8584, "lon": 2.2945},  # Eiffel Tower
        {"lat": 48.8606, "lon": 2.3376},  # Louvre
        {"lat": 48.8530, "lon": 2.3499},  # Notre Dame
    ],
    "mode": "auto",
    "units": "km"
}
r = requests.post(
    'https://mapsi.dev/v1/route',
    json=payload,
    headers={'X-API-Key': 'YOUR_API_KEY'}
)
data = r.json()
print(f"Total: {data['distance_km']} km in {data['duration_sec']}s")
for i, leg in enumerate(data['legs']):
    print(f"  Leg {i+1}: {leg['distance_km']} km")

Matrix API

Compute travel times and distances between multiple origin–destination pairs simultaneously, returning a full N×M matrix in one request. Designed for logistics, fleet routing, and delivery optimisation.

Endpoint

POST /v1/matrix

Request Body

FieldTypeRequiredDescription
sourcesarrayYesArray of {lat, lon} origin points. Max 25.
targetsarrayYesArray of {lat, lon} destination points. Max 25.
profilestringNocar (default), truck, bicycle, pedestrian
unitsstringNometric (default) or imperial

Batch Size Limits

PlanMax Matrix SizeMax Pairs
Free5×525
Growth10×10100
Business25×25625
EnterpriseCustomCustom

Response Fields

FieldDescription
durations[i][j]Travel time in seconds from source i to target j
distances[i][j]Distance in metres from source i to target j
durations_text[i][j]Human-readable duration (e.g., "3h 33m")

cURL

curl -X POST "https://mapsi.dev/v1/matrix" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "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"
  }'

JavaScript

const r = 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 r.json();
console.log(`Paris → Berlin: ${data.durations_text[0][0]}`);

Python

import requests
r = requests.post('https://mapsi.dev/v1/matrix',
    json={'sources': [{'lat': 48.8584, 'lon': 2.2945}], 'targets': [{'lat': 52.52, 'lon': 13.405}]},
    headers={'X-API-Key': 'YOUR_API_KEY'})
print(r.json()['durations_text'])  # [['10h 9m']]

Isochrone API

Generate reachability polygons showing all areas accessible within specified travel times or distances from an origin. Returns a GeoJSON FeatureCollection with one polygon per contour. Supports up to 5 contours per request.

Endpoint

GET /v1/isochrone

Parameters

ParameterTypeRequiredDescription
latnumberYesOrigin latitude
lonnumberYesOrigin longitude
timestringOne ofComma-separated travel time contours in minutes. Example: 10,20,30. Max 5.
distance_kmstringOne ofComma-separated distance contours in km. Cannot combine with time.
profilestringNocar (default), bicycle, pedestrian
denoisenumberNoPolygon smoothing factor 0.0–1.0 (default: 0.5)

Response

Returns a GeoJSON FeatureCollection. Each Feature is a Polygon for one contour, with contour_minutes or contour_km in properties. Polygons are nested — larger contours enclose smaller ones.

cURL

curl "https://mapsi.dev/v1/isochrone?lat=48.8584&lon=2.2945&time=10,20,30&profile=car" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const r = 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 geojson = await r.json();
// Pass directly to MapLibre/Leaflet as a GeoJSON source
map.addSource('isochrone', { type: 'geojson', data: geojson });

Python

import requests
r = requests.get('https://mapsi.dev/v1/isochrone',
    params={'lat': 48.8584, 'lon': 2.2945, 'time': '10,20,30'},
    headers={'X-API-Key': 'YOUR_API_KEY'})
print(f"{len(r.json()['features'])} contour polygons returned")

Elevation API

Returns SRTM 30m resolution elevation data (height above sea level in metres) for any coordinate or batch of coordinates. Global coverage. Single-point via GET, batch via POST.

Endpoints

GET /v1/elevation POST /v1/elevation

Parameters (GET — single point)

ParameterTypeRequiredDescription
latnumberYesLatitude (-90 to 90)
lonnumberYesLongitude (-180 to 180)

Request Body (POST — batch)

FieldTypeRequiredDescription
pointsarrayYesArray of {lat, lon} objects. Max 512 per request.

Batch Size Limits

PlanMax Points
Free10
Growth128
Business512
Enterprise2,000

cURL — Single Point

curl "https://mapsi.dev/v1/elevation?lat=45.8325&lon=6.8652" \
  -H "X-API-Key: YOUR_API_KEY"
# Response: {"success":true,"lat":45.8325,"lon":6.8652,"elevation_m":4808,"source":"srtm30"}

cURL — Batch

curl -X POST "https://mapsi.dev/v1/elevation" \
  -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"points":[{"lat":45.8325,"lon":6.8652},{"lat":27.9881,"lon":86.9250}]}'

JavaScript

// Batch
const r = 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 data = await r.json();
data.results.forEach(p => console.log(`${p.lat},${p.lon} → ${p.elevation_m}m`));

Python

import requests
r = 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 r.json()['results']:
    print(f"{pt['elevation_m']}m")

Nearest Road API

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

ParameterTypeRequiredDescription
latnumberYesLatitude (-90 to 90)
lonnumberYesLongitude (-180 to 180)
limitintegerNoNumber of nearest roads (default: 1, max: 5)
radiusintegerNoSearch radius in metres (default: 200, max: 2000)

Response Fields

FieldDescription
road_nameStreet name from OSM (null if unnamed)
refRoad reference number (e.g., "A1", "M25")
highwayOSM highway classification (motorway, primary, residential, etc.)
speed_limit_kmhPosted speed limit where available in OSM, null otherwise
onewayWhether the road is one-way (boolean)
snapped_pointNearest point on the road geometry {lat, lon}
distance_mDistance from input coordinate to snapped point in metres
osm_way_idOpenStreetMap way ID for the road segment

cURL

curl "https://mapsi.dev/v1/nearest-road?lat=48.8584&lon=2.2945&limit=1" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const r = await fetch(
  'https://mapsi.dev/v1/nearest-road?lat=48.8584&lon=2.2945',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const data = await r.json();
const road = data.results[0];
console.log(`${road.road_name} (${road.highway}), ${road.distance_m}m away`);

Python

import requests
r = requests.get('https://mapsi.dev/v1/nearest-road',
    params={'lat': 48.8584, 'lon': 2.2945},
    headers={'X-API-Key': 'YOUR_API_KEY'})
road = r.json()['results'][0]
print(f"{road['road_name']} ({road['highway']}) — {road['distance_m']}m")

Map Matching API

Snaps a sequence of raw GPS coordinates to the road network, correcting GPS drift into accurate road-aligned trajectories. Returns matched geometry, road names, and a per-match confidence score.

Endpoint

POST /v1/match

Request Body

FieldTypeRequiredDescription
pointsarrayYesGPS points with lat, lon, optional timestamp (Unix seconds). Min 2, max 500.
profilestringNocar (default), bicycle, pedestrian
geometrystringNogeojson (default) or polyline

Response Fields

FieldDescription
confidenceOverall match confidence 0.0–1.0
geometryGeoJSON LineString of the matched road-aligned route
matched_points[]Each input point snapped to the road, with distance_from_original_m
matched_roads[]Road segments traversed with name and highway classification
distance_metersTotal matched route distance
duration_secondsEstimated duration (when timestamps provided)

cURL

curl -X POST "https://mapsi.dev/v1/match" \
  -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"points":[{"lat":48.8584,"lon":2.2945,"timestamp":1741000000},{"lat":48.8591,"lon":2.2962,"timestamp":1741000015}],"profile":"car"}'

JavaScript

const r = 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 }
    ],
    profile: 'car'
  })
});
const data = await r.json();
console.log(`Confidence: ${data.confidence}, Distance: ${data.distance_meters}m`);

Python

import requests
r = requests.post('https://mapsi.dev/v1/match',
    json={'points': [{'lat':48.8584,'lon':2.2945}, {'lat':48.8591,'lon':2.2962}], 'profile':'car'},
    headers={'X-API-Key': 'YOUR_API_KEY'})
data = r.json()
print(f"Confidence: {data['confidence']}")

H3 API

Converts coordinates to Uber's H3 hexagonal grid cell identifiers for spatial aggregation, heatmaps, and density analysis. Supports all H3 resolutions from 0 (coarsest, ~4M km²) to 15 (finest, ~1 m²).

Endpoint

GET /v1/h3

Parameters

ParameterTypeRequiredDescription
latnumberYesLatitude (-90 to 90)
lonnumberYesLongitude (-180 to 180)
resolutionintegerNoH3 resolution 0–15 (default: 9, approx 0.1 km²)
return_boundarybooleanNoInclude hex cell boundary polygon (default: false)
return_neighborsbooleanNoInclude the 6 neighbouring cell IDs (default: false)

Resolution Reference

ResolutionApprox AreaScale
5252 km²City
75.16 km²District
9 (default)0.105 km²Neighbourhood
110.001 km²Block
1343 m²Building

cURL

curl "https://mapsi.dev/v1/h3?lat=48.8584&lon=2.2945&resolution=9&return_boundary=true" \
  -H "X-API-Key: YOUR_API_KEY"

JavaScript

const r = 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 r.json();
console.log(`Cell: ${data.cell_id}, Area: ${data.area_km2} km²`);

Python

import requests
r = requests.get('https://mapsi.dev/v1/h3',
    params={'lat': 48.8584, 'lon': 2.2945, 'resolution': 9},
    headers={'X-API-Key': 'YOUR_API_KEY'})
data = r.json()
print(f"{data['cell_id']} — {data['area_km2']} km²")