Aller au contenu

Appeler l'API directement

Appelez toute API Unmap directement par HTTPS à https://api.unmap.dev. Les paquets @unmap/* joignent votre clé, préparent les requêtes et analysent les réponses, mais vous pouvez utiliser curl, Python ou un client HTTP dans n'importe quel langage. Chaque point de terminaison définit sa méthode HTTP, ses paramètres et son format de réponse.

Il existe une troisième voie entre les deux. Si vous voulez les paquets sans étape de compilation, unmap.dev sert le SDK complet en une seule balise de script ; voyez le Démarrage rapide.

Cette page contient tout ce que vous devez savoir pour le faire : (1) la forme du contrat, (2) le même géocodage et le même itinéraire en curl, fetch et Python, (3) l'affichage d'une carte avec un MapLibre GL JS standard et rien d'autre, et (4) ce que les paquets faisaient pour vous et qui devient votre tâche. Les paramètres et les corps de réponse de chaque point de terminaison ne sont pas répétés ici ; ils se trouvent sur l'API de cartes, Couches (y compris GET /identify et GET /data/query), l'API de géocodage, l'API d'itinéraires, l'API de transport en commun et l'API d'altitude, et ces pages décrivent déjà le contrat HTTP plutôt que le SDK. L'identification point-dans-polygone est GET /identify / unmap.identify(). La liste par bbox d'une couche interrogeable est GET /data/query / unmap.data.query().

Le contrat en un paragraphe

L'URL de base est https://api.unmap.dev. Les chemins propres à Unmap n'ont pas de préfixe de version; les chemins d'Optimize compatibles avec Google acceptent aussi /v1/projects/.... Les points de terminaison de lecture utilisent généralement GET avec des paramètres de requête. Le géocodage par lots, les matrices, l'appariement GPS, l'optimisation des arrêts et des parcs de véhicules, les signalements et les importations utilisent POST; supprimer une superposition utilise DELETE. /route et /isochrone acceptent aussi POST avec un corps JSON, notamment pour les polygones avoid_areas. La référence donne chaque méthode et forme de requête. La clé voyage comme Authorization: Bearer <clé>, X-API-Key: <clé>, X-Goog-Api-Key: <clé> ou ?key=<clé>, vérifiés dans cet ordre. Les URL de styles générées incluent la clé en paramètre pour les tuiles et ressources; une intégration MapLibre personnalisée peut définir des en-têtes via transformRequest (voir Authentification). Les réponses de géocodage, d'itinéraires et de styles sont en application/json ; les tuiles sont des octets de tuiles vectorielles, les glyphes et les sprites sont dans les formats binaires et image que MapLibre attend. La plupart des échecs renvoient du JSON avec un message error et un code. Les erreurs d'Optimize utilisent un objet error structuré au format de Google. Une requête mal formée de tuile, de relief, de courbes, de glyphe ou de sprite répond en texte brut. Une archive de relief ou de courbes non configurée est un JSON 404 not_found. Un style dont la publication active du fond de carte est absente est aussi du texte brut : 503 basemap release is misconfigured (voir Erreurs).

Le point de terminaison racine ne demande pas de clé, et il décrit les autres :

curl https://api.unmap.dev/
{
  "name": "unmap gateway",
  "endpoints": ["/tiles/{z}/{x}/{y}", "/styles/{style}.json", "/geocode/search", /* … */],
  "styles": ["base", "muted", "outdoor", "blueprint", "blush", "orchid", "canopy", "lagoon", "tropic", "sunset", "bold", "pastel", "atlas", "swiss", "winter"],
  "auth": "API key required via 'Authorization: Bearer um_...', 'X-API-Key', 'X-Goog-Api-Key', or '?key=', checked in that order",
  "docs": "https://unmap.dev/docs",
  "openapi": "https://api.unmap.dev/openapi.json",
  "apiCatalog": "https://api.unmap.dev/.well-known/api-catalog",
  /* plus authMd, mcp, a2a, agentCard et protectedResource, et l'attribution des données */
}

Description lisible par machine

Si vous branchez un outil, un générateur de code ou un agent plutôt que de lire, deux autres documents sans authentification décrivent le même contrat dans des formats faits pour cela :

  • https://api.unmap.dev/openapi.json est une description OpenAPI 3.1 des points de terminaison de données et des agents de la passerelle : les paramètres, les trois formes de clé comme schémas de sécurité, et les corps de réponse et d'erreur. Générez un client à partir de ce document, ou donnez-le à un agent.
  • https://unmap.dev/.well-known/api-catalog (aussi sur api.unmap.dev) est un catalogue d'API RFC 9727 : un linkset qui nomme l'API, pointe vers le document OpenAPI et renvoie vers cette documentation en français et en anglais. Les deux pages d'accueil et la racine de l'API l'annoncent par un en-tête Link, rel="api-catalog".
