Démarrage rapide

Lancez-vous en 3 étapes :

1. Obtenir une clé API

Inscrivez-vous sur portal.napspan.com pour obtenir une clé API gratuite (essai de 14 jours, 1 000 requêtes/jour).

2. Effectuer votre première requête

curl
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://api.napspan.com/api/v1/events?jurisdiction=FRA&limit=5"

3. Analyser la réponse

Réponse JSON
{
  "data": [
    {
      "id": "fr-evt-a86-001",
      "type": "construction",
      "sub_type": "roadwork",
      "severity": "minor",
      "title": "Travaux sur l'A86 Boulogne",
      "description": "Voie de droite fermée entre Sortie 14 et Sortie 15...",
      "latitude": 48.8407,
      "longitude": 2.2386,
      "jurisdiction": "FR",
      "start_time": "2026-03-23T07:00:00Z"
    }
  ],
  "total": 90,
  "limit": 5,
  "has_more": true
}

Spécification OpenAPI

La spécification API complète et lisible par machine — uniquement les endpoints de données (événements, fonctionnalités, carte, analytique, corridor poids lourds, prix des carburants, métadonnées). Utilisez-la pour générer des clients, l'importer dans Postman ou Insomnia, ou parcourir la référence interactive.

Authentification

Toutes les requêtes API nécessitent une clé API. Transmettez-la via l'en-tête X-API-Key (recommandé) ou le paramètre de requête api_key.

En-tête (recommandé)
curl -H "X-API-Key: sk_live_abc123" https://api.napspan.com/api/v1/events
Paramètre de requête
curl "https://api.napspan.com/api/v1/events?api_key=sk_live_abc123"

Erreurs & limites de débit

L'API retourne des codes de statut HTTP standard. Les en-têtes de limite de débit sont inclus dans chaque réponse.

StatutSignification
200Succès
400Requête incorrecte (paramètres manquants/invalides)
401Clé API manquante ou invalide
403Limite du plan dépassée (juridiction, restriction de fonctionnalité, essai expiré)
429Limite de débit dépassée — réessayez après Retry-After secondes
500Erreur serveur — veuillez réessayer ou contacter le support

Chaque réponse d’erreur contient un champ error lisible. Un 403 refusé par une limite de forfait contient en plus un code stable, afin que votre intégration puisse réagir sans analyser le texte du message — testez code, affichez error.

{
  "error": "add a jurisdiction filter to this request, e.g. ?jurisdiction=DE-BY (up to 1 per request, comma-separated). The Free plan scopes queries to specific jurisdictions; a higher plan can query all jurisdictions at once.",
  "code": "plan_jurisdiction",
  "plan": "free",
  "plan_name": "Free",
  "upgrade_url": "https://portal.napspan.com/billing",
  "docs_url": "/reference.html"
}

Codes : plan_jurisdiction, plan_batch_size, plan_event_time_range, plan_event_status, plan_archived_event, plan_inactive_features, plan_geojson, plan_analytics, plan_truck, trial_expired, subscription_expired. Ces champs sont absents des autres erreurs, traitez-les donc comme facultatifs.

Événements

Les événements de circulation incluent les incidents, travaux, fermetures, alertes météo, restrictions et événements spéciaux dans toutes les juridictions actives.

GET /api/v1/events

ParamètreTypeDescription
idsstringIdentifiants d'événements séparés par des virgules pour une requête groupée. Lorsque ids est fourni, tous les autres filtres sont ignorés et la pagination est désactivée — la réponse renvoie toujours l'ensemble complet sur une seule page, quel que soit le status. Limité par le max_batch_size du plan.
jurisdictionstringFiltrer par code ISO pays/région (ex. FR, DE, AT) obligatoire sur Free. Interroger un code primaire étend automatiquement la requête à tous les membres de son groupe, le cas échéant.
typestringFiltrer par type d'événement : incident, construction, closure, weather, special_event, advisory, restriction
severitystringFiltrer : minor, moderate, major, critical
lat, lng, radius_kmnumberRecherche par rayon (ex. lat=48.86&lng=2.35&radius_km=50)
bboxstringBoîte englobante : minLng,minLat,maxLng,maxLat
limitintRésultats par page (par défaut 100, max selon le plan)
offsetintDécalage de pagination
Requête groupée — récupérer plusieurs ID d'événements en un seul appel
curl -H "X-API-Key: $KEY" \
  "https://api.napspan.com/api/v1/events?ids=fr-evt-a86-001,de-evt-a9-002,at-evt-a4-015"
# Événements près de Paris, FR
curl -H "X-API-Key: $KEY" \
  "https://api.napspan.com/api/v1/events?jurisdiction=FRA&lat=48.86&lng=2.35&radius_km=100"
import requests

resp = requests.get("https://api.napspan.com/api/v1/events", params={
    "jurisdiction": "FR",
    "lat": 48.86, "lng": 2.35, "radius_km": 100
}, headers={"X-API-Key": KEY})
events = resp.json()["data"]
const res = await fetch(
  `https://api.napspan.com/api/v1/events?jurisdiction=FRA&lat=48.86&lng=2.35&radius_km=100`,
  { headers: { "X-API-Key": KEY } }
);
const { data, total } = await res.json();
req, _ := http.NewRequest("GET",
    "https://api.napspan.com/api/v1/events?jurisdiction=FRA&lat=48.86&lng=2.35&radius_km=100", nil)
req.Header.Set("X-API-Key", key)
resp, _ := http.DefaultClient.Do(req)
{
  "data": [
    {
      "id": "fr-evt-a86-001",
      "source_id": "EVT-2026-04521",
      "source": "fr",
      "jurisdiction": "FR",
      "type": "incident",
      "severity": "major",
      "status": "active",
      "title": "Multi-vehicle collision on A86 westbound near Boulogne",
      "description": "Two right lanes blocked. Emergency services on scene.",
      "affected_roads": ["A86"],
      "direction": "westbound",
      "lanes_affected": "2 of 4 lanes blocked",
      "start_time": "2026-03-29T14:30:00Z",
      "end_time": null,
      "estimated_end_time": "2026-03-29T17:00:00Z",
      "latitude": 48.8407,
      "longitude": 2.2386,
      "road_class": "motorway",
      "last_updated": "2026-03-29T14:45:00Z",
      "created_at": "2026-03-29T14:30:00Z"
    }
  ],
  "total": 42,
  "limit": 100,
  "offset": 0,
  "has_more": false
}

GET /api/v1/events/{id}

Événement unique par ID. Retourne l'événement complet avec tous les champs de métadonnées renseignés.

Réponse
{
  "id": "fr-evt-a86-001",
  "source_id": "EVT-2026-04521",
  "source": "fr",
  "jurisdiction": "FR",
  "type": "incident",
  "severity": "major",
  "status": "active",
  "title": "Multi-vehicle collision on A86 westbound near Boulogne",
  "description": "Two right lanes blocked. Emergency services on scene.",
  "location": { "type": "Point", "coordinates": [2.2386, 48.8407] },
  "affected_roads": ["A86"],
  "direction": "westbound",
  "lanes_affected": "2 of 4 lanes blocked",
  "start_time": "2026-03-29T14:30:00Z",
  "end_time": null,
  "estimated_start_time": null,
  "estimated_end_time": "2026-03-29T17:00:00Z",
  "source_created_at": "2026-03-29T14:28:55Z",
  "source_updated_at": "2026-03-29T14:45:00Z",
  "latitude": 48.8407,
  "longitude": 2.2386,
  "road_class": "motorway",
  "metadata": { "vehicles_involved": 3 },
  "last_updated": "2026-03-29T14:45:00Z",
  "created_at": "2026-03-29T14:30:00Z",
  "archived_at": null,
  "archive_reason": null
}

