EasyTrack API

API REST publique permettant à des applications tierces d'intégrer les fonctionnalités EasyTrack : positions GPS temps réel, devices, geofences, alertes, rapports PDF, share-links et exports d'historique.

Vue d'ensemble

L'API EasyTrack est une API REST JSON hébergée sur Cloudflare (edge, région UE). Toutes les requêtes doivent être en HTTPS. Les réponses sont au format application/json sauf mention contraire (PDF, CSV, KML…).

Domainehttps://api.easytrack.ch
FormatJSON UTF-8
AuthBearer token (obtenu via OTP email)
CORSOuvert aux origines autorisées (contacter le support)
HébergementCloudflare EU · D1 (WEUR) · R2

URL de base

https://api.easytrack.ch

Versionnage

L'API n'a pas encore de préfixe de version dans l'URL. Les évolutions non rétrocompatibles seront annoncées via un préfixe /v2 et une période de dépréciation de 6 mois.

Quotas & limites

Authentification par OTP

L'authentification se fait par code à usage unique (OTP) envoyé par email. Après vérification, l'API retourne un jeton Bearer à utiliser dans toutes les requêtes ultérieures.

POST /auth/request-code Public

Envoie un code OTP à 6 chiffres à l'adresse email fournie.

Body

{
  "email": "user@example.com",
  "lang": "fr"        // optionnel : fr, en, de, it, es, pt, nl, tr
}

Réponse

{
  "success": true,
  "message": "Code envoyé par email",
  "expires_in": 600
}
POST /auth/verify-code Public

Vérifie l'OTP et retourne un jeton Bearer.

Body

{
  "email": "user@example.com",
  "code":  "123456"
}

Réponse (succès)

{
  "success": true,
  "token": "eyJhbGci…",           // Bearer token
  "expires_at": "2026-08-01T…Z",
  "user": {
    "id": 42,
    "email": "user@example.com",
    "role": "client",
    "is_2fa_enabled": false
  }
}

Réponse (2FA requis)

{
  "success": true,
  "requires_2fa": true,
  "pending_token": "…"            // à utiliser dans /auth/verify-2fa
}

Utiliser le jeton Bearer

Toutes les routes protégées attendent le header suivant :

Authorization: Bearer <token>
Sécurité Le jeton est équivalent à un mot de passe. Ne le stockez jamais côté frontend public. Il expire après 30 jours d'inactivité.

Magic link

POST /auth/magic-link Public

Envoie un lien magique par email permettant une connexion sans code. Utile pour des liens embarqués dans des emails.

{ "email": "user@example.com", "lang": "fr" }

Deuxième facteur (TOTP)

POST /auth/2fa/setupGénère un secret + QR-code
POST /auth/2fa/verifyActive le 2FA après vérification
POST /auth/verify-2faVérifie le code TOTP au login
POST /auth/2fa/disableDésactive le 2FA
GET /auth/2fa/statusÉtat actuel du 2FA

Session courante

GET /auth/me Bearer

Retourne le profil de l'utilisateur connecté.

POST /auth/logout Bearer

Révoque le jeton courant.

Positions GPS

Points GPS bruts et enrichis (adresse, allumage, batterie…). Deux tables distinctes : raw_positions (tous les points) et positions (points filtrés, utilisés par le replay).

GET /positions/latest Bearer

Dernière position connue de tous les devices auxquels le compte a accès.

Query params

ParamètreTypeDescription
imeisstringFiltrer par IMEIs (séparés par virgules)
include_addressboolReverse-geocode chaque point

Réponse

{
  "success": true,
  "positions": [
    {
      "imei": "862272081390363",
      "latitude": 46.2044,
      "longitude": 6.1432,
      "speed": 42,
      "angle": 187,
      "ignition": 1,
      "server_timestamp": "2026-06-30T14:22:08Z",
      "address": "Rue de Bâle 14, 1201 Genève, Suisse"
    }
  ]
}
GET /positions Bearer

Positions filtrées (replay quality) pour un device sur une plage temporelle.

ParamètreTypeDescription
imeistringObligatoire
fromISO 8601Date de début (UTC)
toISO 8601Date de fin (UTC)
limitintMax 5000
GET /positions/imei/{imei} Bearer

