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
/nearestbefore/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.
footroutes use a denser graph (pedestrians can walk on footpaths, through parks, down alleys). For large areas,autois faster because the graph has fewer edges.