archive_reason est null tant que l'événement est actif. Lorsqu'un événement est archivé, il porte l'une de ces deux valeurs :

  • observed — le flux amont a renvoyé une réponse correcte et l'événement n'y figurait plus, nous l'avons donc archivé normalement. C'est le cas habituel.
  • stale_sweep — la voie d'archivage par sondage n'a pas pu retirer l'événement (réponses amont vides ou en erreur) et un balayage de sécurité l'a forcé en archivé après environ poll_interval × sweep_factor (facteur 15 par défaut) sans nouvelle observation. Traitez archived_at sur ces lignes comme un horodatage « présumé terminé avant », pas comme une fin précise. Un ratio stale_sweep durablement élevé sur une source indique que le flux amont émet rarement des enregistrements de clôture.

GET /api/v1/events/geojson Starter+

Mêmes paramètres que /events, retourne une FeatureCollection GeoJSON. Utilisable directement avec Leaflet, Mapbox ou tout outil compatible GeoJSON. Content-Type : application/geo+json.

Réponse
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [2.2386, 48.8407] },
      "properties": {
        "id": "fr-evt-a86-001",
        "source": "fr",
        "jurisdiction": "FR",
        "type": "incident",
        "severity": "major",
        "status": "active",
        "title": "Multi-vehicle collision on A86 westbound near Boulogne",
        "affected_roads": ["A86"],
        "direction": "westbound",
        "start_time": "2026-03-29T14:30:00Z"
      }
    }
  ]
}

Fonctionnalités

Les fonctionnalités sont des données hors événement : caméras, stations météo, aires de repos, panneaux, stationnement poids lourds, recharge EV, et plus encore. Tous les types partagent le même point de terminaison — spécifiez un type unique, ou utilisez group pour interroger tous les types d'une catégorie en une seule requête (par ex. group=trucking retourne neuf types liés aux poids lourds).

GET /api/v1/features

ParamètreTypeDescription
typestringType de fonctionnalité (voir Types de fonctionnalités). type ou group est obligatoire.
groupstringIdentifiant de groupe (voir Groupes de fonctionnalités). Expansion pratique vers tous les types du groupe. Combiné à radius_km, le rayon est plafonné à 200 km — une recherche plus large sur tous les types d’un groupe ne peut pas aboutir à temps et renvoie 400 au lieu d’expirer. Pour un rayon sans limite, interrogez un seul type.
jurisdictionstringFiltrer par code de juridiction. Interroger un code primaire étend automatiquement la requête à tous les membres de son groupe, le cas échéant.
activebooltrue pour ne retourner que les fonctionnalités actives
lat, lng, radius_kmnumberRecherche par rayon
bboxstringBoîte englobante : minLng,minLat,maxLng,maxLat
starts_after, starts_beforestringFiltre de fenêtre planifiée sur le début prévu (retombe sur le début réel). RFC3339 ou AAAA-MM-JJ.
ends_after, ends_beforestringFiltre de fenêtre planifiée sur la fin prévue. Les entrées à durée indéterminée (début connu, pas de fin) satisfont ends_after mais jamais ends_before.
limit, offsetintPagination

Les filtres de fenêtre planifiée s’appliquent aux types de features bornés dans le temps — future_construction, alerts, special_events, truck_restrictions et similaires. En bornant les deux extrémités, la requête sélectionne tout ce qui chevauche la période : ?starts_before=2026-09-01&ends_after=2026-08-01 renvoie chaque entrée prévue active à un moment quelconque d’août 2026. Les features sans aucune date sont exclues des requêtes de fenêtre.

Note sur la couverture : aucune source NAPSPAN ne publie encore de dates de début et de fin prévues. Ces filtres renvoient donc actuellement un ensemble vide pour chaque type de feature de l’UE. Ces paramètres font partie du contrat d’API commun et renverront automatiquement des résultats dès qu’une source publiera des calendriers — d’ici là, ne comptez pas sur eux pour des données européennes.

Chaque ligne porte un booléen has_details. Si la valeur est true, la source publie davantage de données que la ligne de liste — appelez GET /features/{id}/details (ou groupez via POST /features/details/batch ci-dessous) pour les obtenir. Si false, la ligne de liste contient déjà tout ce que la source expose pour ce couple (source, feature_type).

Exemple : caméras près de Paris
curl -H "X-API-Key: $KEY" \
  "https://api.napspan.com/api/v1/features?type=cameras&jurisdiction=FRA&lat=48.86&lng=2.35&radius_km=50"
Exemple : toutes les couches poids lourds en France (une requête)
curl -H "X-API-Key: $KEY" \
  "https://api.napspan.com/api/v1/features?group=trucking&jurisdiction=FRA"

La forme de properties varie selon le feature_type. Les exemples ci-dessous montrent les champs typiques pour les types les plus courants — choisissez un onglet.

