Routing

By the end of this guide, you'll have directions, isochrones, and distance matrices working with Plaza's routing endpoints.

All routing runs in Postgres with pgRouting. No external routing engine, no OSRM, no Valhalla. The upside is simplicity and consistency with the rest of the API. The downside is that very long routes (cross-country drives) are slower than dedicated routing engines.

Directions

Calculate a route between two points.

curl -X POST "https://plaza.fyi/api/v1/route" \
-H "x-api-key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"origin": {"lat": 48.8566, "lng": 2.3522},
"destination": {"lat": 48.8738, "lng": 2.2950},
"mode": "foot"
}'

Travel modes

Mode Description
auto Driving (default)
foot Walking
bicycle Cycling

Each mode uses a different graph. foot includes pedestrian paths and alleys that auto doesn't, which makes foot queries slower over large areas because the graph is denser.

Response

{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [[2.3522, 48.8566], [2.3400, 48.8600], ...]
},
"properties": {
"distance_m": 3420,
"duration_s": 2580,
"mode": "foot",
"steps": [
{"instruction": "Head north on Rue de Rivoli", "distance_m": 450},
{"instruction": "Turn left onto Avenue des Champs-Elysees", "distance_m": 1200}
]
}
}

A GeoJSON Feature with a LineString geometry. distance_m is meters, duration_s is seconds, steps has turn-by-turn instructions.

If no route exists (e.g., the two points are on disconnected islands), you get a 404 with code no_route_found.

Isochrones

Calculate the area reachable from a point within a given time.

curl "https://plaza.fyi/api/v1/isochrone?lat=48.8566&lng=2.3522&time=600&mode=foot" \
-H "x-api-key: pk_live_YOUR_KEY"
Parameter Required Description
lat yes Center latitude
lng yes Center longitude
time yes Travel time in seconds (1-7,200)
mode no auto, foot, bicycle (default: auto)

The response is a GeoJSON Polygon representing everywhere you can reach in that time.

{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[2.34, 48.85], [2.36, 48.86], ...]]
},
"properties": {
"center": [2.3522, 48.8566],
"time_s": 600,
"mode": "foot"
}
}

5-15 minute isochrones are fast and produce clean polygons. Beyond 60 minutes, expect slower responses and more complex geometry.

Distance matrix

Get travel distances and durations between multiple origins and destinations in one call.

curl -X POST "https://plaza.fyi/api/v1/matrix" \
-H "x-api-key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"origins": [
{"lat": 48.8566, "lng": 2.3522},
{"lat": 48.8738, "lng": 2.2950}
],
"destinations": [
{"lat": 48.8530, "lng": 2.3499},
{"lat": 48.8606, "lng": 2.3376}
],
"mode": "auto"
}'

Response:

{
"durations": [[120, 300], [450, 200]],
"distances": [[1200, 3500], [4800, 2100]],
"mode": "auto"
}

durations is in seconds, distances in meters. Rows are origins, columns are destinations. So durations[0][1] is the travel time from the first origin to the second destination.

Matrix limits

  • Max 50 origins, 50 destinations
  • Total pairs (origins x destinations) cannot exceed 2,500
  • Each point must be within 500m of the road network

Start small and increase. A 50x50 matrix computes 2,500 routes -- that's a lot of work for a single request.

Nearest road

Snap a coordinate to the nearest point on the road network.

curl "https://plaza.fyi/api/v1/nearest?lat=48.8566&lng=2.3522" \
-H "x-api-key: pk_live_YOUR_KEY"
Parameter Required Description
lat yes Latitude
lng yes Longitude
radius no Search radius in meters (default 500, max 5,000)

Returns the snapped point and the distance from your input coordinate. Use this to check if a coordinate is routable before calling /route -- a route request with an origin far from any road returns 404.

Client examples

Python -- route with error handling

import requests
resp = requests.post(
"https://plaza.fyi/api/v1/route",
json={
"origin": {"lat": 48.8566, "lng": 2.3522},
"destination": {"lat": 48.8738, "lng": 2.2950},
"mode": "bicycle"
},
headers={"x-api-key": "pk_live_YOUR_KEY"}
)
if resp.status_code == 200:
route = resp.json()
props = route["properties"]
print(f"{props['distance_m']}m, {props['duration_s']}s")
elif resp.status_code == 404:
print("No route found")

JavaScript -- isochrone on a map

const resp = await fetch(
"https://plaza.fyi/api/v1/isochrone?lat=51.505&lng=-0.09&time=900&mode=foot",
{ headers: { "x-api-key": "pk_live_YOUR_KEY" } }
);
const isochrone = await resp.json();
map.addSource("isochrone", { type: "geojson", data: isochrone });
map.addLayer({
id: "isochrone-fill",
type: "fill",
source: "isochrone",
paint: { "fill-color": "#3b82f6", "fill-opacity": 0.3 }
});

Practical tips

  • Snap first, route second. If you're unsure whether a coordinate is near a road, call /nearest before /route. Saves you a wasted request.
  • Keep matrices small. Start with 5-10 points per side. A 50x50 matrix is computationally expensive. Make sure you actually need all those pairs.
  • Long isochrones get slow. Stick to under 60 minutes. If you need a 2-hour driving isochrone, consider whether a simpler radius search would work instead.
  • Mode affects performance. foot routes use a denser graph (pedestrians can walk on footpaths, through parks, down alleys). For large areas, auto is faster because the graph has fewer edges.