Accueil / Services / Cellules H3
Itinéraires et isochrones sur cellules H3 · expérimental

Cellules H3

Calculez un itinéraire ou une zone accessible, à pied, à vélo ou en voiture, et recevez le résultat sous forme de cellules H3 : des identifiants stables, prêts à être croisés avec vos propres indicateurs.

Préfixe /v2/hexodos/ Moteur hexodos Île-de-France Documentation de H3 ↗
Principe

Un résultat exprimé en cellules

Le service hexodos calcule sur un réseau découpé en cellules H3 : un itinéraire est la suite des cellules traversées, une isochrone l'ensemble des cellules atteintes, chacune avec son temps de trajet. Les réponses donnent l'index de chaque cellule : c'est lui qui permet de joindre un résultat à une table d'indicateurs (population, commerces, équipements…) sans aucun calcul géométrique.

FonctionMéthodeUsage
routePOSTItinéraire entre deux points : durée, distance, cellules traversées dans l'ordre
isochronePOSTCellules accessibles en un ou plusieurs temps donnés, avec le temps de chacune
statusGETModes servis, emprise et date des données

Service expérimental. hexodos couvre pour l'instant l'Île-de-France et n'est pas ouvert sur tous les serveurs. Là où il ne l'est pas, ses fonctions répondent 503 avec le code service_not_configured (voir erreurs).

Chaque fonction s'appelle avec la clé d'API habituelle (en-tête X-API-Key). Les requêtes route et isochrone sont des objets JSON envoyés en POST ; une autre méthode reçoit 405. Les noms des champs sont en anglais, les messages d'erreur en français.

Notions

Qu'est-ce qu'une cellule H3 ?

H3 est un découpage de la Terre entière en hexagones, emboîtés par niveaux de finesse appelés résolutions. Chaque cellule porte un index unique et stable, écrit en texte (8b1fb4662475fff), qui ne dépend d'aucune frontière administrative. hexodos travaille à la résolution 11, des hexagones d'environ 25 m de côté et 2 150 m² : deux résultats, ou un résultat et un indicateur, se comparent donc par simple égalité d'index.

La bibliothèque H3 existe pour la plupart des langages (h3 en Python, h3-js en JavaScript, des extensions pour PostgreSQL, DuckDB ou BigQuery) : elle retrouve la cellule d'un point, le contour d'une cellule ou sa cellule parente à une résolution plus grossière.

Requête

Points et modes de déplacement

Un point de départ ou d'arrivée s'écrit de l'une des deux façons suivantes, jamais les deux à la fois :

FormeExemple
Coordonnées{"lat": 48.855199, "lon": 2.354035}
Cellule de résolution 11{"cell": "8b1fb4662475fff"}

Le calcul part du point de rattachement de la cellule : le point du réseau le plus proche de son centre. Si la cellule demandée n'en a pas (un parc, un bâtiment), hexodos retient la cellule voisine la plus proche qui en a un, jusqu'à environ 500 m. La réponse indique la cellule réellement utilisée et la distance entre le point demandé et son rattachement (snap_distance_m).

modeModeVitesse
pedestrianPiéton5 km/h, sens uniques ignorés
bicycleVélo16 km/h sur revêtement lisse ou pavé, moins sur chemin compacté, terre ou gravier ; 1 s par feu ; sens uniques respectés sauf contresens cyclables
autoVoitureVitesse maximale autorisée de la voie, sinon une vitesse par type de route ; 130 km/h au plus ; 2 s par feu, jusqu'à 2 s par carrefour franchi sans feu, selon la priorité ; interdictions de tourner respectées

Les noms des modes sont ceux du calcul d'itinéraires (costing). Il n'y a pas de réglage par mode : pas d'options de profil, pas de trafic, pas d'heure de départ.

Endpoint

Calculer un itinéraire

POST/v2/hexodos/route