{
  "data": [
    {
      "id": "fr-cam-a86-paris-01",
      "source": "fr",
      "jurisdiction": "FR",
      "feature_type": "cameras",
      "name": "A86 Boulogne",
      "latitude": 48.8407,
      "longitude": 2.2386,
      "road_name": "A86",
      "direction": "westbound",
      "is_active": true,
      "properties": {
        "url": "https://sytadin.fr/cameras/a86_boulogne.jpg",
        "video_url": null
      },
      "last_updated": "2026-03-29T14:50:00Z",
      "has_details": true
    }
  ],
  "total": 8643, "limit": 100, "offset": 0, "has_more": true
}
{
  "data": [
    {
      "id": "at-wx-a4-vie",
      "jurisdiction": "AT",
      "feature_type": "weather_stations",
      "name": "A4 Vienna Weather Station",
      "latitude": 48.2082, "longitude": 16.3738,
      "road_name": "A4",
      "is_active": true,
      "properties": {
        "temperature": 12.4,
        "wind_speed": 18.2,
        "wind_direction": "NW",
        "precipitation": "light_rain",
        "road_surface": "wet",
        "humidity": 78,
        "visibility": 12.0
      },
      "last_updated": "2026-03-29T14:45:00Z",
      "has_details": false
    }
  ],
  "total": 2150, "limit": 100, "offset": 0, "has_more": true
}
{
  "data": [
    {
      "id": "fr-dms-a4-paris-512",
      "jurisdiction": "FR",
      "feature_type": "signs",
      "name": "A4 EB DMS at PR 12",
      "latitude": 48.8566, "longitude": 2.4500,
      "road_name": "A4",
      "direction": "eastbound",
      "is_active": true,
      "properties": {
        "message": "ACCIDENT 5 KM / 2 VOIES FERMÉES / RALENTISSEMENTS",
        "posted_at": "2026-03-29T14:35:00Z",
        "sign_type": "DMS"
      },
      "last_updated": "2026-03-29T14:50:00Z",
      "has_details": true
    }
  ],
  "total": 3120, "limit": 100, "offset": 0, "has_more": true
}
{
  "data": [
    {
      "id": "nl-ev-amsterdam-a2-12",
      "source": "ndw",
      "jurisdiction": "NL",
      "feature_type": "ev_charging",
      "name": "Fastned Amsterdam Zuid",
      "latitude": 52.3399, "longitude": 4.8732,
      "is_active": true,
      "properties": {
        "network": "Fastned",
        "connector_types": ["CCS2", "CHAdeMO", "Type2"],
        "max_kw": 300,
        "port_count": 8,
        "access": "public",
        "pricing": "€0.69/kWh"
      },
      "last_updated": "2026-03-15T00:00:00Z",
      "has_details": true
    }
  ],
  "total": 42100, "limit": 100, "offset": 0, "has_more": true
}
{
  "data": [
    {
      "id": "de-bridge-a8-iller",
      "source": "bast",
      "feature_type": "bridge_clearances",
      "name": "A8 Iller Viaduct",
      "latitude": 48.21, "longitude": 10.05,
      "is_active": true,
      "properties": {
        "min_vertical_clearance_m": 4.50,
        "posting_status": "open",
        "weight_limit_tons": null,
        "year_built": 1972,
        "structure_kind": "prestressed concrete",
        "bridge_number": "BAST-7811-A8"
      },
      "last_updated": "2026-01-15T00:00:00Z",
      "has_details": false
    }
  ],
  "total": 39800, "limit": 100, "offset": 0, "has_more": true
}
{
  "data": [
    {
      "id": "de-tp-a7-soltau",
      "jurisdiction": "DE",
      "feature_type": "truck_parking",
      "name": "A7 Truck Parking Soltau-Ost",
      "latitude": 52.99, "longitude": 9.83,
      "is_active": true,
      "properties": {
        "capacity": 62,
        "available": 12,
        "availability_pct": 19,
        "amenities": ["restrooms", "vending", "lighting"],
        "observed_at": "2026-03-29T14:30:00Z"
      },
      "last_updated": "2026-03-29T14:50:00Z",
      "has_details": false
    }
  ],
  "total": 580, "limit": 100, "offset": 0, "has_more": true
}

GET /api/v1/features/types

Retourne chaque feature_type actif avec les compteurs total et actif. Mis en cache 2 minutes. Utile pour limiter une liste déroulante UI aux types réellement disponibles.

Réponse
[
  { "type": "cameras",           "count": 8120,  "active_count": 7842 },
  { "type": "weather_stations",  "count": 2150,  "active_count": 2098 },
  { "type": "signs",             "count": 3120,  "active_count": 2987 },
  { "type": "ev_charging",       "count": 42100, "active_count": 42100 },
  { "type": "bridge_clearances", "count": 39800, "active_count": 39800 }
]

GET /api/v1/features/groups

Retourne la taxonomie de 16 groupes de fonctionnalités avec leurs types membres. Utilisez le champ id comme paramètre group sur /features. Mis en cache 1 heure. Voir Groupes de fonctionnalités ci-dessous pour la table complète.

Réponse (tronquée à 2 sur 16 groupes)
[
  {
    "id": "imagery",
    "name": "Imagery",
    "description": "Live traffic camera feeds",
    "sort_order": 1,
    "feature_types": ["cameras"]
  },
  {
    "id": "trucking",
    "name": "Trucking & Commercial Vehicles",
    "description": "Truck restrictions, routes, parking, inspections",
    "sort_order": 8,
    "feature_types": [
      "truck_restrictions", "weight_restrictions", "bridge_clearances",
      "truck_routes", "freight_corridors", "truck_parking",
      "truck_rest_areas", "weigh_stations", "inspection_stations"
    ]
  }
]

GET /api/v1/features/{id}/details

Détail chargé à la demande pour une fonctionnalité unique. Certaines sources n'exposent que des champs compacts dans la liste ; ce point de terminaison renvoie l'objet properties complet ainsi qu'un drapeau detail_available et un indicateur cache (hit / miss / none / poll / error). Utilisez le champ has_details de la réponse de liste pour décider si l'appel en vaut la peine.

Réponse
{
  "data": {
    "id": "fr-cam-a86-paris-01",
    "feature_type": "cameras",
    "name": "A86 Boulogne",
    "latitude": 48.8407, "longitude": 2.2386,
    "properties": {
      "url": "https://sytadin.fr/cameras/a86_boulogne.jpg",
      "video_url": "https://sytadin.fr/cameras/a86_boulogne.m3u8",
      "views": [
        { "name": "Westbound", "url": "https://sytadin.fr/cameras/a86_boulogne_wb.jpg" },
        { "name": "Eastbound", "url": "https://sytadin.fr/cameras/a86_boulogne_eb.jpg" }
      ]
    }
  },
  "detail_available": true,
  "cache": "miss"
}

POST /api/v1/features/details/batch

Récupérer les détails de plusieurs fonctionnalités en un seul appel. La mise en cache par ID est identique à celle du point de terminaison unique (basée sur Redis, indexée par ID) — un groupage qui chevauche des appels précédents ne coûte rien pour la portion qui se chevauche. Les succès partiels sont préservés : si une récupération en amont échoue, l'entrée concernée porte cache: "error" sans faire échouer toute la requête ; les ID manquants apparaissent avec not_found: true. La taille du lot est limitée par le max_batch_size du plan.

Requête
curl -X POST -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"ids": ["fr-cam-a86-paris-01", "fr-cam-a4-paris-04", "missing-id"]}' \
  "https://api.napspan.com/api/v1/features/details/batch"
Réponse (tableau parallèle, une entrée par ID demandé, dans le même ordre)
{
  "count": 3,
  "data": [
    {
      "id": "fr-cam-a86-paris-01",
      "data": { "id": "fr-cam-a86-paris-01", "name": "A86 Boulogne", "properties": { "url": "…", "views": ["…"] } },
      "detail_available": true,
      "cache": "hit"
    },
    {
      "id": "fr-cam-a4-paris-04",
      "data": { "id": "fr-cam-a4-paris-04", "name": "A4 Porte de Bercy" },
      "detail_available": true,
      "cache": "miss"
    },
    {
      "id": "missing-id",
      "detail_available": false,
      "cache": "",
      "not_found": true
    }
  ]
}

Corridor poids lourds Pro+

Trouvez toutes les restrictions poids lourds le long d'un itinéraire. Trace un corridor avec marge entre deux points et retourne tous les gabarits de pont, restrictions de poids, routes camions et restrictions qui le croisent. Utilise des requêtes spatiales PostGIS pour un calcul précis sur grand cercle.

GET /api/v1/truck/corridor