curl https://api.unmap.dev/openapi.json | jq '.paths | keys'
curl https://unmap.dev/.well-known/api-catalog

La réponse de la racine renvoie vers quelques autres documents sans authentification dans le même esprit : authMd (/auth.md, comment un agent obtient une identification), protectedResource (les métadonnées RFC 9728), agentCard et mcpServerCard.

Le document OpenAPI ne couvre que le plan de données par clé d'API. L'API de compte derrière le tableau de bord s'authentifie par une session de navigateur et n'y figure pas.

Les deux mêmes requêtes, de trois façons

Géocodez une requête, puis conduisez à partir de la réponse. Les trois onglets sont un seul programme : choisissez le langage dans lequel vous travaillez. fetch est tout ce que @unmap/geocoding et @unmap/routing utilisent en dessous, et les seules choses que les paquets ajoutent sont la construction de l'URL, une erreur levée sur un statut non-2xx et des types TypeScript pour la réponse ; l'onglet fetch est donc la bibliothèque cliente écrite à la main, et il s'exécute tel quel dans Node, Deno, Bun, les Workers ou un navigateur. Placez votre clé dans une variable d'environnement et chaque onglet s'exécute tel qu'écrit.

export UNMAP_API_KEY=um_live_...
 
# Géocodage direct. La réponse est un tableau JSON, donc passez-la à jq pour la lire.
curl "https://api.unmap.dev/geocode/search?q=Calgary%20Tower&limit=1" \
  -H "Authorization: Bearer $UNMAP_API_KEY" | jq '.[0] | {name, lng, lat}'
 
# Conduire entre deux points. Les coordonnées sont lng,lat et la virgule n'a pas besoin d'encodage.
curl "https://api.unmap.dev/route?from=-114.0719,51.0447&to=-113.9871,51.0899&mode=auto" \
  -H "Authorization: Bearer $UNMAP_API_KEY" | jq '{distanceMeters, durationSeconds}'

Le premier appel affiche le nom et les coordonnées du meilleur résultat ; le second affiche une distance routière en mètres et une durée en secondes. Tous les autres points de terminaison suivent le même schéma : un chemin, quelques paramètres de requête, un en-tête. Les pages API de géocodage et API d'itinéraires donnent une ligne curl et une ligne fetch pour chacun.

Deux détails de ces onglets méritent de passer dans votre propre code. D'abord, laissez la bibliothèque encoder la requête : URL et URLSearchParams dans l'onglet fetch, params= dans l'onglet Python. C'est ce qui fait qu'une requête comme rue Sainte-Catherine, ou une requête écrite en syllabaire, arrive intacte. Lire le corps en cas d'échec vaut aussi la ligne supplémentaire : le message nomme le paramètre fautif, et le code distingue un 429 de limite de débit d'un 429 de quota de forfait, et un 422 outside_coverage d'un 422 no_route.

Ensuite, fixez un délai d'attente, comme le fait l'onglet Python. Le géocodage et /route répondent en quelques centaines de millisecondes, mais une isochrone représente plusieurs passes de calcul dans le conteneur d'itinéraires et a été mesurée autour de 700 ms à chaud le 2026-09-02, donc un client sans aucun délai finira un jour par attendre dessus.

Afficher une carte avec un MapLibre standard

Une carte n'a pas non plus besoin de code @unmap. Le point de terminaison des styles renvoie un document de style MapLibre complet dont les URL de tuiles, de glyphes et de sprites pointent déjà vers la passerelle avec votre clé dans leurs paramètres, de sorte qu'un MapLibre GL JS ordinaire pointé vers cette seule URL découvre tout le reste lui-même. Voici la page entière, avec MapLibre chargé depuis un CDN et sans étape de compilation :

<link
  href="https://unpkg.com/maplibre-gl@6.13.0/dist/maplibre-gl.css"
  rel="stylesheet"
  integrity="sha384-yFNc3bs28S14jOJo1ZO9SnLiAmtyY2a3H9be8GkLMpDGlO5r1zZNP8fYu+fOCE/w"
  crossorigin="anonymous"
/>
 
<div id="map" style="height: 400px"></div>
 
<script type="module">
  import { Map } from "https://unpkg.com/maplibre-gl@6.13.0/dist/maplibre-gl.mjs";
 
  new Map({
    container: "map",
    style: "https://api.unmap.dev/styles/base.json?mode=light&key=um_live_...",
    center: [-114.0719, 51.0447],
    zoom: 11,
  });
</script>

MapLibre 6 est distribué uniquement en ESM. Il n'y a plus de version UMD ni de variable globale maplibregl : le script est donc un module, et les éléments voulus sont importés par leur nom. La feuille de style porte toujours une empreinte integrity; le module, lui, ne le peut pas, car une instruction import n'a aucun attribut pour la porter. C'est la deuxième raison pour laquelle le CDN est ici une démonstration et non une recommandation : dans une application, installez maplibre-gl et servez-le depuis votre propre site, comme le fait le Guide de démarrage.

