api.rail-horizon.com — Documentation des endpoints
● Online Node.js / Express Socket.IO

📡 Vue d'ensemble

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.

ℹ️ Base URL : 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.
GroupePréfixeDescription
/trackingGPS TrackingRéception des positions, historique, dernière position
/pushPushClés VAPID, abonnements, envoi de notifications
/publicPublicFlotte publique, info réseau (auth : clé API association)
/widgetWidgetScript JS de suivi intégrable sur n'importe quel site
/overlaysOverlaysDonnées Open Data ferroviaires + détection contextuelle (ligne, quai, gares)
/healthSantéÉtat du serveur et de la base de données

🔐 Authentification

Trois mécanismes selon l'appelant.

TypeHeader / ParamUtilisé 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

📍 GPS Tracking

Endpoints pour envoyer des positions depuis une application mobile et lire les données en temps réel.

POST /tracking/update api_key Envoi d'une position GPS

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).

GET /tracking/live/:slug public Dernière position connue

:slug est l'access_slug du véhicule ou le delegate_slug d'une délégation.

ParamètreDescription
detectAjoute la détection contextuelle (ligne, quai, gares) dans la réponse — un seul appel au lieu de deuxoptionnel
{
  "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.

GET /tracking/history/:slug public Historique des positions
ParamètreDescription
limitNombre de points (défaut: 200, max: 1000)optionnel
sinceSeulement les positions après cette date ISO (sans date / from).optionnel
dateUne 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, toFenêtre exacte en secondes Unix [from ; to[ (recommandé : fuseau et heure d'été gérés par l'appelant, 3 jours maximum).optionnel
maxJourné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
snapsnap=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.

WS Socket.IO (namespace /) public Suivi temps réel

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.

GET /overlays/detect public Détection contextuelle (ligne, quai, gares)

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ètreDescription
latLatitude décimalerequis
lonLongitude décimalerequis
speedVitesse en km/h — sous 10 km/h, la détection « à quai » est activéeoptionnel
headingCap 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.

📱 Configuration Traccar Client

Le protocole OsmAnd permet d'envoyer des positions via une simple requête GET. Idéal pour Traccar Client (Android/iOS).

GET /tracking unique_id + api_key Protocole OsmAnd / Traccar

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ètreDescription
idIdentifiant unique de l'appareil (unique_id ex: RH-35DB4223) ou delegate_unique_id d'une délégationrequis
latLatitude décimalerequis
lonLongitude décimalerequis
speedVitesse en nœuds (×1.852 = km/h)optionnel
bearingCap en degrés (0–360)optionnel
altitudeAltitude en mètresoptionnel
battNiveau batterie (0–100)optionnel
⚠️ L'authentification via Traccar Client se fait par l'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

Frequency10–30 secondes selon la vitesse du véhicule
Distance50–100 mètres
AccuracyHigh (GPS)

🔔 Notifications Push

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.

GET /push/vapid-public/:siteApiKey public Clé VAPID publique d'un site

Retourne la clé publique VAPID nécessaire pour créer un abonnement push côté navigateur.

{ "publicKey": "BGxxxxxx..." }
POST /push/subscribe/:siteApiKey public Abonner un navigateur
{
  "subscription": {
    "endpoint": "https://fcm.googleapis.com/...",
    "keys": { "p256dh": "...", "auth": "..." }
  }
}

Utiliser l'objet retourné par serviceWorkerRegistration.pushManager.subscribe().

POST /push/unsubscribe/:siteApiKey public Désabonner un navigateur
{ "endpoint": "https://fcm.googleapis.com/..." }
POST /push/notify X-Internal-Secret Envoyer une notification (PHP uniquement)
⚠️ Cet endpoint est réservé au serveur PHP. Il nécessite le header 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
}

🌐 API Publique

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).

GET /public/fleet Bearer Flotte complète de l'association

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"
  }
]
GET /public/network/:slug public Informations publiques d'un réseau

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, ... }
  ]
}

💚 Santé du serveur

Endpoint de monitoring pour vérifier que l'API et la base de données sont opérationnelles.

GET /health public État du serveur
// Réponse OK (200)
{ "status": "ok", "ts": "2026-04-29T10:30:00.000Z" }

// Réponse erreur BDD (503)
{ "status": "db_error", "error": "..." }

🚂 Référence — Types de véhicules

Valeurs acceptées pour le champ vehicle_type.

ValeurDescription
locomotiveLocomotive (BB, CC, BB…)
automotriceAutomotrice (TGV, Intercités, Transilien…)
autorailAutorail (X 73500, AGC…)
tramTramway
busBus / Car
voitureVoiture remorquée
bateauBateau / ferry
autreAutre (défaut)