ParamètreTypeDescription
from_lat obligatoirenumberLatitude d'origine
from_lng obligatoirenumberLongitude d'origine
to_lat obligatoirenumberLatitude de destination
to_lng obligatoirenumberLongitude de destination
buffer_kmnumberDistance de marge autour du corridor (par défaut 5, max 50 km)
heightnumberHauteur du véhicule en mètres — filtre les gabarits inférieurs
weightnumberPoids du véhicule en tonnes — filtre les limites de poids inférieures
jurisdictionstringRestreindre à une seule juridiction
limitintRésultats maximum (par défaut 500, max 2000)
Recherche dans : bridge_clearances, bridges, weight_restrictions, truck_restrictions, truck_routes, freight_corridors, truck_parking
Exemple : A8 Munich à Salzbourg
curl -H "X-API-Key: $KEY" \
  "https://api.napspan.com/api/v1/truck/corridor?\
from_lat=48.14&from_lng=11.58&\
to_lat=47.81&to_lng=13.05&\
buffer_km=10"
Réponse
{
  "corridor": {
    "from": [48.14, 11.58],
    "to": [47.81, 13.05],
    "buffer_km": 10,
    "distance_km": 142.5
  },
  "data": [
    {
      "id": "de-bridge-a8-iller",
      "feature_type": "bridge_clearances",
      "name": "A8 Iller Viaduct",
      "latitude": 48.21,
      "longitude": 10.05,
      "properties": {
        "posting_status": "open",
        "year_built": 1972,
        "_distance_km": "2.31"
      }
    },
    {
      "id": "at-trk-a1-salzburg",
      "feature_type": "truck_restrictions",
      "name": "Salzburg West",
      "properties": {
        "restriction": "Section ban for trucks > 7.5 t on weekends",
        "_distance_km": "0.45"
      }
    }
  ],
  "total": 98,
  "limit": 500
}

GET /api/v1/truck/corridor/geojson Pro+ GeoJSON

Même requête, retourne une FeatureCollection GeoJSON. Utilisez-la pour afficher les résultats du corridor directement sur une carte Leaflet ou Mapbox.

// Afficher le corridor poids lourds sur une carte Leaflet
const url = `https://api.napspan.com/api/v1/truck/corridor/geojson`
  + `?from_lat=48.14&from_lng=11.58&to_lat=47.81&to_lng=13.05&buffer_km=10`;

fetch(url, { headers: { "X-API-Key": KEY } })
  .then(r => r.json())
  .then(geojson => {
    L.geoJSON(geojson, {
      pointToLayer: (f, ll) => L.circleMarker(ll, { radius: 6 }),
      onEachFeature: (f, layer) => {
        layer.bindPopup(`<b>${f.properties.name}</b><br>${f.properties.feature_type}`);
      }
    }).addTo(map);
  });
import requests

resp = requests.get("https://api.napspan.com/api/v1/truck/corridor", params={
    "from_lat": 48.14, "from_lng": 11.58,
    "to_lat": 47.81,  "to_lng": 13.05,
    "buffer_km": 10
}, headers={"X-API-Key": KEY})

for feat in resp.json()["data"]:
    if feat["feature_type"] == "bridge_clearances":
        print(f"Pont : {feat['name']} ({feat['properties'].get('posting_status', 'unknown')})")
Réponse (FeatureCollection)
{
  "type": "FeatureCollection",
  "corridor": {
    "from": [48.14, 11.58],
    "to": [47.81, 13.05],
    "buffer_km": 10,
    "distance_km": 142.5
  },
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [10.05, 48.21] },
      "properties": {
        "id": "de-bridge-a8-iller",
        "feature_type": "bridge_clearances",
        "name": "A8 Iller Viaduct",
        "min_vertical_clearance_m": 4.50,
        "posting_status": "open",
        "_distance_km": "2.31"
      }
    }
  ]
}

Analytique Pro+

Analytique historique et tendances pour les événements, les fonctionnalités et la santé des sources. Tous les points de terminaison nécessitent un plan Pro ou Enterprise.

GET /api/v1/analytics/history/{id}

Chronologie du cycle de vie d'un événement unique — création, changements de gravité, changements de voies, changements d'heure de fin, archivage.

Réponse
[
  { "id": 1, "event_id": "fr-evt-a86-001",
    "change_type": "created",
    "old_value": null, "new_value": "active",
    "changed_at": "2026-03-29T14:30:00Z" },
  { "id": 2, "event_id": "fr-evt-a86-001",
    "change_type": "severity_change",
    "old_value": "moderate", "new_value": "major",
    "changed_at": "2026-03-29T14:35:00Z" }
]

GET /api/v1/analytics/changes

Flux des changements récents pour tous les événements. Paginé. Utile pour synchroniser une copie en aval de l'état des événements sans interroger chaque événement individuellement.

Réponse
{
  "data": [
    { "id": 45, "event_id": "fr-evt-a86-001",
      "change_type": "severity_change",
      "old_value": "moderate", "new_value": "major",
      "jurisdiction": "FR",
      "event_title": "Multi-vehicle collision on A86 westbound",
      "changed_at": "2026-03-29T14:35:00Z" }
  ],
  "total": 128, "limit": 100, "offset": 0, "has_more": true
}

GET /api/v1/analytics/clearance

Temps de résolution P50 / P95 / moyens par juridiction et type d'événement. Calculés à partir de start_timearchived_at.

Réponse
[
  { "jurisdiction": "FR", "event_type": "incident",
    "total_events": 320,
    "p50_minutes": 42.5, "p95_minutes": 175.0, "avg_minutes": 59.4 },
  { "jurisdiction": "AT", "event_type": "construction",
    "total_events": 150,
    "p50_minutes": 4320.0, "p95_minutes": 21600.0, "avg_minutes": 7200.0 }
]

GET /api/v1/analytics/corridors

Fréquence d'événements et temps moyen de résolution par route. Meilleur signal pour identifier « quel corridor est peu fiable aujourd'hui ».

Réponse
[
  { "road": "A86", "jurisdiction": "FR",
    "total_events": 245,
    "avg_clearance_minutes": 52.3,
    "incident_count": 180, "construction_count": 65 }
]

GET /api/v1/analytics/trends

Totaux journaliers d'événements avec ventilation par type.

Réponse
[
  { "period": "2026-03-29", "total": 142,
    "by_type": { "incident": 58, "construction": 62, "closure": 12, "weather": 10 } },
  { "period": "2026-03-28", "total": 128,
    "by_type": { "incident": 45, "construction": 60, "closure": 15, "weather": 8 } }
]

GET /api/v1/analytics/hotspots

Clusters géographiques d'événements avec le type et la route dominants par cluster.

Réponse
[
  { "cluster_id": 1,
    "latitude": 48.8407, "longitude": 2.2386,
    "event_count": 28, "radius_km": 2.5,
    "top_type": "incident", "top_road": "A86" }
]

GET /api/v1/analytics/weather

Historique des relevés des stations météo — la base de données utilisée pour la corrélation météo-événement.

Réponse
[
  { "station_id": "at-wx-a4-vie",
    "name": "A4 Vienna Weather Station",
    "latitude": 48.2082, "longitude": 16.3738,
    "temperature": 12.4, "wind_speed": 18.2, "wind_direction": "NW",
    "precipitation": "light_rain", "road_surface": "wet",
    "humidity": 78, "visibility": 12.0,
    "recorded_at": "2026-03-29T14:45:00Z" }
]

Autres points de terminaison analytique

Forme identique aux exemples ci-dessus — schémas complets dans la référence interactive.

Point de terminaisonDescription
/analytics/feature-historyChangements du cycle de vie des fonctionnalités (création, désactivation, réactivation).
/analytics/event-weather/{id}Snapshot météo enregistré au moment de la création de l'événement (recherche PostGIS de la station la plus proche).
/analytics/weather-correlationAgrégation de la corrélation entre événements et météo.