Renvoie la durée et la distance du trajet le plus rapide entre deux points, la suite des cellules traversées et le polygone de leur fusion, un ruban d'une cinquantaine de mètres de large.

Paramètres

ChampDescription
originrequisPoint de départ : coordonnées ou cellule (voir points).
destinationrequisPoint d'arrivée, sous la même forme.
moderequispedestrian, bicycle ou auto.
geometryfalse pour ne pas recevoir le polygone (par défaut true) : réponse plus légère si seules les cellules vous intéressent.

Un champ inconnu est refusé (400) : une faute de frappe n'est jamais prise pour une valeur par défaut.

Exemple

curl "https://geoservice.example.com/v2/hexodos/route" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "origin": {"lat": 48.855199, "lon": 2.354035},
    "destination": {"lat": 48.853138, "lon": 2.349185},
    "mode": "pedestrian"
  }'
200 OK · réponse réelle, géométrie abrégée
{
  "mode": "pedestrian",
  "resolution": 11,
  "origin": {"cell": "8b1fb4662475fff", "snap_distance_m": 6.6},
  "destination": {"cell": "8b1fb46624a4fff", "snap_distance_m": 30.7},
  "duration_s": 430.3,
  "distance_m": 597.4,
  "cells": [
    "8b1fb4662475fff", "8b1fb4662474fff", "8b1fb4662429fff", "8b1fb466242dfff",
    "8b1fb4662428fff", "8b1fb466242cfff", "8b1fb4662421fff", "8b1fb4662425fff",
    "8b1fb4662424fff", "8b1fb4662420fff", "8b1fb4662426fff", "8b1fb4662422fff",
    "8b1fb4662435fff", "8b1fb4662422fff", "8b1fb4662435fff", "8b1fb4662431fff",
    "8b1fb4662430fff", "8b1fb4662433fff", "8b1fb4662432fff", "8b1fb4662414fff",
    "8b1fb4662589fff", "8b1fb466258bfff", "8b1fb46624a4fff"
  ],
  "geometry": {
    "type": "Polygon",
    "coordinates": [[[2.354605692753111, 48.85510856402714], …]]
  }
}

Réponse

ChampContenu
resolutionRésolution des cellules de la réponse : toujours 11.
origin, destinationCellule réellement utilisée et distance, en mètres, entre le point demandé et son rattachement.
duration_s, distance_mDurée en secondes et distance en mètres, rattachements compris.
cellsCellules traversées, dans l'ordre du trajet. Un trajet qui sort d'une cellule puis y revient la cite deux fois : c'est le cas ci-dessus de 8b1fb4662422fff et 8b1fb4662435fff.
geometryPolygone GeoJSON (longitude, latitude) de la fusion des cellules traversées ; il peut avoir un trou quand le trajet fait une boucle. Son type est Polygon en pratique, mais peut être MultiPolygon : lisez type avant coordinates.

Départ et arrivée dans la même cellule donnent une durée et une distance nulles, et une seule cellule.

Endpoint

Calculer une isochrone

POST/v2/hexodos/isochrone

Renvoie, pour chaque durée demandée, les cellules accessibles depuis un point avec le temps de trajet de chacune, et le multipolygone de leur fusion.

Paramètres

ChampDescription
originrequisPoint de départ : coordonnées ou cellule.
moderequispedestrian, bicycle ou auto.
contours_minrequisListe de durées en minutes, strictement positives, entières ou non : [5, 10, 15].
closingTaille de la fermeture, entier de 0 à 3 (par défaut 2). 0 rend les seules cellules atteintes par le réseau.
compacttrue pour recevoir les cellules compactées, sans les temps (par défaut false).
geometryfalse pour ne pas recevoir les multipolygones (par défaut true).

Exemple

curl "https://geoservice.example.com/v2/hexodos/isochrone" \
  -H "X-API-Key: $GEOSERVICE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "origin": {"lat": 48.855199, "lon": 2.354035},
    "mode": "pedestrian",
    "contours_min": [5, 10]
  }'
