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
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.
| id | Complément | État |
|---|---|---|
municipalities | noyau | OGL-Canada (subdivisions de recensement de StatCan). Tuiles en direct. L'identification exige le bake Land. |
parks | noyau | OGL-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-lands | noyau | OGL-Canada. Limites législatives et administratives, pas des territoires traditionnels. Tuiles en direct. |
survey.dls | legal-land | Donné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.nts | legal-land | OGL-Canada, Index du Système national de référence cartographique de RNCan. 8 couches sources avec étiquettes. |
energy.wells … energy.geothermal | energy | Énergie 0.1. Attribution AER / Alberta Energy. Voir Profil énergie. |
agriculture.crops … agriculture.bc-capability | agriculture | Superpositions Agriculture 0.1. AAC / OGL-AB / OGL-C.-B. Pas une carte agricole nationale. Voir Profil agriculture. |
survey.geographic-township | legal-land | L'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-lots | legal-land | Lots 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-orders | agriculture | Pé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.parcels | legal-land | Tout 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.airports | remote | Éloigné 0.2. Aéroports ANS de Transports Canada. Superposition seulement. Tuiles de superposition en direct. Voir Profil éloigné. |
mining.occurrences … mining.sk-potential | mining | Superpositions 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.water | la couche water du fond de carte, z0–15 |
rail, ca.rail | la couche roads du fond de carte filtrée sur kind: rail, z3–15 |
remote.roads | la 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 /layersne les liste plus : le catalogue compte 29 entrées.GET /layers/waterrépond410 Goneavecuse_insteadqui nomme le remplacement, plutôt qu'un404. « 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,municipalitiesrenvoie200avec la superposition des municipalités et sans celle de l'eau. C'est important : un identifiant de superposition inconnu est un400qui fait échouer toute la requête de style, donc si un identifiant retiré était traité comme inconnu, un client dont l'URL dit encorewaterperdrait sa carte entière, pas une couche. - Les requêtes de tuiles sous
/layers/water/{z}/{x}/{y}répondent404.
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 :
| Couche | source_layers |
|---|---|
survey.dls | ab_twp, bc_twp, mb_twp, sk_twp, ab_sec … sk_lsd (seize : quatre provinces x canton, section, quart, subdivision légale), plus ab_twp_label … sk_lsd_label |
survey.nts | bc_series, bc_block, bc_unit, bc_qtr_unit, plus bc_series_label … bc_qtr_unit_label |
survey.geographic-township | on_twp, on_con, on_lot, plus on_twp_label, on_con_label, on_lot_label |
survey.river-lots | mb_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.
| SKU | Mensuel | Annuel | Capacités accordées |
|---|---|---|---|
addon-legal-land | 39 $ | 390 $ | legalLand |
addon-energy | 129 $ | 1 290 $ | energy, legalLand |
addon-agriculture | 69 $ | 690 $ | agriculture, legalLand |
addon-mining | 49 $ | 490 $ | mining |
addon-remote | 39 $ | 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.