Métadonnées & statut

Points de terminaison légers de catalogue et de statut. Ils sont publics (aucune clé API requise) — seul /fuel-prices nécessite une clé API, sans restriction de plan.

GET /api/v1/jurisdictions

Juridictions actives avec code, nom, pays et scope. Par défaut, seules les juridictions géographiques réelles sont renvoyées (scope=state). Utilisez ?scope=federal pour les sources nationales transversales, ?scope=regional pour les flux sous-nationaux, ou ?scope=all pour tout renvoyer.

Lorsque group_id n'est pas null, la juridiction appartient à un groupe (voir /api/v1/jurisdictions/groups ci-dessous). Une requête ?jurisdiction=<primary> sur /events ou /features est transparente : elle est étendue à tous les membres ; pour désactiver, passez un code non principal ou une liste séparée par des virgules. Le déploiement européen n'expose actuellement aucun groupe — toutes les lignes renvoient group_id: null — mais le champ est documenté afin que les clients puissent l'adopter dès que des flux frères apparaîtront.

Réponse
[
  { "code": "FR", "name": "France",  "country": "FR", "scope": "state", "group_id": null, "is_active": true },
  { "code": "DE", "name": "Germany", "country": "DE", "scope": "state", "group_id": null, "is_active": true }
]

GET /api/v1/jurisdictions/groups

Faisceaux canoniques pour les juridictions dont le flux est réparti sur plusieurs codes. Le primary_jurisdiction_code est celui à utiliser sur /events et /features : la requête est étendue de manière transparente à toutes les entrées members. Le déploiement européen renvoie actuellement un tableau vide ; le point de terminaison est livré pour que les clients puissent s'y appuyer dès qu'il faudra regrouper Mobilithek ou d'autres sources nationales.

Réponse
[]

GET /api/v1/stats/summary

Statistiques agrégées détaillées — utilisées par les pages marketing pour des compteurs en direct. Requête plus lourde que /stats ; mise en cache 60 s.

Réponse
{
  "jurisdictions": { "total": 28, "active": 26, "by_country": { "DE": 1, "AT": 1, "FR": 1 } },
  "events": {
    "active": 3120,
    "by_type": { "incident": 820, "construction": 1450, "closure": 280 },
    "by_severity": { "minor": 1080, "moderate": 1450, "major": 510, "critical": 80 }
  },
  "features": { "total": 96450, "by_type": { "cameras": 8120, "ev_charging": 42100 } },
  "last_sync": "2026-03-29T14:55:00Z",
  "uptime": "72h15m"
}

GET /api/v1/fuel-prices

Prix des carburants européens (lorsque des sources licenciées sont disponibles). Avec latest=true, uniquement la dernière observation par jurisdiction + fuel_type.

Réponse
{
  "data": [
    { "jurisdiction": "FR", "country": "FR", "fuel_type": "diesel",
      "price": 1.74, "currency": "EUR", "unit": "litre",
      "observed_at": "2026-05-05", "source": "DGEC" },
    { "jurisdiction": "DE", "country": "DE", "fuel_type": "diesel",
      "price": 1.69, "currency": "EUR", "unit": "litre",
      "observed_at": "2026-05-05", "source": "BAFA" }
  ],
  "total": 128, "limit": 100, "offset": 0, "has_more": true
}

GET /api/v1/status

Snapshot de statut public — adapté à une page de statut non authentifiée ou à un moniteur d'uptime externe. Compteurs agrégés et ventilation par juridiction avec disponibilité sur 7 jours. Mise en cache 60 s.

Réponse (tronquée)
{
  "overall": "operational",
  "generated_at": "2026-05-08T14:00:00Z",
  "worker": { "last_seen": "2026-05-08T13:59:50Z", "staleness_seconds": 10, "healthy": true },
  "total_resources": 186, "healthy": 175, "warning": 8, "critical": 3,
  "jurisdictions": [
    { "code": "FR", "name": "France", "country": "FR",
      "status": "operational", "total_resources": 12, "open_circuits": 0,
      "uptime_7day_percent": 99.8 }
  ]
}

Webhooks Pro+

Abonnez-vous aux changements d'événements en temps réel. Lorsqu'un événement de circulation est créé, change de gravité ou de statut, ou est archivé, l'API envoie un POST signé HMAC-SHA256 à votre point de terminaison. Les clients Pro et Enterprise configurent leurs abonnements dans le portail — portal.napspan.com/webhooks. Le secret généré automatiquement est affiché une seule fois à la création ; copiez-le immédiatement.

Chaque webhook est filtré par juridiction (obligatoire, sélection multiple — choisissez-en une ou plusieurs), et facultativement par type d'événement, sous-type et gravité (également en sélection multiple). Les filtres sont combinés en ET entre les dimensions ; au sein d'une dimension, le webhook se déclenche dès que l'événement correspond à l'une des valeurs sélectionnées.

Le filtre facultatif sub_type affine au sein d'un type — par exemple, type: ["incident"] + sub_type: ["accident"] ne livre que les accidents, et non les pannes ou les débris. Il est additif : omettez-le (ou envoyez un tableau vide) et vous recevez tous les sous-types, exactement comme auparavant. sub_type est aussi un champ présent sur chaque événement et un paramètre de requête ?sub_type= sur /events. Consultez le vocabulaire complet dans la référence de l'API.