La clé doit être dans l'URL du style sous la forme ?key=, parce que c'est la seule forme que les requêtes de tuiles, de glyphes et de sprites lancées par MapLibre peuvent porter, et la passerelle recopie la clé qui a récupéré le style dans les URL qu'elle écrit. Tout ce que font les options style, mode, lang et theme du SDK est un paramètre sur cette même URL, de sorte que /styles/outdoor.json?mode=dark&lang=fr est une carte outdoor sombre avec des étiquettes en français et que ?theme=<code> applique un thème venu de /create. La liste complète des styles et des paramètres est sur l'API de cartes.

La même URL fonctionne partout où un style MapLibre est accepté : MapLibre Native sur iOS et Android, le greffon MapLibre pour Leaflet, ou tout moteur de rendu qui lit un document de spécification de style version 8. Vous installez notre cartographie, pas notre code.

Appeler depuis un navigateur

L'API répond aux requêtes intersites depuis n'importe quelle origine : GET, HEAD, OPTIONS et POST (ce dernier n'atteint que /mcp, le point de terminaison JSON-RPC ; tout ce qui figure sur cette page est un GET), avec les en-têtes Authorization et X-API-Key permis. Les deux formes d'en-tête fonctionnent donc depuis un fetch de navigateur, mais ?key= est le meilleur choix à cet endroit. Un en-tête personnalisé transforme chaque requête en requête avec vérification préalable, un aller-retour OPTIONS de plus avant le GET, tandis qu'un paramètre de requête est une requête simple qui passe directement, et c'est le mécanisme que les requêtes de tuiles de la carte utilisent déjà.

Ce qu'un navigateur envoie et qu'un serveur n'envoie pas est un en-tête Origin, et la passerelle le lit. Une requête depuis une origine de développement est comptée mais jamais facturée : localhost, 127.0.0.1, [::1], tout hôte *.localhost, et toute prévisualisation *.pages.dev ou *.workers.dev, pourvu que la clé autorise cette origine. Une requête depuis toute autre origine est facturée normalement. Si la clé porte une liste d'origines autorisées, tout ce qui n'y figure pas reçoit un 403 avec le code origin_not_allowed, y compris une requête qui n'envoie aucun Origin. Un appel côté serveur ne porte aucun Origin et compte toujours comme du trafic de production, quelle que soit la clé utilisée : donnez donc à votre serveur une clé sans origine autorisée. Les règles exactes sont sur Forfaits et limites.

Ce que les paquets faisaient pour vous

S'en passer signifie reprendre quelques responsabilités que les clients assumaient. Aucune n'est difficile ; elles sont listées pour que rien ne soit une surprise :

  • Les paires de coordonnées sont en lng,lat, longitude d'abord. Un point est une paire séparée par une virgule : from et to sur /route, near sur /geocode/reverse, /isochrone et les autres points de terminaison qui prennent un ancrage. Les clients prennent des tuples [lng, lat] et écrivent les paramètres HTTP pour vous. /timezone utilise lat et lon séparément; /identify utilise at=lng,lat. Les corps JSON utilisent des tableaux, comme "near": [lng, lat] sur POST /isochrone.
  • Encodez la requête. q=Calgary Tower doit voyager sous la forme Calgary%20Tower. Toute bibliothèque HTTP le fait quand vous passez les paramètres comme un dictionnaire plutôt qu'en concaténant une chaîne.
  • Vérifiez le statut vous-même. Les clients lèvent une erreur sur toute réponse non-2xx. En HTTP, un 400 a toujours un corps JSON, alors lisez-le ; le message nomme le paramètre fautif.
  • Respectez Retry-After. Un 429 en porte un, sauf si son code est billing_required. Attendez ce nombre de secondes au lieu de réessayer immédiatement ; la limite de rafale est de 1 000 requêtes par 60 secondes par clé, par site Cloudflare. Un 502 n'en porte pas : le client réessaie ce statut selon son propre délai.
  • Laissez les en-têtes de cache travailler. Une réponse de géocodage est mise en cache à notre périphérie pendant 24 heures, un itinéraire ou une isochrone est en private, max-age=3600 (votre client peut la réutiliser, un cache partagé ne le doit pas), et une tuile qui a des octets est en public, max-age=86400. Un 204 vide n'envoie pas cet en-tête. Un navigateur respecte tout cela automatiquement. Un client côté serveur ne le fait que s'il a un cache HTTP, et une requête d'itinéraire répétée sans cache est un appel facturable répété.
  • Gardez une clé um_live_ hors de tout ce que vous distribuez à des inconnus, ou inscrivez les origines d'où elle peut servir pour qu'une clé copiée soit inutile ailleurs. Sur le serveur, une variable d'environnement suffit, et cette clé ne devrait porter aucune origine autorisée.

Prochaines étapes