Accueil / Services / Itinéraires
Calcul d'itinéraires

Itinéraires, matrices et isochrones

Calculez un trajet, une tournée optimisée, une matrice de temps et de distances ou une zone accessible, en voiture, à pied ou à vélo, en France, en Belgique et en Allemagne.

Préfixe /v2/routing/ Moteur Valhalla Documentation complète de Valhalla ↗
Principe

Comment appeler le calcul d'itinéraires

Chaque fonction de Valhalla est exposée sous /v2/routing/{fonction}. La requête est un objet JSON, envoyé de préférence en POST :

FonctionUsage
routeItinéraire entre deux points ou plus, avec instructions de navigation
optimized_routeTournée : ordre de passage optimal entre plusieurs points
sources_to_targetsMatrice de temps et de distances (1×N, N×N, N×M)
isochroneZones accessibles en un temps ou une distance donnés
trace_route, trace_attributesRecalage d'une trace GPS sur le réseau routier
locateTronçons de route les plus proches d'un point
statusVersion du moteur et fonctions disponibles

POST ou GET. En POST, le corps JSON est la requête. En GET, passez le même JSON, encodé, dans le paramètre json :

GET /v2/routing/route?json=%7B%22locations%22%3A…%7D

Préférez POST : la requête reste lisible et n'est pas limitée par la longueur maximale d'une URL.

Seules les fonctions de ce tableau sont ouvertes. Toute autre fonction de Valhalla renvoie 404 avec le code unknown_endpoint.

Profils

Profils de déplacement

Le paramètre costing choisit le mode de déplacement. Il est obligatoire dans toutes les requêtes. Les options de chaque profil se règlent dans costing_options.{profil}.

costingModeOptions utiles de costing_options
autoVoitureuse_highways, use_tolls, use_ferry (0 à 1 : de « éviter » à « privilégier »)
pedestrianPiétonwalking_speed (km/h), max_distance (mètres de marche)
bicycleVélobicycle_type (Road, Hybrid, City, Cross, Mountain), cycling_speed, use_roads
Éviter les péages et les autoroutes
{
  "costing": "auto",
  "costing_options": {
    "auto": {"use_tolls": 0, "use_highways": 0.1}
  }
}

La liste complète des options est dans la documentation des profils de Valhalla.

Endpoint

Calculer un itinéraire

POST/v2/routing/route ouGET?json=…

Renvoie le trajet qui passe par les points dans l'ordre donné, avec la distance, la durée, la géométrie et les instructions de navigation.

Paramètres principaux

ParamètreDescription
locationsrequisListe ordonnée d'au moins deux points {"lat", "lon"}. Un point intermédiaire peut être de type "through" (passage sans arrêt) au lieu de "break" (arrêt, par défaut).
costingrequisProfil : auto, pedestrian ou bicycle.
costing_optionsRéglages du profil (voir profils).
directions_options.unitskilometers (par défaut) ou miles.
directions_options.languageLangue des instructions, par exemple fr-FR, nl-NL, de-DE.
directions_typenone pour ne recevoir que le résumé et la géométrie, sans instructions : réponse plus légère. Se place à la racine de la requête, pas dans directions_options.
alternatesNombre d'itinéraires alternatifs souhaités. Ils sont renvoyés dans une liste alternates, à côté de trip.

Exemple

curl "https://geoservice.example.com/v2/routing/route" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "locations": [
      {"lat": 48.855199, "lon": 2.354035},
      {"lat": 48.853138, "lon": 2.349185}
    ],
    "costing": "auto",
    "directions_options": {"units": "kilometers", "language": "fr-FR"}
  }'