Le filtre facultatif cause est similaire, mais fonctionne d'un type à l'autre. Comme sub_type est rattaché à un type (le sous-type d'une fermeture décrit la fermeture, pas sa cause), un accident qu'une source publie comme fermeture porte type: "closure", sub_type: "lane_closure" — et cause: "accident". Ainsi, cause: ["accident"] capture les événements dus à un accident quelle que soit la manière dont la source les a modélisés, ce que sub_type: ["accident"] seul manquerait. Comme sub_type, cause est un champ présent sur chaque événement, un paramètre de requête ?cause= sur /events et une dimension de filtre de webhook additive.

Types d'événements

ÉvénementDéclenché lorsque
event.createdUn nouvel événement de circulation arrive depuis une source nationale de données de mobilité.
event.severity_changeLa gravité d'un événement existant change (ex. moderatemajor).
event.status_changeLe statut bascule (ex. activearchived).
event.archivedL'événement est terminé.
testEnvoyé uniquement par le bouton « Tester » du portail — déclenché immédiatement, jamais enregistré dans l'historique des livraisons.

Charge utile immédiate (par défaut)

Un POST par changement. À utiliser si vous avez besoin de la latence la plus faible possible et que votre récepteur supporte les pics.

Corps du POST webhook
{
  "event": "event.severity_change",
  "timestamp": "2026-03-29T14:35:00Z",
  "data": {
    "event_id": "fr-evt-a86-001",
    "jurisdiction": "FR",
    "type": "incident",
    "sub_type": "accident",
    "cause": "accident",
    "severity": "major",
    "road_name": "A86",
    "changes": {
      "old_severity": "moderate",
      "new_severity": "major"
    }
  }
}

Charge utile groupée

Définissez batch_window_seconds (1–300) lors de la création du webhook pour collecter les changements pendant cette fenêtre et les livrer en un seul POST. Réduit le volume HTTP pour les destinataires bavards (Slack, Teams, Lambda) au prix d'une latence supplémentaire allant jusqu'à window_seconds.

Corps du POST groupé (batch_window_seconds=60)
{
  "batch": {
    "window_seconds": 60,
    "started_at": "2026-03-29T14:30:00Z",
    "ended_at": "2026-03-29T14:31:00Z",
    "event_count": 2
  },
  "events": [
    {
      "event": "event.created",
      "timestamp": "2026-03-29T14:30:15Z",
      "data": { "event_id": "fr-evt-a4-002", "jurisdiction": "FR", "type": "construction", "sub_type": "roadwork", "severity": "minor", "road_name": "A4" }
    },
    {
      "event": "event.severity_change",
      "timestamp": "2026-03-29T14:30:42Z",
      "data": { "event_id": "fr-evt-a86-001", "jurisdiction": "FR", "type": "incident", "sub_type": "accident", "severity": "major", "road_name": "A86", "changes": { "old_severity": "moderate", "new_severity": "major" } }
    }
  ]
}

Les récepteurs branchent selon la présence de la clé batch :

Pseudo-code récepteur
if ("batch" in body) {
  // groupé : itérer sur body.events
  for (const ev of body.events) handle(ev);
} else {
  // immédiat : traiter le body lui-même
  handle(body);
}

Un lot unique est plafonné à 100 événements ; les files d'attente plus longues sont réparties sur plusieurs POST dans la même fenêtre.

Vérification de la signature

Chaque livraison inclut un en-tête X-Webhook-Signature contenant le HMAC-SHA256 (hex, minuscule) du corps de la requête, signé avec votre secret webhook. Rejetez les requêtes dont la signature ne correspond pas.

Récepteur Node.js
import crypto from "crypto";

app.post("/napspan-webhook", (req, res) => {
  const sig = req.headers["x-webhook-signature"];
  const expected = crypto
    .createHmac("sha256", process.env.WEBHOOK_SECRET)
    .update(req.rawBody)            // octets bruts, PAS JSON.stringify(req.body)
    .digest("hex");

  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).end();
  }
  // traiter req.body…
  res.status(200).end();
});

Fiabilité

Les livraisons en échec sont relancées jusqu'à 3 fois avec un délai exponentiel (10s, 30s, 90s). Après 10 échecs consécutifs, l'abonnement est désactivé automatiquement — réactivez-le depuis le portail une fois votre point de terminaison rétabli. Utilisez le bouton Tester sur chaque ligne du portail pour déclencher immédiatement un événement test et confirmer l'accessibilité avant de dépendre d'un webhook en production.

Routage poids lourds Pro+

Un itinéraire adapté aux poids lourds, de l'origine à la destination — calculé par notre moteur de routage (y compris les restrictions par catégorie de tunnel ADR pour les chargements dangereux), puis enrichi de chaque danger à proximité connu de notre base de données : incidents RTTI/SRTI en direct, travaux programmés, gabarits de ponts filtrés selon la hauteur du camion demandé, restrictions poids lourds et de poids, météo le long du corridor et alertes actives — selon ce que chaque NAP publie comme données sous-jacentes.

POST /api/v1/routing/route

ChampTypeDescription
origin obligatoireobject{ "lat": ..., "lng": ... }
destination obligatoireobject{ "lat": ..., "lng": ... }
truck obligatoireobjectBloc véhicule — profile (tractor, straight, box), weight_t, height_m, optionnels length_m, width_m, axles, hazmat
truck.profile_idstringRéférence un profil de camion enregistré de votre bibliothèque de flotte (géré dans le portail sous Mes camions) au lieu de renvoyer le bloc complet. Les champs truck.* en ligne envoyés à ses côtés y sont fusionnés en profondeur (la valeur en ligne l'emporte champ par champ). Le bloc résolu est renvoyé sous resolved_truck. Voir Profils de camion réutilisables.
alternativesintNombre d'itinéraires alternatifs (0–3, par défaut 0)
avoidarrayOptionnel : tolls, ferries, tunnels
includearrayCanaux de détail optionnels. Ajoutez tolls pour que le moteur de routage chiffre les systèmes de péage de l'itinéraire pour votre camion — le coût est renvoyé dans summary.toll_costs[] (une entrée par devise) et sections[].tolls[] (par système). polyline et summary sont toujours inclus. Ajoutez toll_alternative (forfaits payants ; implique tolls) pour calculer également un second itinéraire sans péage et en chiffrer le compromis — voir Alternative tenant compte des péages ; il est facturé comme 2 appels de routage. Le calcul des péages ajoute un coût en amont, il est donc désactivé sauf demande explicite.
currencystringDevise ISO 4217 pour les tarifs de péage — prise en compte uniquement avec include: ["tolls"]. Omettez-la pour obtenir la devise native de chaque système de péage.
enrichmentobjectAjuste le filtrage des avertissements post-routage — aucun de ces champs n'est envoyé au moteur de routage. Sous-clés : exclude_types, min_severity, buffer_m (10–1000, défaut 100), clearance_pad_m (0–1, défaut 0.15), skip_temporal_filter, max_distance_m.
cargoobjectMétadonnées de cargaison stockées sur l'itinéraire sauvegardé. Sous-clé : hazmat_class (classe ADR, p. ex. "1.3D").
truck.permit_numberstringNuméro de permis de transport exceptionnel. Renvoyé dans la réponse.
customer_route_idstringClé de corrélation libre (≤128 caractères). Renvoyée à l'identique.
tagsarrayÉtiquettes libres pour l'analyse flotte/ligne (max. 16 entrées, ≤64 caractères chacune).
Chaque appel réussi est décompté de votre quota de routage mensuel — le solde de l'abonnement est consommé en priorité, puis les éventuels packs de recharge dans l'ordre FIFO. Les nouveaux appels sur un itinéraire enregistré (voir ci-dessous) ne consomment pas de quota.
Exemple : Berlin → Munich, tracteur 20 t, 4,0 m de haut
curl -X POST -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  https://api.napspan.com/api/v1/routing/route \
  -d '{
    "origin":      { "lat": 52.5200, "lng": 13.4050 },
    "destination": { "lat": 48.1351, "lng": 11.5820 },
    "truck": {
      "profile":  "tractor",
      "weight_t": 20,
      "height_m": 4.0
    },
    "include":  ["tolls"],
    "currency": "EUR"
  }'
Réponse
{
  "route_id":   "rt_01HXYZ4K8Q2V7R9N3M5P6T8W0E",
  "expires_at": "2026-05-18T14:32:00Z",
  "routes": [
    {
      "summary": {
        "distance_km":   585.4,
        "duration_min":  352,
        "toll_costs":   [ { "currency": "EUR", "value": 38.70 } ]
      },
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [13.4050, 52.5200],
          [12.3700, 51.3400],
          [11.5820, 48.1351]
        ]
      },
      "warnings": [
        {
          "type":           "bridge_clearance",
          "severity":       "critical",
          "feature_id":     "DE-bridge-A9-K1247",
          "name":           "Pont sur l'A9 près de Leipzig",
          "latitude":       51.3400,
          "longitude":      12.3700,
          "clearance_m":    4.0,
          "truck_height_m": 4.2,
          "message":        "Le gabarit vertical affiché est inférieur à la hauteur du camion demandée."
        }
      ]
    }
  ]
}

Alternative tenant compte des péages