200 OK · réponse réelle, listes abrégées
{
  "mode": "pedestrian",
  "resolution": 11,
  "closing": 2,
  "origin": {"cell": "8b1fb4662475fff", "snap_distance_m": 6.6},
  "contours": [
    {
      "minutes": 5,
      "cell_count": 189,
      "filled_count": 34,
      "cells": [
        {"cell": "8b1fb4662475fff", "duration_s": 0.0},
        {"cell": "8b1fb4662474fff", "duration_s": 6.1},
        {"cell": "8b1fb466240dfff", "duration_s": 6.1, "filled": true},
        {"cell": "8b1fb4662471fff", "duration_s": 22.0},
        …
      ],
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [[[[2.3525623500053947, 48.85769664414983], …]]]
      }
    },
    {"minutes": 10, "cell_count": 810, "filled_count": 103, "cells": […], "geometry": {…}}
  ]
}

Réponse

ChampContenu
closingTaille de fermeture appliquée : celle demandée, 2 sinon.
contoursUn contour par durée, dans l'ordre demandé. Chaque contour contient les cellules des contours plus courts : celui de 10 minutes reprend les 189 cellules de celui de 5 minutes.
cell_countNombre de cellules du contour, cellules ajoutées par la fermeture comprises. Les cellules atteintes par le réseau sont cell_count − filled_count.
filled_countNombre de cellules ajoutées par la fermeture ; 0 avec "closing": 0.
cellsCellules par temps croissant, l'origine en tête à 0 s. Une cellule ajoutée par la fermeture porte "filled": true ; une cellule atteinte n'a pas ce champ (il ne vaut jamais false).
geometryMultipolygone GeoJSON (longitude, latitude) de la fusion des cellules du contour, trous restants compris.
Isochrone

La fermeture des isochrones

Le réseau ne traverse pas toutes les cellules : les cœurs d'îlots, les cours et les jardins sans allée n'en contiennent aucune voie. Les cellules réellement atteintes forment donc une zone criblée de trous. La fermeture les bouche : elle ajoute à chaque contour les cellules enclavées dans des vides étroits, sans jamais retirer une cellule atteinte.

Contour de 10 minutes sans fermeture : 707 cellules, 32 trous.
"closing": 0 · 707 cellules, 32 trous
Le même contour fermé : 810 cellules dont 103 ajoutées, aucun trou.
"closing": 2 · 810 cellules, dont 103 ajoutées
cellules atteintes cellules ajoutées (filled) 10 minutes à pied depuis l'Hôtel de Ville, Paris. Tracé à partir des réponses réelles de isochrone.
SujetRègle
Ce qu'elle boucheLes vides plus étroits qu'environ deux fois sa taille, en cellules, quelle que soit leur surface : un îlot, une cour en longueur, une échancrure étroite du bord. Avec la taille 2, par défaut, les vides d'environ 170 m.
Ce qu'elle laisseLes vides plus larges : un fleuve, un faisceau de voies ferrées, un grand parc ou un cimetière ne sont que grignotés sur leurs bords. À vélo, 10 minutes depuis le même point : 473 trous sans fermeture, 2 avec.
Tailleclosing de 0 à 3. Plus elle est grande, plus les vides bouchés sont larges. 0 rend le résultat brut, les seules cellules atteintes.
Temps d'une cellule ajoutéeCelui de la cellule atteinte la plus rapide autour d'elle (à une distance au plus égale à closing). À temps égal, une cellule atteinte est listée avant une cellule ajoutée.
D'un contour à l'autreChaque contour est fermé séparément, et un contour fermé contient toujours les contours plus courts fermés. Une cellule ajoutée dans un contour court peut être atteinte dans un contour plus long : elle y figure sans filled, avec son propre temps.
ItinérairesJamais fermés.

