Aller au contenu

Couches

unmap n'est pas un hôte SIG générique. Les données canadiennes officielles passent par un catalogue nommé : chaque couche a un identifiant, une licence, une attribution, une couverture et des trous connus. Les tuiles sont des archives nommées sur R2, servies comme les courbes de niveau : lecture par plage et Cache API, jamais de calcul.

GET /layers
GET /layers/{id}
GET /layers/{id}/{z}/{x}/{y}
GET /styles/{style}.json?overlays=municipalities,survey.dls
GET /identify?at=lng,lat
GET /data/query?layer=energy.wells&bbox=minlng,minlat,maxlng,maxlat
npm i @unmap/sdk
résultat en direct
le code qui l’a produit
import { Unmap } from "@unmap/sdk";

const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  style: "base",
  overlays: ["municipalities"],
  center: [-114.0719, 51.0447],
  zoom: 8,
});

Comment les identifiants sont nommés

Un identifiant nomme la chose, jamais le pays. wells, survey.dls. La couverture réelle d'une couche est portée par le champ jurisdiction, lisible par machine et extensible; l'identifiant est un nom stable et ne l'est pas.

Les couches de fondation portaient autrefois un préfixe ca. que les couches sectorielles n'avaient pas, ce qui se lisait comme une affirmation géographique sans en être une. Toutes les couches de ce catalogue sont canadiennes, et la plupart des couches sectorielles ne couvrent que l'Alberta : ca.rail et energy.wells se trouvaient de part et d'autre d'une frontière qui suivait le palier commercial, pas le pays. Le préfixe est supprimé.

Six des huit identifiants renommés continuent de fonctionner : ca.survey.dls renvoie survey.dls, et de même pour ca.municipalities, ca.parks, ca.aboriginal-lands, ca.survey.nts et ca.survey.parcels. ca.water et ca.rail sont retirés avec les couches qu'ils aliasaient, plutôt que redirigés ailleurs. Ce sont des alias, pas des entrées du catalogue : /layers liste 30 couches sous les nouveaux noms. Préférez les nouveaux identifiants; les anciens ne vous seront pas retirés.

Quand unmap desservira un autre pays, c'est le jeu de données qui décide. Un puits reste un puits : les puits américains élargiront energy.wells à ["CA-AB", "US-TX"]. Un système d'arpentage, non : l'arpentage des terres fédérales et le Public Land Survey System sont deux systèmes distincts, donc survey.dls et survey.plss, deux identifiants que leurs propres noms distinguent déjà.

Catalogue

GET /layers retourne toutes les lignes. GET /layers/{id} en retourne une. Les deux sont des métadonnées publiques : licence, attribution, couverture, trous connus, bandes de zoom, et le complément le cas échéant. Les clés d'objet R2 n'y figurent pas. Une couverture incomplète n'est jamais cachée.

Identifiants Canada 0.1–0.4. Toutes les archives de ce tableau sont téléversées et desservies, et chaque entrée indique dans ses champs coverage et jurisdiction jusqu'où elle porte réellement.