Ajoutez toll_alternative à include (cela implique tolls) et la réponse gagne un bloc toll_alternative de premier niveau : un second itinéraire calculé en évitant les routes à péage, avec le compromis chiffré — combien de mètres et de secondes supplémentaires coûte le trajet sans péage, et l'argent de péage qu'il économise par devise. Cela permet à un répartiteur d'arbitrer « payer le péage ou le contourner » en une seule requête.

Facturation : puisque cela calcule un second itinéraire, c'est compté comme 2 appels de routage (le principal + l'alternative sans péage) — ou 1 lorsque toute la réponse est servie depuis le cache. La fonctionnalité est disponible uniquement sur les forfaits payants ; une requête en forfait Free renvoie l'itinéraire principal accompagné de toll_alternative_omitted: "plan_upgrade_required". Si l'alternative ne peut être produite pour toute autre raison, l'itinéraire principal est tout de même renvoyé, avec la raison dans toll_alternative_omitted (quota_exhausted, upstream_error ou no_alternative).

Réponse : le bloc toll_alternative (aux côtés de routes[])
  "toll_alternative": {
    "summary": {
      "distance_m":  372000,
      "duration_s":  13800,
      "toll_costs":  []
    },
    "geometry":        { "type": "LineString", "coordinates": [ /* … */ ] },
    "extra_distance_m": 22000,
    "extra_duration_s": 1200,
    "savings":         [ { "currency": "EUR", "value": 38.70 } ],
    "cached":          false
  }

Types d'alerte

Chaque entrée de warnings[] porte un type, une severity (info / warning / critical), la distance parcourue le long de l'itinéraire, une heure d'arrivée prévue et un bloc properties spécifique au type. Utilisez l'objet enrichment pour filtrer par gravité ou écarter les types qui ne vous intéressent pas. La disponibilité de chaque type dépend de ce que le NAP publie pour ce corridor.

TypeGravité typiqueSe déclenche quand
bridge_clearancecriticalGabarit affiché < hauteur du camion + clearance_pad_m, ou capacité de charge < poids du camion
truck_restrictioncriticalUne limite de hauteur / largeur / longueur / poids affichée sur l'itinéraire est inférieure à la valeur du camion (signalée par dimension)
weight_restrictioncriticalUne limite de poids affichée sur l'itinéraire est inférieure au poids du camion
traffic_eventcritical–infoUn incident, une fermeture ou des travaux RTTI/SRTI en direct croisent le corridor pendant la fenêtre de trajet
future_constructionwarningDes travaux programmés chevauchent l'heure de trajet prévue à ce point de l'itinéraire
special_eventinfoUne fermeture planifiée ou un événement spécial touche l'itinéraire
alertinfoUne alerte générale de juridiction s'applique le long du corridor
weatherinfoConditions / alertes météo signalées par des stations à proximité de l'itinéraire
border_crossingcritical–infoUn poste-frontière se trouve sur l'itinéraire. Lorsque la source publie un temps d'attente pour la voie poids lourds, la gravité en découle (info sous 15 min, warning à partir de 15, critical au-delà de 45 ou lorsque le poste est fermé)

Les restrictions par catégorie de tunnel ADR sont appliquées par le routeur lui-même (via la catégorie de tunnel et la classe de marchandises dangereuses du camion), de sorte que les tunnels interdits sont évités dans la géométrie de l'itinéraire plutôt que signalés comme une alerte. Activez le canal distinct features[] avec enrichment.include_features pour obtenir également les commodités à proximité le long de l'itinéraire — truck_parking, truck_rest_areas, rest_areas adaptées aux poids lourds, service_plazas et ev_charging. Le nombre de types de commodités demandables à la fois dépend du forfait (Free : aucun ; le plafond augmente selon le palier ; Enterprise : illimité) — votre plafond est publié sous routing_max_feature_types via GET /api/v1/customer/plans. Le dépassement renvoie 403 feature_types_limit.

Planification des temps de conduite

Ajoutez un bloc truck.hos — le compteur de temps de conduite et de repos du conducteur au départ — et la réponse gagne un canal hos[] : les points où le conducteur doit faire une pause ou cesser de conduire selon le régime choisi, chacun accompagné des parkings poids lourds et aires de repos encore atteignables avant cette limite. Il couvre l'UE (règlement 561/2006), les États-Unis (FMCSA) et le Canada (au sud et au nord du 60e parallèle — canada_south / canada_north), et il est gratuit sur tous les forfaits. Omettez ruleset pour utiliser par défaut la région de votre déploiement (eu ici).

Chaque champ *_remaining_s correspond aux secondes restantes par rapport à cette limite — omettez-en un pour supposer un conducteur reposé. Un profil de camion réutilisable ne devrait stocker que ruleset ; envoyez les compteurs propres au trajet en ligne.

Requête : ajouter le compteur HOS du conducteur au bloc truck
    "truck": {
      "profile":  "tractor",
      "weight_t": 20,
      "height_m": 4.0,
      "hos": {
        "ruleset":           "eu",
        "drive_remaining_s": 32400,
        "since_break_s":     9000
      }
    }
Réponse : le canal hos[] (aux côtés de warnings[] / features[])
      "hos": [
        {
          "reason":                 "break_required",
          "distance_along_route_m": 112000,
          "projected_time":         "2026-05-18T13:30:00Z",
          "legal_deadline":         "2026-05-18T13:30:00Z",
          "feasible":               true,
          "suggested_stops": [
            { "type": "truck_parking", "name": "Autohof Montabaur A3", "distance_along_route_m": 106000, "available_spots": 22, "capacity": 45, "as_of": "2026-05-18T13:25:00Z" }
          ]
        }
      ],
      "hos_summary": {
        "adjusted_arrival_time": "2026-05-19T02:10:00Z",
        "delay_s":               39600,
        "meets_arrival_window":  false
      }

reason vaut break_required, drive_limit, duty_window ou cycle_limit. Les suggested_stops sont triés d'abord par places libres, puis par proximité de l'échéance, afin que le conducteur exploite le plus de temps de conduite légal avant de s'arrêter ; lorsqu'un flux de stationnement publie l'occupation, chaque arrêt porte available_spots / capacity, et feasible: false signifie que tout stationnement atteignable est plein (ou qu'aucun n'est atteignable) avant cette limite. hos_summary récapitule la projection par rapport à votre heure d'arrivée — adjusted_arrival_time est l'arrivée une fois les repos obligatoires insérés, delay_s le temps qu'ils ajoutent, et meets_arrival_window (présent seulement si vous envoyez arrival_time) indique si le conducteur respecte encore légalement cette fenêtre. Un ruleset inconnu renvoie 400 invalid_hos_ruleset.

Itinéraires enregistrés

Chaque appel est enregistré automatiquement pendant 30 minutes sous son route_id. Récupérez-le à tout moment dans cette fenêtre via GET /api/v1/routing/route/saved/{id} pour obtenir des avertissements réévalués sur l'état temps réel — ces relectures ne consomment pas de quota de routage. Pour conserver un itinéraire au-delà des 30 minutes, appelez POST /api/v1/routing/route/saved/{id}/persist ; les itinéraires persistés sont décomptés de la limite de slots de votre plan.