200 OK · réponse abrégée
{
  "trip": {
    "locations": [
      {"type": "break", "lat": 48.855199, "lon": 2.354035, "side_of_street": "right", "original_index": 0},
      {"type": "break", "lat": 48.853138, "lon": 2.349185, "original_index": 1}
    ],
    "legs": [{
      "maneuvers": [
        {
          "type": 2,
          "instruction": "Conduisez vers le nord-ouest sur Rue de l'Hôtel de Ville.",
          "verbal_post_transition_instruction": "Continuez pendant 20 mètres.",
          "street_names": ["Rue de l'Hôtel de Ville"],
          "time": 5.651, "length": 0.015,
          "begin_shape_index": 0, "end_shape_index": 2,
          "travel_mode": "drive"
        },
        …
      ],
      "summary": {"time": 321.438, "length": 1.185},
      "shape": "me{d|AortnCsAzDcA~CaB{AuNaM}BHkBBwIaEyAe…"
    }],
    "summary": {
      "time": 321.438, "length": 1.185,
      "has_toll": false, "has_highway": false, "has_ferry": false,
      "min_lat": 48.853633, "min_lon": 2.349207, "max_lat": 48.856957, "max_lon": 2.356614
    },
    "status_message": "Found route between points",
    "status": 0,
    "units": "kilometers",
    "language": "fr-FR"
  }
}
trip.summary
Durée totale (time, en secondes), distance (length, dans l'unité demandée) et emprise du trajet.
trip.legs[]
Une étape par couple de points d'arrêt consécutifs, chacune avec son résumé, sa géométrie shape et ses manœuvres.
maneuvers[]
Instructions pas à pas. begin_shape_index et end_shape_index renvoient aux points de la géométrie décodée.
Géométrie

Décoder la géométrie

La géométrie shape est une polyligne encodée avec une précision de 6 décimales, et non de 5 comme la polyligne de Google. Avec une bibliothèque de décodage, pensez à préciser cette précision, sinon le tracé tombe très loin de la réalité.

// Décode une polyligne Valhalla en [[lon, lat], …] (ordre GeoJSON).
function decodeShape(str, precision = 6) {
  const factor = 10 ** precision;
  const coords = [];
  let index = 0, lat = 0, lon = 0;
  while (index < str.length) {
    for (const axis of [0, 1]) {
      let result = 0, shift = 0, byte;
      do {
        byte = str.charCodeAt(index++) - 63;
        result |= (byte & 0x1f) << shift;
        shift += 5;
      } while (byte >= 0x20);
      const delta = result & 1 ? ~(result >> 1) : result >> 1;
      if (axis === 0) lat += delta; else lon += delta;
    }
    coords.push([lon / factor, lat / factor]);
  }
  return coords;
}

const line = { type: "LineString", coordinates: decodeShape(trip.legs[0].shape) };

Recevoir directement du GeoJSON

Pour éviter le décodage, demandez une réponse au format OSRM avec une géométrie GeoJSON : "format": "osrm" et "shape_format": "geojson", ensemble. Au format natif de Valhalla, shape_format est ignoré sans erreur et shape reste une polyligne encodée.

curl "https://geoservice.example.com/v2/routing/route" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "locations": [
      {"lat": 48.855199, "lon": 2.354035},
      {"lat": 48.853138, "lon": 2.349185}
    ],
    "costing": "auto",
    "directions_options": {"language": "fr-FR"},
    "format": "osrm",
    "shape_format": "geojson"
  }'
200 OK · réponse abrégée
{
  "routes": [{
    "distance": 1185.71,
    "duration": 321.45,
    "weight_name": "auto",
    "weight": 731.777,
    "geometry": {
      "type": "LineString",
      "coordinates": [[2.353976, 48.855143], [2.353882, 48.855185], [2.353802, 48.855219], …, [2.349207, 48.853633]]
    },
    "legs": [{
      "distance": 1185.71,
      "duration": 321.45,
      "summary": "Rue de Rivoli, Pont d'Arcole",
      "steps": [
        {
          "name": "Rue de l'Hôtel de Ville",
          "distance": 15.71, "duration": 5.663,
          "mode": "driving",
          "maneuver": {
            "type": "depart",
            "instruction": "Conduisez vers le nord-ouest sur Rue de l'Hôtel de Ville.",
            "location": [2.353976, 48.855143],
            "bearing_before": 0, "bearing_after": 304
          },
          "geometry": {
            "type": "LineString",
            "coordinates": [[2.353976, 48.855143], [2.353882, 48.855185], [2.353802, 48.855219]]
          },
          …
        },
        …
      ]
    }]
  }],
  "waypoints": [
    {"name": "Rue de l'Hôtel de Ville", "location": [2.353976, 48.855143], "distance": 7.621},
    {"name": "Rue d'Arcole", "location": [2.349207, 48.853633], "distance": 55.139}
  ],
  "code": "Ok"
}

La réponse suit alors la structure d'OSRM, et non celle de Valhalla :

routes[].geometry
Tracé complet, directement utilisable comme géométrie d'une Feature GeoJSON (coordonnées en [lon, lat]).
routes[].legs[].steps[]
Instructions pas à pas, chacune avec sa propre géométrie GeoJSON. Avec "directions_type": "none", la liste est vide.
distance, duration
Toujours en mètres et en secondes, quelle que soit la valeur de directions_options.units.

Ce couple de paramètres fonctionne aussi avec optimized_route et trace_route (le tracé recalé est alors dans matchings[].geometry). Il est sans effet sur trace_attributes, dont la géométrie reste une polyligne encodée à décoder comme ci-dessus.

Endpoint

Optimiser une tournée

POST/v2/routing/optimized_route

Cherche l'ordre de passage le plus court entre les points (problème du voyageur de commerce). Le premier et le dernier point restent fixes : pour une boucle, répétez le point de départ en fin de liste. Les paramètres sont ceux de route.

