Calculer une zone de chalandise
Une zone de chalandise réelle n'est pas un disque : la Seine, une
voie ferrée ou un massif changent ce qu'on atteint en quinze
minutes bien plus qu'un rayon en kilomètres ne peut le dire. Ce
guide montre comment demander à GET /locations/search
le contour réellement atteignable en voiture, à pied ou à vélo
depuis l'un de vos sites, puis comment obtenir la population, les
ménages et le niveau de vie moyen de cette zone avec
POST /zone/stats, et enrichir une adresse précise avec
GET /address/view/{id}. Les sites que
vous interrogez viennent de votre propre référentiel ;
s'il n'existe pas encore, créez-le d'abord avec le guide
Mes lieux.
Les paramètres qui font une isochrone
Par défaut, /locations/search trie vos sites autour
d'un point avec rayon, un disque en kilomètres à vol
d'oiseau. Pour obtenir une zone de chalandise réelle, remplacez-le
par quatre paramètres :
| Paramètre | Rôle | Valeurs |
|---|---|---|
duree |
Durée de trajet en minutes — le rayon de temps, pas de distance | Entier, 1 à 30 |
mode |
Mode de déplacement de l'isochrone ; n'a de sens qu'avec duree |
auto (défaut) · pieton · velo |
circulation |
Hypothèse de circulation de l'isochrone ; n'a de sens qu'avec duree ; pointe demande la voiture |
fluide (défaut) · pointe |
polygone |
Demande le contour GeoJSON de la zone dans la réponse | Booléen, défaut false |
duree et rayon sont exclusifs
l'un de l'autre : les envoyer ensemble, ou n'envoyer
aucun des deux, est refusé en 422
(portee_ambigue) — de même qu'un mode
fourni sans duree (mode_sans_duree).
Même règle pour circulation : sans duree,
422 circulation_sans_duree ; pointe à pied
ou à vélo, 422 circulation_mode_incompatible — un
contour piéton « à l'heure de pointe » serait le même qu'en
circulation libre, et le dire vaut mieux que le laisser croire.
Aucune portée par défaut n'est prêtée d'office : un rayon supposé
serait indiscernable d'un rayon voulu.
Plan Growth
duree (et donc le mode de trajet et le polygone qui
en découlent) demande le plan
Growth. La
recherche par rayon reste accessible dès
Starter.
Un appel, une réponse
Le centre se donne par lat+lon, ou par
adresse — une adresse complète, mais aussi un simple
nom de commune. Voici la zone de chalandise à quinze minutes en
voiture autour de Lyon, contour compris :
curl "https://api.trustydata.app/services/v1/locations/search?referentiel=boutiques&adresse=Lyon&duree=15&mode=auto&polygone=true&limit=5" \
-H "Authorization: Bearer VOTRE_CLE_API"
{
"resultats": [
{
"id_externe": "LYON-BELLECOUR",
"nom_public": "Boulangerie Bellecour",
"ligne_voie": "12 Place Bellecour",
"code_postal": "69002",
"commune": "Lyon",
"latitude": 45.757814,
"longitude": 4.832011,
"distance_m": 241.7,
"ouverture": { "statut": "ouvert", "prochaine_fermeture": "2026-09-05T19:30:00+02:00" },
"statut": "actif",
"geocodage_statut": "non_requis"
}
],
"pagination": { "limit": 5, "offset": 0, "next_offset": null, "total_estime": 1 },
"point_central": {
"lat": 45.75776,
"lon": 4.83201,
"adresse_resolue": "Lyon",
"precision": "commune",
"commune": "Lyon",
"code_insee": "69382"
},
"portee": {
"type": "isochrone",
"duree_min": 15,
"mode": "auto",
"circulation": "fluide",
"polygone": { "type": "Polygon", "coordinates": [ [ [4.79, 45.72], [4.91, 45.73], "…" ] ] }
},
"attribution": "Données cartographiques © les contributeurs OpenStreetMap, sous licence ODbL — https://www.openstreetmap.org/copyright"
}
Trois blocs à retenir. point_central dit où la
recherche a réellement porté — ici precision: "commune",
parce que la saisie ne désignait ni voie ni numéro : le centre est
celui de la commune, à quelques kilomètres près sur une grande
ville. portee.polygone porte le contour, présent
seulement parce que polygone=true a été demandé (ici
tronqué pour la lisibilité — un vrai contour compte des dizaines de
points). Et chaque entrée de resultats[] garde sa
distance_m à vol d'oiseau : c'est elle qui a classé la
liste, pas le contour, qui ne sert qu'à délimiter qui entre dans la
recherche.
attribution n'apparaît que parce que le moteur
d'itinéraire a été sollicité (une duree, ou
distances=true sur un rayon) : la mention
OpenStreetMap/ODbL est alors obligatoire partout où
le résultat est affiché — voir Attribution OSM.
Fluide ou heure de pointe
Par défaut, une isochrone est calculée en circulation
libre : chaque tronçon est parcouru à sa vitesse de base
(la limitation OpenStreetMap, ou la vitesse par défaut de sa
catégorie). C'est circulation=fluide, et c'est ce que
l'API a toujours fait. À 15 minutes du 1 rue Scribe à Paris, en
voiture, cela fait 131,3 km² et 2 334 839 habitants — une zone qui
déborde largement le périphérique, parce qu'à 30 km/h de moyenne on
va loin en un quart d'heure.
circulation=pointe calcule la même zone à
l'heure de pointe du matin, un jour ouvré vers 08:30.
Les vitesses sont alors des vitesses typiques
modélisées : à chaque tronçon s'applique un facteur qui
dépend de sa classe de voie (autoroute, primaire, secondaire,
tertiaire, desserte) et de la densité de population de son
environnement (carreaux INSEE Filosofi de 200 m, sur 3 km autour),
calibré pour que Paris rende ce que l'on observe à cette heure, et
validé sur Lyon, Marseille et Saint-Lô. Ce n'est ni une mesure rue
par rue, ni du trafic temps réel : une hypothèse de circulation, la
même pour tout le monde, documentée. Même centre, même durée :
curl -X POST "https://api.trustydata.app/services/v1/zone/stats" \
-H "Authorization: Bearer VOTRE_CLE_API" -H "Content-Type: application/json" \
-d '{"adresse": "1 rue Scribe, 75009 Paris", "duree": 15, "mode": "auto", "circulation": "pointe"}'
{
"point_central": {
"lat": 48.870618,
"lon": 2.329855,
"adresse_resolue": "1 Rue Scribe, 75009 Paris 9e Arrondissement",
"id": "af6bc041-64ae-463b-a310-f8f7f3af97e7",
"precision": "adresse",
"commune": null,
"code_insee": null
},
"portee": {
"type": "isochrone",
"duree_min": 15,
"mode": "auto",
"circulation": "pointe",
"rayon_km": null,
"polygone": null
},
"surface_km2": 53.8,
"population": 1125636,
"menages": 579446,
"menages_pauvres": 85483,
"niveau_de_vie_moyen": 39336,
"iris_couverts": 695,
"carreaux": {
"total": 1391,
"estimes": 54
},
"source": {
"filosofi_millesime": 2021,
"contours_iris_millesime": 2026
},
"attribution": "Source : INSEE, Filosofi 2021 (carreaux 200 m) ; IGN, Contours IRIS 2026. Itinéraires : Données cartographiques © les contributeurs OpenStreetMap, sous licence ODbL — https://www.openstreetmap.org/copyright"
}
53,8 km² et 1 125 636 habitants au lieu de 131,3 et
2 334 839 : la zone tient à peu près dans Paris et sa bordure
immédiate, de Levallois à Bagnolet et de Clichy à la Seine —
comparable à ce que rendent les outils de
géomarketing à la même heure. La réponse répète le réglage dans
portee.circulation, fluide compris : un
chiffre ne se lit pas sans l'hypothèse qui le porte. Le même
paramètre existe sur GET /locations/search, avec le
même écho.
Ce que pointe n'est pas
Un tronçon précis saturé à 8 h 15 n'est pas connu : le modèle voit
une catégorie de voie et une densité. Les grands axes en zone dense
sont ralentis d'un tiers à moitié, les rues de desserte en zone
rurale pas du tout. Et une isochrone pointe demande
une hypothèse que la plateforme doit porter : si elle n'est pas
ouverte, la route rend 503 circulation_indisponible
— GET /version l'annonce dans
circulation_pointe.
Lire le contour
portee.polygone est un objet GeoJSON standard —
Polygon ou MultiPolygon selon la forme de
la zone atteignable — en coordonnées WGS84
(longitude, latitude, dans cet ordre). C'est le format que
consomment nativement Leaflet, Mapbox GL ou MapLibre pour tracer un
calque : pas de reprojection à faire.
const zone = reponse.portee.polygone;
L.geoJSON(zone, { style: { color: 'seagreen', weight: 2, fillOpacity: 0.1 } })
.addTo(carte);
Le contour pèse 10 à 20 Ko selon la complexité de
la zone — c'est pour cela qu'il n'est jamais renvoyé par défaut :
une intégration qui ne veut que la liste des sites (un widget « le
plus proche de vous ») n'a pas à le transporter. Ne demandez
polygone=true que sur l'appel qui affiche
effectivement une carte.
Agréger — sur toute la zone
Le contour délimite ; POST /zone/stats compte. Avec le
même centre, la même durée et le même mode que
l'appel précédent, il rend ce que l'INSEE sait de ceux qui habitent
la zone — le contour est déjà calculé côté API, il n'est pas
recalculé, et l'appel est compté une fois quelle que soit la portée :
curl -X POST "https://api.trustydata.app/services/v1/zone/stats" \
-H "Authorization: Bearer VOTRE_CLE_API" -H "Content-Type: application/json" \
-d '{"adresse": "Lyon", "duree": 15, "mode": "auto"}'
{
"point_central": {
"lat": 45.758880705795356,
"lon": 4.835271469337425,
"adresse_resolue": "LYON",
"id": null,
"precision": "commune",
"commune": "LYON",
"code_insee": "69123"
},
"portee": {
"type": "isochrone",
"duree_min": 15,
"mode": "auto",
"circulation": "fluide",
"rayon_km": null,
"polygone": null
},
"surface_km2": 136.8,
"population": 737125,
"menages": 362325,
"menages_pauvres": 54799,
"niveau_de_vie_moyen": 27473,
"iris_couverts": 367,
"carreaux": {
"total": 3064,
"estimes": 690
},
"source": {
"filosofi_millesime": 2021,
"contours_iris_millesime": 2026
},
"attribution": "Source : INSEE, Filosofi 2021 (carreaux 200 m) ; IGN, Contours IRIS 2026. Itinéraires : Données cartographiques © les contributeurs OpenStreetMap, sous licence ODbL — https://www.openstreetmap.org/copyright"
}
Réponse obtenue avec une clé du plan
Growth — la
route demande ce plan au minimum, et rend la même chose en
Business.
Quatre choses à lire. population,
menages et menages_pauvres sont des
sommes des carreaux INSEE Filosofi de 200 m qui
tombent dans la zone, pondérées par la part de chaque carreau
dedans : un carreau à cheval sur la limite compte pour ce qui est à
l'intérieur. niveau_de_vie_moyen est une moyenne par
personne et par an, en euros — la seule grandeur de revenu qu'un
carroyage permet d'additionner ; il vaut null si la
population est nulle. iris_couverts compte les
quartiers IRIS dont le contour touche la zone : un compte, pas une
somme. Et carreaux.estimes dit combien de carreaux
portent des valeurs imputées par l'INSEE au titre du secret
statistique — souvent la majorité hors des villes denses, et c'est la norme du
fichier, pas un défaut de votre zone.
attribution est à reproduire avec tout chiffre
affiché : elle nomme les millésimes de Filosofi et des
Contours IRIS, lus à chaque appel, et la mention OpenStreetMap s'y
ajoute parce que la portée est une isochrone.
Trois façons de décrire la zone
- Une durée —
adresse(oulat+lon) +duree(1 à 30 min) +mode(autopar défaut,pieton,velo) : l'exemple ci-dessus. - Un rayon — un centre +
rayon(1 à 50 km), disque à vol d'oiseau, sans moteur d'itinéraire. - Un contour —
polygone, un GeoJSONPolygonouMultiPolygonWGS84 pris tel quel : celui queportee.polygonevous a rendu plus haut, ou un contour dessiné à la main. Seul, sans centre.
Une seule de ces trois formes par appel — deux à la fois font un
422 portee_ambigue. Le plafond de surface est de
10 000 km² (422 zone_trop_grande) ;
un rayon de 50 km en fait 7 850, un isochrone de 30 minutes en
voiture rarement plus de 3 000. Et une zone sans aucun carreau — en
mer, à l'étranger — est un 200 avec des zéros, pas une
erreur, comme une recherche sans résultat.
Enrichir — par adresse
Le contour délimite une zone et /zone/stats la
chiffre ; ni l'un ni l'autre ne dit rien d'une
adresse précise. Pour qualifier ce que vous voyez sur la
carte — une adresse candidate à un nouveau site, un point de
passage identifié dans la zone — appelez
GET /address/view/{id} sur l'adresse qui vous
intéresse :
curl "https://api.trustydata.app/services/v1/address/view/69382_1080_00012" \
-H "Authorization: Bearer VOTRE_CLE_API"
La richesse de la réponse dépend du plan de votre clé, comme pour
tout endpoint /address/* : le plan
Discovery rend
déjà l'adresse restituée ; le plan
Starter ajoute
la position (WGS84 et Lambert 93) ; le plan
Growth ajoute le
bloc geocoding, dont geocoding.code_iris —
l'identifiant de la zone IRIS INSEE qui contient l'adresse ; le plan
Business ajoute
statistical_grid, la maille de 200 m de la grille
Filosofi (INSEE) dans laquelle tombe cette adresse précise, avec son
nombre d'habitants et de ménages.
Deux échelles, deux endpoints — ne pas les additionner.
statistical_grid décrit la maille de 200 m
d'une adresse, appelée une par une ;
POST /zone/stats additionne toutes les
mailles d'un contour, au prorata de leur surface. Sommer vous-même
les mailles des adresses que vous avez enrichies ne redonne pas le
chiffre de la zone — mailles à cheval sur le contour, doubles
comptes — et n'a plus de raison d'être. Ce que la zone ne rend pas :
une médiane (elle ne s'additionne pas), des tranches d'âge, un
détail par IRIS.
Ce que le contour ne dit pas
-
Le contour ne porte pas de chiffre lui-même.
Population, ménages et niveau de vie moyen « de la zone » viennent
de
POST /zone/stats, avec le même centre et la même durée, ou en lui renvoyantportee.polygonetel quel. -
Le tri des résultats reste à vol d'oiseau.
portee.polygonedélimite qui entre dans la recherche ; il ne change pas l'ordre deresultats[], toujours classé surdistance_m. -
L'enrichissement routier s'arrête à 25 résultats.
Avec
distances=true, les 25 premiers résultats de la page gagnentduree_setdistance_routiere_m(calculés dans lemodede la portée) et toujours en circulation libre, y compris sous une portéecirculation=pointe; au-delà, les deux champs valentnull. C'est un enrichissement de la page rendue, pas un second tri : voir Mes lieux pour le détail des bornes et de la pagination.
Questions fréquentes
Quel appel calcule une zone de chalandise ?
GET /services/v1/locations/search avec adresse
(ou lat/lon), duree de 1 à 30 minutes,
mode auto, pieton ou velo,
et polygone=true pour recevoir le contour GeoJSON. Plan Growth.
Comment obtenir la population de la zone ?
POST /services/v1/zone/stats, avec la même durée et le même
mode, ou un rayon, ou le contour lui-même : population, ménages, ménages
pauvres, niveau de vie moyen et IRIS couverts, sommés sur les carreaux
Filosofi 200 m (INSEE, millésime 2021). Plan Growth.
Fluide ou heure de pointe ?
circulation=fluide (défaut) ou circulation=pointe.
En pointe, les vitesses modélisées de l'heure de pointe du matin réduisent
le contour ; la réponse rappelle le réglage dans portee.circulation.
Aller plus loin
- Démo — Zone de chalandise — tester en direct sans écrire de code
- Cas d'usage — Zone de chalandise
- Article — Calculer une zone de chalandise
- Référence complète —
GET /locations/searchetPOST /zone/statsen détail, tous les paramètres - Mes lieux — créer et alimenter le référentiel de sites interrogé ici
- Attribution OSM — la mention à afficher dès qu'une
dureeentre en jeu
Sources des données mobilisées par ce guide : le référentiel BAN officiel (IGN) et l'INSEE (IRIS, grille Filosofi) pour les adresses ; OpenStreetMap, sous licence ODbL, pour le réseau routier qui dessine l'isochrone ; l'INSEE (carroyage Filosofi 2021) et l'IGN (Contours IRIS 2026) pour les chiffres de zone.