Récupérez des points d'intérêt le long d'un itinéraire enregistré à la demande via GET /api/v1/routing/route/saved/{id}/features?types=cameras,fuel_stations,truck_parking. C'est le complément à la demande de include_features : l'appel ne consomme aucun quota de routage et renvoie les types de POI demandés — triés par distance le long de l'itinéraire — y compris les caméras de trafic et les stations-service, disponibles uniquement ici et non dans le canal intégré features[] (deux couches nationales denses qui ralentiraient l'appel de routage synchrone). Lorsqu'un flux national publie des prix par station, ceux-ci sont transmis dans les properties du point. Chaque point est étiqueté avec distance_along_route_m, sa distance perpendiculaire detour_m hors itinéraire et le side (left/right) du sens de circulation. Le nombre de types distincts est soumis à la même limite routing_max_feature_types, et les résultats sont mis en cache par itinéraire et soumis à une limite de débit comme une relecture.

Profils de camion réutilisables

Si vous calculez des itinéraires pour la même poignée de véhicules encore et encore, enregistrez chaque camion une fois au lieu de renvoyer son bloc complet à chaque appel. Créez et gérez des profils nommés dans votre portail sous Mes camions, puis référencez-en un par son ID avec truck.profile_id :

Référencer un profil enregistré, remplacer un champ
curl -X POST -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  https://api.napspan.com/api/v1/routing/route \
  -d '{
    "origin":      { "lat": 48.2082, "lng": 16.3738 },
    "destination": { "lat": 48.3069, "lng": 14.2858 },
    "truck": {
      "profile_id": "9f1c2e7a-6b3d-4a21-9f0e-2c5d8b7a1e34",
      "weight_t":   38
    }
  }'

Le serveur charge le profil stocké et fusionne en profondeur tout champ truck.* en ligne que vous envoyez à ses côtés — les valeurs en ligne l'emportent champ par champ, vous pouvez donc conserver un profil de base et remplacer, par exemple, weight_t pour un trajet chargé donné. Le bloc camion entièrement résolu est renvoyé sous resolved_truck afin que vous puissiez confirmer exactement ce que le moteur de routage a vu :

Réponse (extrait)
{
  "route_id": "rt_01HXYZ4K8Q2V7R9N3M5P6T8W0E",
  "resolved_truck": {
    "profile_id": "9f1c2e7a-6b3d-4a21-9f0e-2c5d8b7a1e34",
    "profile":    "tractor",
    "weight_t":   38,
    "height_m":   4.0,
    "axle_count": 5
  },
  "routes": [ /* … */ ]
}

Un ID inconnu renvoie 400 profile_not_found. Un profil enregistré ne peut pas lui-même contenir un profile_id.

Évitement avancé & détail d'itinéraire

Au-delà d'avoid, la requête accepte des contrôles d'itinéraire plus fins : avoid_areas (bloquer des zones interdites en bbox / cercle / polygone), avoid_zones (environmental, congestion_pricing), avoid_truck_roads, avoid_countries et le plus strict exclude_countries (codes ISO-3), ainsi que details[] pour les attributs routiers par segment (limitations de vitesse, classe fonctionnelle, voies …). Chaque itinéraire porte aussi les notices[] du moteur de routage lui-même — des indicateurs tels que violatedVehicleRestriction lorsqu'aucun trajet entièrement conforme n'existe. Voir la référence pour la liste complète des champs.

Schéma complet de requête/réponse (tous les champs du profil camion, tous les types d'avertissement, enveloppes d'erreur) : voir la référence interactive sur /reference.html.

Groupes de fonctionnalités

60+ types de fonctionnalités organisés en 16 groupes. Passez l'id comme paramètre group sur /features pour interroger tous les membres en une seule requête.

ID du groupeNomMembres
imageryImageriecameras
weatherMétéo et environnementweather_stations, regional_weather, weather_forecasts, weather_alerts, wind_warnings
road_conditionsÉtat des routesroad_conditions, ice_roads, snow_plans
traffic_performancePerformance du trafictraffic_segments, speed_data, travel_times, express_lanes, hov_lanes
planned_eventsÉvénements et fermetures prévusworkzones, future_construction, future_roadwork, special_events, seasonal_loads
alerts_advisoriesAlertes et avisalerts, emergency_alerts, advisories, general_info
wildfiresFeux de forêtwildfires, wildfire_incidents, wildfire_perimeters
truckingCamionnage et véhicules commerciauxtruck_restrictions, weight_restrictions, bridge_clearances, truck_routes, freight_corridors, truck_parking, truck_rest_areas, weigh_stations, inspection_stations
traveler_servicesServices aux voyageursrest_areas, service_centres, info_centres, visitor_locations, parks, communities, carpool_lots, airports
fuel_chargingCarburant et rechargeev_charging, alt_fuel_stations
bordersFrontières et passagesborder_crossings, ports_of_entry
ferriesTraversiersferries, coastal_ferries
transitTransport en communtransit_hubs, transit_stops
tollsPéagestolls
static_infrastructureInfrastructure et applicationbridges, signs, roundabouts, speed_cameras
operationsOpérationsservice_vehicles

Types de fonctionnalités

Passez l'une de ces valeurs comme paramètre type à /features.

camerasCaptures de caméras de circulation avec URL d'images
weather_stationsCapteurs RWIS : température, vent, humidité, état de la chaussée
rest_areasAires de repos avec équipements (toilettes, wifi, vidange camping-car)
signsPanneaux à messages variables avec texte actuel
road_conditionsÉtat de la surface routière par segment
ev_chargingStations de recharge EV (registres nationaux de points de recharge)
bridge_clearancesGabarit vertical de pont, capacité de charge, statut d'affichage
truck_restrictionsLimites de hauteur/poids, zones matières dangereuses, permis
weight_restrictionsLimites de poids saisonnières/permanentes (polylignes)
truck_routesItinéraires camions désignés (polylignes)
freight_corridorsCorridors du réseau de fret, dont RTE-T (polylignes)
truck_parkingParkings poids lourds avec capacité et équipements
weigh_stationsEmplacements et statut des stations de pesage
traffic_segmentsDonnées des capteurs de flux de circulation (vitesse/volume)
service_vehiclesChasse-neige, véhicules de service DOT (saisonniers)
ferriesTerminaux de ferry et statut des lignes

Types d'événements

TypePlage de gravitéDescription
incidentmoderate–criticalAccidents, véhicules en panne, dangers
constructionminor–moderateTravaux routiers, entretien, revêtement
closuremajor–criticalFermetures totales de route
weathermoderate–criticalImpacts routiers liés à la météo
special_eventminor–moderateÉvénements planifiés (défilés, courses)
advisoryminor–moderateAvis de voyage, avertissements
restrictionminor–moderateRestrictions de poids, hauteur, vitesse

Plans & limites

LimiteFree (essai 14 jours)Starter (29 €/mois)Pro (99 €/mois)Enterprise
RPM603001 0005 000
Requêtes quotidiennes1 00050 000500 000Illimitées
Clés API131050
Juridictions/requête210IllimitéesIllimitées
Résultats/page1005001 000Illimités
Export GeoJSONNonOuiOuiOui
AnalytiqueNonNonOuiOui
Corridor poids lourdsNonNonOuiOui
Délai des données15 minTemps réelTemps réelTemps réel

Obtenir une clé API gratuite