Fermée ou brute ? La fermeture donne une zone continue, proche de ce qu'on dessinerait à la main, et compte les cellules d'un îlot entouré de rues accessibles. Pour ne garder que les cellules qu'une voie traverse réellement, filtrez les cellules marquées filled, ou demandez "closing": 0.

Cellules compactées

Avec "compact": true, une cellule parente remplace ses sept filles quand toutes sont dans le contour : la liste mêle plusieurs résolutions, triée par index, sans temps ni marque filled. Les 810 cellules du contour de 10 minutes ci-dessus tiennent alors en 144 index. uncompactCells de la bibliothèque H3, à la résolution 11, redonne les cellules du contour fermé ; la géométrie ne change pas.

Usage

Joindre une isochrone à des indicateurs

Une table d'indicateurs indexée par cellule H3 de résolution 11 se joint à une isochrone par égalité d'index. Exemple : le nombre de commerces accessibles en 10 minutes à pied, à partir d'un fichier commerces.csv à deux colonnes, cell et commerces.

import httpx
import pandas as pd

r = httpx.post(
    "https://geoservice.example.com/v2/hexodos/isochrone",
    headers={"X-API-Key": GEOSERVICE_KEY},
    json={
        "origin": {"lat": 48.855199, "lon": 2.354035},
        "mode": "pedestrian",
        "contours_min": [10],
        "geometry": False,
    },
)
cellules = pd.DataFrame(r.json()["contours"][0]["cells"])  # cell, duration_s, filled
commerces = pd.read_csv("commerces.csv")                    # cell, commerces

zone = cellules.merge(commerces, on="cell", how="left").fillna({"commerces": 0})
print(zone["commerces"].sum(), "commerces à 10 minutes à pied")

# Sans les cellules ajoutées par la fermeture (colonne absente s'il n'y en a aucune) :
atteintes = zone[zone["filled"].isna()] if "filled" in zone else zone
print(atteintes["commerces"].sum(), "dans les cellules qu'une voie traverse")

Indicateurs à une autre résolution

