L'API Node.js gère la réception GPS temps-réel, les notifications push VAPID, et la distribution des données publiques. Le site PHP (rail-horizon.com) orchestre l'authentification et la gestion métier.
https://api.rail-horizon.com — Toutes les routes sont en HTTPS. Le serveur est optionnel : si il devient inaccessible, le site PHP bascule automatiquement sur un fallback base de données.
| Groupe | Préfixe | Description |
|---|---|---|
| /tracking | GPS Tracking | Réception des positions, historique, dernière position |
| /push | Push | Clés VAPID, abonnements, envoi de notifications |
| /public | Public | Flotte publique, info réseau (auth : clé API association) |
| /widget | Widget | Script JS de suivi intégrable sur n'importe quel site |
| /overlays | Overlays | Données Open Data ferroviaires + détection contextuelle (ligne, quai, gares) |
| /health | Santé | État du serveur et de la base de données |
Trois mécanismes selon l'appelant.
| Type | Header / Param | Utilisé par |
|---|---|---|
| api_key appareil | Header X-API-Key ou body api_key |
Applications GPS (Traccar, BGeo) pour envoyer des positions |
| Bearer (association) | Header Authorization: Bearer CLE ou ?key=CLE |
API publique — récupérer la flotte/réseau d'une association |
| X-Internal-Secret | Header X-Internal-Secret: SECRET |
Serveur PHP uniquement (push/notify, relais internes) |
| Public (aucune auth) | — | Lecture des positions live/historique via le slug public |
Endpoints pour envoyer des positions depuis une application mobile et lire les données en temps réel.
Accepte trois formats de body JSON :
Format Background Geolocation (BGeo)
{
"device_id": "RH-XXXXXXXX",
"api_key": "votre_cle_api_appareil",
"location": {
"coords": {
"latitude": 48.8566,
"longitude": 2.3522,
"speed": 13.8, // m/s — -1 si indisponible
"heading": 90.0,
"altitude": 35.0,
"accuracy": 4.2
},
"battery": { "level": 0.87, "is_charging": false },
"is_moving": true,
"odometer": 12345.6
}
}
Format plat
{
"device_id": "RH-XXXXXXXX",
"api_key": "votre_cle_api_appareil",
"lat": 48.8566,
"lon": 2.3522,
"speed": 45.5, // km/h
"altitude": 35.0,
"accuracy": 4.2
}
Réponse : {"ok": true} — La position est diffusée en temps réel via Socket.IO (room track:ACCESS_SLUG).
:slug est l'access_slug du véhicule ou le delegate_slug d'une délégation.
| Paramètre | Description | |
|---|---|---|
| detect | Ajoute la détection contextuelle (ligne, quai, gares) dans la réponse — un seul appel au lieu de deux | optionnel |
{
"slug": "abc123",
"name": "BB 17016",
"vehicle_type": "locomotive",
"is_online": true,
"lat": 48.8566,
"lon": 2.3522,
"speed": 45.5,
"heading": 90,
"altitude": 35,
"accuracy": 4.2,
"status_message": null,
"garage_mode": false,
"ts": "2026-04-29T10:30:00.000Z",
// présent uniquement avec ?detect=1 — null si la détection est indisponible
"detection": {
"isAtPlatform": true,
"platform": { "gare": "Paris-Nord-Surface", "voie": "272000-1-18", ... },
"nearestStation": { "nom": "Paris Gare du Nord", "distM": 238 },
"nextStation": { "nom": "Paris Est", "distM": 602 },
"currentLine": { "nom": "Ligne de Paris-Nord à Lille", "vmax": 60, "voltage": "25000", ... }
}
}
Une détection en échec (fichiers SNCF injoignables) ne fait jamais échouer la position : detection vaut simplement null.
| Paramètre | Description | |
|---|---|---|
| limit | Nombre de points (défaut: 200, max: 1000) | optionnel |
| since | Seulement les positions après cette date ISO (sans date / from). | optionnel |
| date | Une journée — format YYYY-MM-DD. Avec tz (minutes à l'est de UTC, ex. 120) : la journée dans CE fuseau ; sinon, journée « heure de la base ». | optionnel |
| from, to | Fenêtre exacte en secondes Unix [from ; to[ (recommandé : fuseau et heure d'été gérés par l'appelant, 3 jours maximum). | optionnel |
| max | Journée allégée (200–6000 points) : réponse { points, total, rejected, hidden, shown, stats, off_rail? }. stats = distance, vitesses moyenne et maximale calculées sur toutes les positions plausibles. Sans max, une journée de plus de 5 000 positions est allégée automatiquement (≈ 3 000 points, tableau). | optionnel |
| snap | snap=1 : positions recalées sur la voie ferrée la plus probable (lat/lon recalés, raw_lat/raw_lon d'origine, on_rail) ; avec max : off_rail = tronçons qui ne suivent aucune voie (trajet en voiture…). | optionnel |
Sans fenêtre de temps : tableau des dernières positions (ordre chronologique). Avec une fenêtre : toute la journée, ordre ASC, horodatages ISO UTC exacts. Les sauts GPS impossibles sont écartés (rejected) ; les positions masquées par le propriétaire (nettoyage du tracé) n'apparaissent pas.
Connexion et abonnement
// Script Socket.IO disponible sur l'API elle-même const socket = io('https://api.rail-horizon.com'); // S'abonner au slug d'un véhicule socket.emit('subscribe', 'abc123'); // Recevoir les positions en temps réel socket.on('position', (data) => { console.log(data.lat, data.lon, data.speed); // data.slug, data.lat, data.lon, data.speed, data.heading, // data.altitude, data.battery, data.accuracy, // data.is_moving, data.is_charging, data.ts }); // Se désabonner socket.emit('unsubscribe', 'abc123');
Chaque véhicule émet dans la room track:ACCESS_SLUG à chaque nouvelle position reçue.
Calcule, à partir d'une position, la ligne ferroviaire empruntée (nom, vitesse max, tension), si le véhicule est à quai, la gare la plus proche
et la prochaine gare devant lui. Utilisée en interne par les widgets carte et statistiques — utilisable directement pour toute intégration
(pas besoin d'implémenter la géométrie et de charger les fichiers SNCF Open Data vous-même). Si vous suivez déjà un véhicule par son
:slug, préférez /tracking/live/:slug?detect=1
qui renvoie la position et la détection en un seul appel.
| Paramètre | Description | |
|---|---|---|
| lat | Latitude décimale | requis |
| lon | Longitude décimale | requis |
| speed | Vitesse en km/h — sous 10 km/h, la détection « à quai » est activée | optionnel |
| heading | Cap en degrés (0–360) — affine la « prochaine gare » (cône ±45° devant le véhicule) | optionnel |
Exemple
GET /overlays/detect?lat=48.88204687&lon=2.35676191&speed=0&heading=195.43
Réponse
{
"isAtPlatform": true,
"platform": {
"gare": "Paris-Nord-Surface",
"libelle": "Quai 18/19",
"voie": "272000-1-18",
"longueur": 405,
"distM": 0
},
"nearestStation": { "nom": "Paris Gare du Nord", "distM": 238 },
"nextStation": { "nom": "Paris Est", "distM": 602 },
"currentLine": {
"nom": "Ligne de Paris-Nord à Lille",
"code": "272000",
"vmax": 60,
"voltage": "25000",
"distM": 18,
"pk": 0
}
}
CORS ouvert (utilisable depuis n'importe quel site). Réponse mise en cache 20 s. Limite : 300 requêtes / 15 min / IP, comme le reste de /overlays.
Le protocole OsmAnd permet d'envoyer des positions via une simple requête GET. Idéal pour Traccar Client (Android/iOS).
URL du serveur à saisir dans Traccar Client : https://track.rail-horizon.com (équivalent à https://api.rail-horizon.com/tracking). Requête envoyée par l'application :
https://track.rail-horizon.com/?id={deviceId}&lat={lat}&lon={lon}&speed={speed}&bearing={heading}&altitude={altitude}&batt={battery}
| Paramètre | Description | |
|---|---|---|
| id | Identifiant unique de l'appareil (unique_id ex: RH-35DB4223) ou delegate_unique_id d'une délégation | requis |
| lat | Latitude décimale | requis |
| lon | Longitude décimale | requis |
| speed | Vitesse en nœuds (×1.852 = km/h) | optionnel |
| bearing | Cap en degrés (0–360) | optionnel |
| altitude | Altitude en mètres | optionnel |
| batt | Niveau batterie (0–100) | optionnel |
unique_id de l'appareil. Cet identifiant est généré automatiquement et visible dans le Dashboard → Véhicules. Il n'est pas à confondre avec la clé API de l'association.
Paramètres recommandés dans Traccar Client
| Frequency | 10–30 secondes selon la vitesse du véhicule |
| Distance | 50–100 mètres |
| Accuracy | High (GPS) |
Web Push VAPID — les abonnements sont liés à des "sites push" créés dans le Dashboard. Chaque site a sa propre paire de clés VAPID.
Retourne la clé publique VAPID nécessaire pour créer un abonnement push côté navigateur.
{ "publicKey": "BGxxxxxx..." }
{
"subscription": {
"endpoint": "https://fcm.googleapis.com/...",
"keys": { "p256dh": "...", "auth": "..." }
}
}
Utiliser l'objet retourné par serviceWorkerRegistration.pushManager.subscribe().
{ "endpoint": "https://fcm.googleapis.com/..." }
X-Internal-Secret partagé entre les deux serveurs.
{
"site_id": 42,
"title": "Nouvelle position",
"body": "Le train est en gare de Lyon.",
"url": "https://www.rail-horizon.com/track/abc123",
"icon": "https://..." // optionnel
}
Accès aux données d'une association depuis un service externe. Nécessite la clé API de l'association (visible dans Dashboard → Intégration).
Deux formes d'authentification acceptées :
// Via header Authorization: Bearer VotreCleApiAssociation // Via query param GET /public/fleet?key=VotreCleApiAssociation
Réponse
[
{
"id": 1,
"name": "BB 26000",
"vehicle_type": "locomotive",
"access_slug": "abc123",
"is_online": true,
"last_lat": 48.8566,
"last_lon": 2.3522,
"last_speed": 145.0,
"last_seen": "2026-04-29T10:30:00.000Z"
}
]
Retourne les infos de l'association et ses véhicules actifs. Le :slug est visible dans l'URL rail-horizon.com/reseau/:slug.
{
"id": 1,
"name": "Association AAPSL",
"description": "...",
"logo_url": "https://...",
"vehicles": [
{ "name": "BB 26000", "access_slug": "abc123", "is_online": true, ... }
]
}
Endpoint de monitoring pour vérifier que l'API et la base de données sont opérationnelles.
// Réponse OK (200) { "status": "ok", "ts": "2026-04-29T10:30:00.000Z" } // Réponse erreur BDD (503) { "status": "db_error", "error": "..." }
Valeurs acceptées pour le champ vehicle_type.
| Valeur | Description |
|---|---|
| locomotive | Locomotive (BB, CC, BB…) |
| automotrice | Automotrice (TGV, Intercités, Transilien…) |
| autorail | Autorail (X 73500, AGC…) |
| tram | Tramway |
| bus | Bus / Car |
| voiture | Voiture remorquée |
| bateau | Bateau / ferry |
| autre | Autre (défaut) |