idComplémentÉtat
municipalitiesnoyauOGL-Canada (subdivisions de recensement de StatCan). Tuiles en direct. L'identification exige le bake Land.
parksnoyauOGL-Canada (BDCAPC d'ECCC, déc. 2025). Le registre des aires protégées : 22 438 aires, terrestres et marines, avec type de désignation et noms en/fr/autochtones. Nationale.
aboriginal-landsnoyauOGL-Canada. Limites législatives et administratives, pas des territoires traditionnels. Tuiles en direct.
survey.dlslegal-landDonnées ouvertes provinciales : AB (OGL-AB, ATS v4.1), SK (GOS Standard Unrestricted Use v2.0, GeoHub), MB (licence OpenMB, Initiative des terres du Manitoba), Peace en C.-B. (OGL-C.-B., BC Data Catalogue). 32 couches sources avec étiquettes.
survey.ntslegal-landOGL-Canada, Index du Système national de référence cartographique de RNCan. 8 couches sources avec étiquettes.
energy.wellsenergy.geothermalenergyÉnergie 0.1. Attribution AER / Alberta Energy. Voir Profil énergie.
agriculture.cropsagriculture.bc-capabilityagricultureSuperpositions Agriculture 0.1. AAC / OGL-AB / OGL-C.-B. Pas une carte agricole nationale. Voir Profil agriculture.
survey.geographic-townshiplegal-landL'arpentage propre à l'Ontario : cantons nommés, rangs, lots. Ni ARD ni SNRC. OGL-Ontario (Information sur les terres de l'Ontario). 6 couches sources avec étiquettes.
survey.river-lotslegal-landLots riverains du Manitoba, antérieurs à l'ARD et arpentés depuis les rivières plutôt que sur une grille. Licence OpenMB (Manitoba Land Initiative). 2 couches sources avec étiquettes.
agriculture.soil-ordersagriculturePédo-paysages du Canada v3.2 d'AAC, ~1:1M. La seule couche agricole qui atteint les provinces de l'Atlantique. Contexte régional, pas un levé pédologique.
survey.parcelslegal-landTout le cadastre ParcelMap BC, lots urbains compris, avec identification et recherche par PID. Pas de la terre agricole : croisez avec agriculture.alr pour cela. OGL-C.-B.
remote.airportsremoteÉloigné 0.2. Aéroports ANS de Transports Canada. Superposition seulement. Tuiles de superposition en direct. Voir Profil éloigné.
mining.occurrencesmining.sk-potentialminingSuperpositions Minier 0.1. Identification Minier 0.2 via tables Land. Les titres sont energy.mineral-tenure. Voir Profil minier.

L'activité et la production Petrinex, ainsi que la Direction du pétrole du Manitoba, sont retenues et ne figurent pas au catalogue.

Une archive absente est un 404 { "error": "layer archive not configured" }. Un zoom hors des bandes de la couche est un 204. Cela suffit pour composer des styles et écrire des clients avant que les objets n'arrivent. Les tests d'archives en direct ne s'exécutent que si UNMAP_CANADA_LAYERS=1.

aboriginal-lands est de la géographie administrative ouverte de RNCan. Ce n'est pas une carte des nations autochtones ni des territoires traditionnels. Citez known_gaps sur /layers/aboriginal-lands.

Superpositions

?overlays= sur une URL de style ajoute des sources et des couches ligne/étiquette uniquement palette, au-dessus des routes et sous les étiquettes. La couleur vient de la saveur du style, jamais d'un hexadécimal en dur, pour qu'un thème recolore la superposition avec le reste de la carte. Un identifiant inconnu est un 400. Une superposition soumise à complément, sur une clé qui ne l'a pas, est un 403 addon_required.

import { Unmap } from "@unmap/sdk";
 
const unmap = new Unmap({
  key: "um_live_...",
  container: "map",
  style: "base",
  overlays: ["municipalities"],
  center: [-114.0719, 51.0447],
  zoom: 8,
});

profile: "energy", agriculture, remote ou mining est un préréglage de composition pour cet ensemble. Ce n'est pas un style. Quand profile et overlays sont tous les deux présents, overlays l'emporte. Voir Énergie, Agriculture, Éloigné et Minier.

Identification

GET /identify?at=lng,lat (SDK : unmap.identify()) est l'API d'identification. Elle indique quels polygones du catalogue contiennent un point. Ce n'est pas du géocodage inverse : la réponse vient de ST_Contains dans PostGIS, pas d'un classement civique. La liste par bbox est GET /data/query / unmap.data.query() plus bas.

layers vaut municipalities par défaut, pour qu'une clé du noyau puisse identifier sans le complément legal-land. Demandez survey.dls ou survey.nts pour la cellule d'arpentage; ces couches exigent le complément et comptent sous legal-land. Un appel limité au noyau compte comme layers. lon et lat sont acceptés à la place de at. geometry=true inclut les polygones lorsque la fiche en a un.

Identifiants reconnus aujourd'hui : municipalities, survey.dls, survey.nts, survey.parcels, energy.wells, energy.pipelines, energy.facilities, energy.fields, energy.petroleum-tenure, energy.mineral-tenure, plus les identifiants miniers. Tout autre identifiant, y compris les couches tuilées du catalogue sans table (parks, aboriginal-lands, energy.ccs, energy.geothermal, remote.airports), est un 400 qui liste ces identifiants. Les couches énergie exigent le module energy. survey.parcels exige legal-land. Les deux tolèrent l'absence de table : une relation manquante ne renvoie aucune entité, pas un 500. Les résultats restent vides tant que la table correspondante n'est pas chargée.

import { Unmap } from "@unmap/sdk";
 
const unmap = new Unmap({ key: "um_live_..." });
 
const { at, results } = await unmap.identify({
  at: [-114.0719, 51.0447],
  layers: ["municipalities", "survey.dls"],
  geometry: true,
});
GET /identify?at=-114.0719,51.0447&layers=municipalities
{
  "at": [-114.0719, 51.0447],
  "results": [
    { "layer": "municipalities", "id": "ab:calgary", "name": "Calgary", "province": "AB" }
  ]
}

municipalities est exportée par pipeline/legal-land/ depuis public.municipal_boundaries (Township Canada) et cuite dans l'image Land comme municipalities.copy. Tant que ce COPY n'est pas dans l'image en service, results est []. C'est le vide honnête, pas une erreur. Les tuiles de superposition de municipalities peuvent quand même se peindre. Voir Couverture.

Requête

GET /data/query?layer=&bbox= (SDK : unmap.data.query()) liste les entités d'une couche du catalogue qui intersectent une emprise. Mêmes tables PostGIS que l'identification. Mêmes règles de complément et de comptage. La limite vaut 50 par défaut et est bornée à 1–50. geometry=true inclut les géométries lorsque la fiche en a une. Les résultats restent vides tant que la table n'est pas chargée.

Identifiants interrogeables : le même ensemble que l'identification (municipalities, survey.dls, survey.nts, survey.parcels, energy.wells, energy.pipelines, energy.facilities, energy.fields, energy.petroleum-tenure, energy.mineral-tenure, mining.occurrences, mining.prospectivity, mining.sk-potential). Une couche tuilée du catalogue (parks, rail, aboriginal-lands, water, energy.ccs, energy.geothermal, remote.*, autres superpositions agriculture) est un 501 qui liste ces identifiants. Un identifiant inconnu est un 400. Pas de filtre polygone arbitraire, pas de GeoAI, pas de catalogue d'imagerie.

import { Unmap } from "@unmap/sdk";
 
const unmap = new Unmap({ key: "um_live_..." });
 
const { layer, bbox, results } = await unmap.data.query({
  layer: "energy.wells",
  bbox: [-114.3, 50.9, -113.8, 51.2],
  limit: 20,
});
GET /data/query?layer=energy.wells&bbox=-114.3,50.9,-113.8,51.2&limit=20
{
  "layer": "energy.wells",
  "bbox": [-114.3, 50.9, -113.8, 51.2],
  "results": []
}

Un tableau results vide est le vide honnête lorsque la table Énergie n'est pas chargée, pas une erreur. /identify reste l'API point-dans-polygone.

Couches retirées

water, rail et remote.roads ont été retirées le 2026-09-15 : le fond de carte dessine déjà les trois, en mieux. remote.roads avait un second problème : le profil remote existe pour l'accès par routes d'hiver et de glace, et le réseau RRN toutes saisons ne porte aucun statut hivernal, donc elle n'a jamais répondu à la question pour laquelle elle avait été ajoutée.

Identifiant retiréÀ utiliser à la place
water, ca.waterla couche water du fond de carte, z0–15
rail, ca.railla couche roads du fond de carte filtrée sur kind: rail, z3–15
remote.roadsla couche roads du fond de carte, z3–15, avec kind, ref, network et name:fr

Les deux couches du fond de carte vont jusqu'à z15 là où les superpositions s'arrêtaient à z12, et elles portent name:fr ainsi que les champs name2/name3 et script qui rendent les noms autochtones. Les superpositions portaient id, name et region : rien qui ne soit déjà dans le fond de carte.

Ce que le retrait signifie en pratique :

  • GET /layers ne les liste plus : le catalogue compte 29 entrées.
  • GET /layers/water répond 410 Gone avec use_instead qui nomme le remplacement, plutôt qu'un 404. « Retirée, utilisez ceci » n'est pas le même fait que « n'existe pas ».
  • Une URL de style qui en nomme une continue de fonctionner. ?overlays=water,municipalities renvoie 200 avec la superposition des municipalités et sans celle de l'eau. C'est important : un identifiant de superposition inconnu est un 400 qui fait échouer toute la requête de style, donc si un identifiant retiré était traité comme inconnu, un client dont l'URL dit encore water perdrait sa carte entière, pas une couche.
  • Les requêtes de tuiles sous /layers/water/{z}/{x}/{y} répondent 404.

Les grilles d'arpentage : une source, plusieurs niveaux

survey.dls, survey.nts, survey.geographic-township et survey.river-lots sont chacune une seule archive contenant tous les niveaux de cet arpentage, chacun étant sa propre couche source vectorielle avec sa propre plage de zoom dans le fichier. Ce sont quatre couches distinctes parce que ce sont quatre systèmes d'arpentage distincts : un « Lot 2 Con 4 Osprey » ontarien ne s'exprime pas en quart de section ARD, et les lots riverains du Manitoba sont antérieurs à la grille ARD. GET /layers/{id} publie la liste sous source_layers :

Couchesource_layers
survey.dlsab_twp, bc_twp, mb_twp, sk_twp, ab_secsk_lsd (seize : quatre provinces x canton, section, quart, subdivision légale), plus ab_twp_labelsk_lsd_label
survey.ntsbc_series, bc_block, bc_unit, bc_qtr_unit, plus bc_series_labelbc_qtr_unit_label
survey.geographic-townshipon_twp, on_con, on_lot, plus on_twp_label, on_con_label, on_lot_label
survey.river-lotsmb_river_lots, plus mb_river_lots_label

Chaque niveau de polygones a une couche de points _label correspondante contenant descriptor, la description légale elle-même (NW-25-24-1-W5 pour l'ARD, la désignation de feuillet pour le SNRC, « Lot 2 Con 4 Osprey » pour un lot ontarien). Dessinez les polygones en lignes et les étiquettes en couche symbol sur descriptor : une grille de carrés identiques est illisible sans elles, et un symbol placé sur les polygones tombe au mauvais endroit.

Donc une seule source dans votre style et une seule requête de tuile par tuile, quels que soient les niveaux dessinés. Ajoutez le niveau voulu comme sa propre couche :

map.addSource("dls", {
  type: "vector",
  tiles: ["https://api.unmap.dev/layers/survey.dls/{z}/{x}/{y}?key=um_live_..."],
  minzoom: 0,
  maxzoom: 14
});
 
// Les cantons de loin, les quarts de section seulement quand ils sont lisibles.
map.addLayer({
  id: "twp", type: "line", source: "dls", "source-layer": "ab_twp",
  paint: { "line-color": "#294049", "line-width": 1 }
});
map.addLayer({
  id: "qtr", type: "line", source: "dls", "source-layer": "ab_qtr",
  minzoom: 11,
  paint: { "line-color": "#294049", "line-width": 0.5 }
});
 
// La description légale, depuis la couche de points prévue pour cela.
map.addLayer({
  id: "twp-label", type: "symbol", source: "dls", "source-layer": "ab_twp_label",
  layout: { "text-field": ["get", "descriptor"], "text-size": 11 }
});

Le canton couvre z0 à z14; section, quart et subdivision légale couvrent z9 à z14. Une requête pour ab_lsd à z5 est légitimement vide, pas une erreur. Idem pour SNRC : bc_series couvre z0 à z14, les trois niveaux plus fins z9 à z14.

?overlays=survey.dls fonctionne toujours et dessine tous les niveaux pour vous. Utilisez la source directement quand vous voulez choisir quels niveaux apparaissent à quel zoom.

Compléments et comptage

Deux mots qui se ressemblent et qui ne sont pas interchangeables. Un SKU est ce que vous achetez et ce qui vous est facturé, par exemple addon-energy. Une capacité est ce qu'il vous permet de faire, par exemple energy. Les deux diffèrent dès qu'un SKU en comprend un autre, et /account/me renvoie les deux.

SKUMensuelAnnuelCapacités accordées
addon-legal-land39 $390 $legalLand
addon-energy129 $1 290 $energy, legalLand
addon-agriculture69 $690 $agriculture, legalLand
addon-mining49 $490 $mining
addon-remote39 $390 $remote

Les couches de fondation ca.* sont dans le noyau. survey.* exige legalLand. energy.* exige energy, agriculture.* exige agriculture, remote.* exige remote, mining.* exige mining. Comme Énergie et Agriculture comprennent legalLand, l'un ou l'autre donne accès aux grilles d'arpentage sans acheter Terres légales séparément.

Une requête soumise à complément, sur une clé qui n'a pas la capacité :

{
  "error": "Legal Land requires the Legal Land add-on",
  "code": "addon_required",
  "capability": "legalLand",
  "addon": "addon-legal-land",
  "message": "Legal Land requires the Legal Land add-on for production use."
}

addon nomme le SKU le moins cher qui l'accorderait, c'est-à-dire quoi acheter. Les clés sans compte (fondateur et intégration) en sont exemptées, comme pour la politique d'origine.

Gratuit en développement. Sur le forfait dev, toutes les capacités sont débloquées depuis une origine de développement : localhost, 127.0.0.1, *.localhost, *.pages.dev et *.workers.dev. Aucune carte, aucun abonnement, rien à acheter. Construisez toute l'intégration d'abord et payez au moment de la mise en production. La même clé depuis une origine de production répond 403 dev_only, dont le message nomme l'étape qui règle vraiment le problème : souscrire un forfait, et non acheter un complément.

Ce droit a un plafond : 5 000 appels premium par mois, toutes capacités restreintes confondues. Il existe pour empêcher que la gratuité de développement serve de production gratuite, et non pour vous compter : c'est une somme sur le compteur d'usage existant, pas une allocation distincte. Au-delà, les capacités restreintes répondent 403 usage_limit_reached tandis que les tuiles, styles, géocodage et itinéraires du noyau continuent normalement. Remise à zéro au début du mois.

Comment en acheter un. Les compléments sont des éléments fixes ajoutés à un forfait payant, facturés selon le même intervalle que le forfait (un abonnement mensuel prend des compléments mensuels, un abonnement annuel des compléments annuels), gérés depuis la page de facturation de votre tableau de bord ou avec POST /account/billing/addons. Envoyez l'ensemble complet que vous voulez obtenir, pas un delta, pour qu'une nouvelle tentative soit sans risque :

{ "addons": ["addon-energy", "addon-remote"] }

Stripe porte l'autorisation. La route met à jour votre abonnement et l'octroi atteint vos clés par webhook quelques secondes plus tard : relisez /account/me plutôt que de supposer que l'appel l'a accordé.

Une capacité n'est jamais facturée deux fois. Ajouter Énergie à un compte qui détient déjà Terres légales remplace la ligne Terres légales dans la même mise à jour au lieu de s'y empiler, puisque Énergie accorde déjà legalLand. La facture augmente de 129 $ moins la partie inutilisée des 39 $, et non de 129 $.

L'ajout prend effet tout de suite, le retrait attend. Un ajout est calculé au prorata et prend effet immédiatement. Un retrait est programmé pour la fin de la période déjà payée : la capacité continue de fonctionner jusque-là, et /account/me la signale dans addonsRemoving avec la date dans addonsRemovingAt tout en la listant toujours dans addons et capabilities, parce que tout cela est vrai en même temps. Redemander le SKU avant cette date annule le retrait. Annuler l'abonnement révoque tous les compléments.

Les compléments exigent un forfait payant : sur le forfait dev il n'y a aucun abonnement auquel les rattacher, et l'appel répond 400. Un complément dont le prix Stripe n'est pas encore configuré répond 503 billing_required en nommant lequel, plutôt qu'un échec vague.

Comptage. Une requête vaut un appel, quoi qu'elle touche. Les lectures du catalogue (GET /layers, GET /layers/{id}) et les tuiles sans complément comptent comme layers. Les tuiles soumises à complément comptent sous un seau d'usage nommé d'après la capacité en forme filaire : legal-land, energy, agriculture, remote, mining. Ces noms de seaux portent un trait d'union et les noms de capacités non : la différence est voulue, car les seaux sont un format filaire de facturation antérieur à la séparation SKU/capacité et ne peuvent pas être renommés sans casser les lignes d'usage déjà enregistrées. Le document de style lui-même compte toujours comme styles; ce sont les requêtes de tuiles de superposition qui sont facturées comme couches.

Il n'y a pas d'allocation d'appels distincte par complément. Une requête soumise à complément puise dans les appels inclus de votre forfait comme n'importe quelle autre : le complément est ce qui l'autorise, pas ce qui la paie.

Voir Erreurs pour le contrat addon_required.