Une table établie à une résolution plus grossière, par exemple 9 (cellules d'environ 175 m de côté), se joint en ramenant chaque cellule de l'isochrone à sa parente : h3.cell_to_parent(cell, 9) en Python, cellToParent(cell, 9) avec h3-js. Plusieurs cellules de l'isochrone partagent alors la même parente : pour un indicateur de stock (population, nombre de commerces), répartissez la valeur de la parente entre ses filles, ou ne gardez que les parentes entièrement couvertes, plutôt que de la compter plusieurs fois.

Avec "compact": true, décompactez d'abord la liste à la résolution 11 (uncompact_cells(cells, 11) en Python, uncompactCells(cells, 11) avec h3-js) : les index compactés ne sont pas de résolution 11 et ne joindraient pas.

Endpoint

État de l'index

GET/v2/hexodos/status

Indique les modes servis, l'emprise couverte et la date des données OpenStreetMap utilisées.

200 OK · réponse réelle
{
  "status": "ok",
  "index": {
    "format_version": 2,
    "resolution": 11,
    "modes": {
      "pedestrian": {"cells": 1912703, "nodes": 4651628, "transitions": 11230804, "penalty_coefficient": 0.5, "max_speed_kmh": 5.0},
      "bicycle": {"cells": 1838717, "nodes": 4092629, "transitions": 8977218, "penalty_coefficient": 0.5, "max_speed_kmh": 16.0},
      "auto": {"cells": 1101982, "nodes": 2314993, "transitions": 4118005, "penalty_coefficient": 0.25, "max_speed_kmh": 130.0}
    },
    "source": {
      "name": "ile-de-france-latest.osm.pbf",
      "sha256": "efb85f303f80c124ac9892ca19573ae0f8c238cccc69e4ff3dd1f85e2163658e",
      "osm_timestamp": "2026-09-16T20:21:21Z"
    },
    "bbox": [1.4261447, 48.1063114, 3.5617685, 49.2439152],
    "built_at": "2026-10-08T11:50:10+00:00"
  }
}
ChampContenu
index.modesModes servis, avec le nombre de cellules couvertes et la vitesse maximale de chacun.
index.bboxEmprise : longitude et latitude minimales, puis maximales. Un point hors de l'emprise n'a aucun réseau à proximité.
index.sourceFichier OpenStreetMap d'origine et date de ses données (osm_timestamp).
index.built_atDate de construction de l'index.
Limites

Ce que le service ne fait pas

SujetCe qu'il en est
Tracé sur les ruesUn itinéraire est une suite de cellules et le ruban de leur fusion, pas une ligne qui suit les rues. Pour un tracé, utilisez le calcul d'itinéraires.
GuidageAucune instruction de navigation, aucun nom de rue.
Transport en communNon pris en charge : piéton, vélo et voiture seulement.
Trajets très courtsDépart et arrivée sont ramenés au rattachement de leur cellule, en général à quelques dizaines de mètres (plus loin, jusqu'à environ 500 m, quand la cellule n'a pas de réseau : voir snap_distance_m) : sous 2 minutes, l'écart dû au rattachement domine et la durée n'est pas précise.
Trafic et horairesPas de trafic, pas d'heure de départ : les vitesses sont fixes.
Feux, virages, pentesLe temps perdu aux feux et aux carrefours est forfaitaire, sans cycle ni sens du virage. En voiture, les interdictions de tourner sont respectées, sauf les rares qui passent par une voie entière ; à vélo, elles ne sont pas prises en compte. Pas de dénivelé.
MatricesPas de matrice de temps : utilisez sources_to_targets.
EmpriseÎle-de-France seulement (voir status).

Une requête qui produirait une réponse trop grande, par exemple une isochrone voiture de longue durée, est refusée (422 limit_exceeded) plutôt que tronquée. Une isochrone fermée compte plus de cellules qu'une isochrone brute : si le refus est dû à la seule fermeture, le message l'indique, et la même requête passe avec "closing": 0.

Erreurs

Erreurs

Les erreurs d'hexodos sont au même format que celles du GeoService (application/problem+json, voir Erreurs) : testez le membre code. Leur instance est le chemin de la fonction dans le moteur (/isochrone), et l'en-tête X-GGO-Upstream vaut hexodos:….

422 Unprocessable Content · réponse réelle, point à Lyon
{
  "type": "tag:galigeo.com,2026:geoservice:no_network_nearby",
  "title": "Aucun réseau à proximité",
  "status": 422,
  "detail": "Aucun réseau du mode demandé à proximité de l'origine (environ 500 m).",
  "instance": "/isochrone",
  "code": "no_network_nearby"
}
HTTPcodeCauseQue faire
400invalid_parameterCorps illisible, champ absent, mal formé ou inconnu, coordonnées et cellule à la fois, mode inconnu, durée ou distance au-delà de la limite. Le detail nomme le champ en cause : « Champ 'contours_min' obligatoire. »Corriger la requête.
413payload_too_largeCorps de requête trop volumineuxUne requête tient en quelques centaines d'octets : vérifier ce qui est envoyé.
422no_network_nearbyAucun réseau du mode à environ 500 m du point, par exemple hors de l'empriseRapprocher le point d'une voie, ou changer de mode.
422route_impossibleDépart et arrivée non reliés par le réseau du mode (île, zone fermée)Changer de point ou de mode.
422limit_exceededRéponse trop grande, détectée pendant le calculRéduire la durée ou le nombre de contours, ou demander "closing": 0 si le message le propose.
500internal_errorErreur inattendue du moteurPrévenir Galigeo.
503index_unavailableDonnées du moteur momentanément indisponiblesRéessayer après un délai.
503service_not_configuredhexodos n'est pas ouvert sur ce serveur (erreur du GeoService)Ne pas réessayer : contacter Galigeo.