TrustyData Docs
Site Tarifs Contact

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ètreRôleValeurs
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_indisponibleGET /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éeadresse (ou lat+lon) + duree (1 à 30 min) + mode (auto par 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 contourpolygone, un GeoJSON Polygon ou MultiPolygon WGS84 pris tel quel : celui que portee.polygone vous 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 renvoyant portee.polygone tel quel.
  • Le tri des résultats reste à vol d'oiseau. portee.polygone délimite qui entre dans la recherche ; il ne change pas l'ordre de resultats[], toujours classé sur distance_m.
  • L'enrichissement routier s'arrête à 25 résultats. Avec distances=true, les 25 premiers résultats de la page gagnent duree_s et distance_routiere_m (calculés dans le mode de la portée) et toujours en circulation libre, y compris sous une portée circulation=pointe ; au-delà, les deux champs valent null. 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

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.