Positions filtrées pour un IMEI (raccourci).

GET /positions/export Bearer

Export brut paginé (raw_positions) - tous les points GPS reçus. Utilisez la pagination via page.

ParamètreDescription
imeiObligatoire
from, toPlage temporelle (ISO 8601)
pageIndex de page (0 par défaut, 5000 points/page)

Réponse

{
  "success": true,
  "imei": "…",
  "page": 0,
  "page_size": 5000,
  "count": 4823,
  "has_more": false,
  "positions": [ /* … */ ]
}

Devices

GET /devices Bearer

Liste des devices assignés au compte connecté.

{
  "success": true,
  "devices": [
    {
      "id": 12, "imei": "862272081390363",
      "plate": "GE888222", "model": "Vivaro",
      "type": "vehicle",
      "is_active": 1,
      "last_seen_at": "2026-06-30T14:22:08Z"
    }
  ]
}
GET /devices/realtime Bearer

Vue optimisée pour dashboard temps réel : liste des devices + dernière position + état allumage/mouvement en une seule requête.

GET /devices/imei/{imei} Bearer

Détail d'un device par son IMEI.

GET /devices/active-days Bearer

Jours où chaque device a été actif (utile pour construire un date picker n'affichant que les dates avec données).

Geofences

Zones géographiques déclenchant des alertes d'entrée/sortie.

GET /geofences Bearer

Liste des geofences du compte.

POST /geofences Bearer

Crée une geofence circulaire ou polygonale.

{
  "name":  "Dépôt Genève",
  "type":  "circle",             // "circle" | "polygon"
  "center":  { "lat": 46.20, "lng": 6.14 },
  "radius_m": 250,
  "device_imeis": ["862272081390363"],
  "trigger_on":  ["enter", "exit"]
}
PUT /geofences/{id} Bearer

Met à jour une geofence.

DELETE /geofences/{id} Bearer

Supprime une geofence.

Alertes

GET /manager/alerts Bearer

Liste des alertes configurées pour le compte (vitesse, kilométrage, geofence, batterie…).

POST /manager/alerts Bearer

Crée une règle d'alerte.

{
  "type": "speed",                // speed | mileage | geofence | battery | offline
  "name": "Excès de vitesse",
  "threshold": 130,               // km/h pour speed
  "device_imeis": ["…"],
  "notify": ["email", "push"]
}
PUT /manager/alerts/{id} Bearer
DELETE /manager/alerts/{id} Bearer

Rapports PDF

Rapports générés côté serveur (Cloudflare Workers + pdf-lib) et stockés dans R2. Envoi automatique par email + URL publique protégée par un token opaque.

GET /manager/reports Bearer

Liste des configurations de rapports du compte.

POST /manager/reports Bearer

Crée une configuration de rapport (quotidien / hebdo / mensuel).

{
  "interval":       "weekly",        // daily | weekly | monthly
  "device_imeis":   ["…"],
  "email_to":       "user@example.com",
  "sections": {
    "summary":  true,
    "stats":    true,
    "trips":    true,
    "parkings": true,
    "alerts":   true
  }
}
POST /manager/reports/autoconfig Bearer

Crée automatiquement une configuration hebdomadaire par défaut incluant tous les devices du compte.

POST /manager/reports/{id}/run-now Bearer

Génère un rapport à la demande, avec option de plage personnalisée. Retourne un token public permettant d'accéder au PDF.

{
  "period_start": "2026-06-15T00:00:00Z",
  "period_end":   "2026-06-22T00:00:00Z",
  "email":        null                       // null = ne pas envoyer d'email
}
{
  "success": true,
  "id":      1287,
  "token":   "4cbc3a9bc89e783682a411…",
  "public_url": "https://api.easytrack.ch/reports/pdf/4cbc3a9…"
}
GET /manager/reports/{id}/runs Bearer

Historique des exécutions d'un rapport.

GET /reports/pdf/{token} Public (token)

Sert le PDF final. Content-Type application/pdf. Nom de fichier : EASYTRACK-YYYY-MM-DD-<CODE>.pdf. Aucun header d'auth n'est nécessaire : la possession du token fait foi.

Un share-link permet à un tiers non authentifié de voir en temps réel un ou plusieurs devices, pendant une durée limitée. Idéal pour partager la position d'une flotte à un client externe ou à un dispatcher.

GET /manager/share-links Bearer

Liste des liens de partage actifs.

POST /manager/share-links Bearer

Crée un lien de partage limité dans le temps.

{
  "name":         "Campagne juin 2026",
  "device_imeis": ["862272081390363", "862272081390400"],
  "expires_at":   "2026-07-05T18:00:00Z"    // ISO 8601 ou null (permanent)
}
{
  "success": true,
  "id":     37,
  "token":  "a1b2c3d4e5f6g7h8"              // → https://my.easytrack.ch/open/share/<token>
}
PUT /manager/share-links/{id} Bearer

Met à jour un lien (renommage, activation/désactivation, changement d'expiration).

DELETE /manager/share-links/{id} Bearer
GET /open/share/{token} Public (token)

Endpoint public retournant la carte HTML avec les devices autorisés. Aucun header d'auth : le token est la clé d'accès. Expire automatiquement selon expires_at.

Export historique

Deux niveaux d'export sont proposés :

Formats supportés côté frontend : JSON, CSV, GPX, KML, GeoJSON.

Manager (compte)

Endpoints généraux du compte connecté.

MéthodeCheminDescription
GET /manager/profile Profil du compte
PUT /manager/profile Mise à jour du profil
GET /manager/settings Paramètres UI/notifications
PUT /manager/settings Enregistre les paramètres
GET /manager/notificationsNotifications reçues
GET /manager/geofences Idem /geofences, scoped par compte

Format des réponses

Toutes les réponses succès suivent la structure suivante :

{
  "success": true,
  /* …données… */
}

En cas d'erreur :

{
  "success": false,
  "error":   "Message lisible",
  "code":    "ERR_INVALID_IMEI"       // optionnel
}

Codes d'erreur HTTP

CodeSignification
400Requête invalide (paramètre manquant/mal formé)
401Jeton absent ou invalide
403Accès non autorisé à cette ressource (device, geofence…)
404Ressource introuvable
410Ressource expirée (PDF, share-link)
429Rate limit dépassé
500Erreur serveur (contactez le support)
503Service dépendant indisponible (stockage, mail…)

Pagination

Les endpoints qui retournent potentiellement beaucoup de données utilisent une pagination par offset / page :

GET /positions/export?imei=…&page=0
↓
{
  "page": 0,
  "page_size": 5000,
  "count": 5000,
  "has_more": true,
  "positions": [ … ]
}

Dates & fuseaux

SDK & exemples

curl

# 1) Demander un OTP
curl -X POST https://api.easytrack.ch/auth/request-code \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com"}'

# 2) Vérifier le code
TOKEN=$(curl -s -X POST https://api.easytrack.ch/auth/verify-code \
  -H "Content-Type: application/json" \
  -d '{"email":"user@example.com","code":"123456"}' | jq -r .token)

# 3) Lister les devices
curl https://api.easytrack.ch/devices \
  -H "Authorization: Bearer $TOKEN"

JavaScript / TypeScript

const API = 'https://api.easytrack.ch';

async function login(email, code) {
  const r = await fetch(`${API}/auth/verify-code`, {
    method:  'POST',
    headers: { 'Content-Type': 'application/json' },
    body:    JSON.stringify({ email, code })
  });
  const { token } = await r.json();
  return token;
}

async function latestPositions(token) {
  const r = await fetch(`${API}/positions/latest`, {
    headers: { Authorization: `Bearer ${token}` }
  });
  return (await r.json()).positions;
}

Python

import requests

API = "https://api.easytrack.ch"

def login(email, code):
    r = requests.post(f"{API}/auth/verify-code",
                      json={"email": email, "code": code})
    return r.json()["token"]

def latest(token):
    r = requests.get(f"{API}/positions/latest",
                     headers={"Authorization": f"Bearer {token}"})
    return r.json()["positions"]

Support

Contact : api@easytrack.ch
Support 24 h / 7 j (plan Business) : support@easytrack.ch
Statut : status.easytrack.ch