Requête : départ et retour au parvis Notre-Dame, trois visites
curl "https://geoservice.example.com/v2/routing/optimized_route" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "locations": [
      {"lat": 48.853401, "lon": 2.348792},
      {"lat": 48.833535, "lon": 2.364601},
      {"lat": 48.845737, "lon": 2.342628},
      {"lat": 48.824381, "lon": 2.330955},
      {"lat": 48.853401, "lon": 2.348792}
    ],
    "costing": "auto"
  }'
200 OK · extrait
{
  "trip": {
    "locations": [
      {"type": "break", "lat": 48.853401, "lon": 2.348792, "original_index": 0},
      {"type": "break", "lat": 48.845737, "lon": 2.342628, "original_index": 2},
      {"type": "break", "lat": 48.824381, "lon": 2.330955, "original_index": 3},
      {"type": "break", "lat": 48.833535, "lon": 2.364601, "original_index": 1},
      {"type": "break", "lat": 48.853401, "lon": 2.348792, "original_index": 4}
    ],
    "legs": [ … 4 étapes … ],
    "summary": {"time": 2399.136, "length": 14.047}
  }
}

trip.locations est renvoyé dans l'ordre optimisé ; original_index donne la position de chaque point dans votre requête. Ici, l'ordre optimal est 0 → 2 → 3 → 1 → 4 : 14 km en 40 minutes.

Endpoint

Calculer une matrice de temps et de distances

POST/v2/routing/sources_to_targets

Calcule le temps et la distance de chaque origine (sources) vers chaque destination (targets), sans les géométries. Pour une matrice 1×N, donnez une seule source ; pour une matrice N×N, la même liste en sources et en destinations.

ParamètreDescription
sourcesrequisPoints d'origine {"lat", "lon"}.
targetsrequisPoints de destination {"lat", "lon"}.
costingrequisProfil : auto, pedestrian ou bicycle.
unitskilometers (par défaut) ou miles.
Requête : une origine, trois destinations
curl "https://geoservice.example.com/v2/routing/sources_to_targets" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sources": [{"lat": 48.824101, "lon": 2.358052}],
    "targets": [
      {"lat": 48.833535, "lon": 2.364601},
      {"lat": 48.815678, "lon": 2.374128},
      {"lat": 48.845737, "lon": 2.342628}
    ],
    "costing": "auto"
  }'
200 OK
{
  "sources_to_targets": [[
    {"from_index": 0, "to_index": 0, "time": 216, "distance": 1.484},
    {"from_index": 0, "to_index": 1, "time": 293, "distance": 2.3},
    {"from_index": 0, "to_index": 2, "time": 485, "distance": 3.028}
  ]],
  "sources": [{"lat": 48.824082, "lon": 2.357917}],
  "targets": [
    {"lat": 48.833633, "lon": 2.364525},
    {"lat": 48.815759, "lon": 2.373594},
    {"lat": 48.845708, "lon": 2.342741}
  ],
  "units": "kilometers",
  "algorithm": "costmatrix"
}

sources_to_targets[i][j] donne le trajet de la source i vers la destination j : time en secondes, distance dans l'unité demandée. Les coordonnées renvoyées sont celles des points recalés sur la route la plus proche. Chaque cellule porte aussi les caps et coordonnées de départ et d'arrivée, omis ici.

Taille des matrices. Le nombre de couples origine × destination et la distance couverte sont limités. Au-delà, le moteur renvoie une erreur 400 (voir limites). Pour de très grandes matrices, découpez-les en blocs de sources.

Endpoint

Calculer une isochrone

POST/v2/routing/isochrone

Renvoie la zone atteignable depuis un point en un temps donné (isochrone) ou sur une distance donnée (isodistance), au format GeoJSON.

ParamètreDescription
locationsrequisUn point de départ {"lat", "lon"}.
costingrequisProfil : auto, pedestrian ou bicycle.
contoursrequisListe de seuils : {"time": 10} en minutes, ou {"distance": 5} en kilomètres. Une couleur facultative par contour : "color": "ff8a3d".
polygonstrue pour des polygones (à privilégier pour l'affichage et l'analyse), false pour des lignes.
denoiseDe 0 à 1 : supprime les petites îles du résultat (1 : ne garde que le plus grand polygone).
generalizeTolérance de simplification du contour, en mètres.
reversetrue pour la zone depuis laquelle on atteint le point (zone de chalandise).
Requête : 2 minutes à pied depuis le parvis Notre-Dame
curl "https://geoservice.example.com/v2/routing/isochrone" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "locations": [{"lat": 48.853401, "lon": 2.348792}],
    "costing": "pedestrian",
    "contours": [{"time": 2}],
    "polygons": true
  }'
200 OK
{
  "type": "FeatureCollection",
  "features": [{
    "type": "Feature",
    "properties": {
      "contour": 2.0, "metric": "time",
      "color": "#bf4040", "fill": "#bf4040", "fillColor": "#bf4040",
      "opacity": 0.33, "fill-opacity": 0.33, "fillOpacity": 0.33
    },
    "geometry": {
      "type": "Polygon",
      "coordinates": [[
        [2.349792, 48.855144], [2.347792, 48.854954], [2.346638, 48.853554],
        [2.348792, 48.851993], [2.350097, 48.852401], [2.351211, 48.853401],
        [2.349792, 48.855144]
      ]]
    }
  }]
}

Une Feature par contour, prête à être affichée par Leaflet, MapLibre ou OpenLayers. properties.contour rappelle le seuil et metric sa nature (time ou distance). Avec plusieurs contours, le plus grand vient en premier.

Endpoints

Recaler une trace GPS

POST/v2/routing/trace_route POST/v2/routing/trace_attributes

Deux fonctions pour associer une suite de positions GPS au réseau routier (map matching) :

  • trace_route renvoie l'itinéraire réellement suivi, au même format que route.
  • trace_attributes renvoie les tronçons parcourus et leurs attributs : noms de rue, vitesses, types de voie…
Requête
curl "https://geoservice.example.com/v2/routing/trace_route" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "shape": [
      {"lat": 48.855143, "lon": 2.353976},
      {"lat": 48.855219, "lon": 2.353802},
      {"lat": 48.856957, "lon": 2.356614}
    ],
    "costing": "auto",
    "shape_match": "map_snap"
  }'

La trace se donne dans shape (points {"lat", "lon"}, avec un horodatage time facultatif) ou dans encoded_polyline. shape_match vaut map_snap pour une trace GPS bruitée, edge_walk pour une géométrie qui suit déjà exactement les routes.

Endpoint

Trouver les routes proches d'un point

POST/v2/routing/locate

Renvoie les tronçons du réseau sur lesquels un point serait recalé pour un profil donné. Utile pour comprendre pourquoi un point de départ est mal placé.

Requête
curl "https://geoservice.example.com/v2/routing/locate" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"locations": [{"lat": 48.853401, "lon": 2.348792}], "costing": "auto"}'
200 OK · extrait
[{
  "input_lat": 48.853401, "input_lon": 2.348792,
  "edges": [
    {"way_id": 45518911, "correlated_lat": 48.853633, "correlated_lon": 2.349207, "side_of_street": "neither", "percent_along": 0.0},
    {"way_id": 203476035, "correlated_lat": 48.853021, "correlated_lon": 2.348907, "side_of_street": "neither", "percent_along": 0.0},
    …
  ],
  "nodes": [{"lon": 2.348907, "lat": 48.853021}, {"lon": 2.349207, "lat": 48.853633}]
}]

way_id est l'identifiant de la voie OpenStreetMap.

Endpoint

Statut du moteur

GET/v2/routing/status
200 OK
{
  "version": "3.8.3",
  "tileset_last_modified": 1789734449,
  "available_actions": ["tile", "status", "centroid", "expansion", "transit_available", "trace_attributes",
                        "trace_route", "isochrone", "optimized_route", "sources_to_targets", "height", "route", "locate"]
}

tileset_last_modified est la date (horodatage Unix) des données routières en service. available_actions liste les fonctions du moteur ; seules celles documentées ici sont ouvertes par le GeoService.

Limites

Limites et erreurs du moteur

Le moteur limite la taille des requêtes : nombre de couples dans une matrice, distance d'un itinéraire selon le profil, nombre et durée des contours d'isochrone. Une requête qui dépasse une limite reçoit une erreur 400 de Valhalla, transmise telle quelle :

400 Bad Request · format Valhalla
{"error_code": 120, "error": "Insufficient number of locations provided", "status_code": 400, "status": "Bad Request"}

Toutes les erreurs de requête ont le même code HTTP 400 : distinguez-les par error_code.

error_codeSignificationQue faire
120Pas assez de pointsFournir au moins deux points à route.
125Profil inconnu (No costing method found)Utiliser auto, pedestrian ou bicycle.
150 à 158Limite de service dépassée (matrice, distance, contours…)Réduire la requête ou la découper.
171Aucune route à proximité d'un pointVérifier les coordonnées (inversion lat/lon ?) et la couverture.
442Aucun itinéraire trouvé entre les pointsPoints non reliés pour ce profil (île, zone piétonne…).

Trajets à pied de plus de 100 km. Le profil pedestrian limite par défaut la marche à 100 km. Au-delà, aucun itinéraire n'est trouvé : augmentez costing_options.pedestrian.max_distance (en mètres) dans votre requête, par exemple 300000.

La liste complète des codes figure dans la référence des erreurs de Valhalla. Les erreurs propres au GeoService sont décrites dans Erreurs.