RoboVis API v1

API REST JSON versionnée. Auth JWT Bearer (HS256, 12h TTL). Déploiement air-gapped — pas de dépendance réseau externe.

Base URL : http://your-server:8080

Authentification

Toutes les routes sauf /v1/auth/login et /v1/insights/health requièrent un header Authorization: Bearer <token>.

POST /v1/auth/login Obtenir un token JWT public
ChampTypeDescription
username*stringNom d'utilisateur
password*stringMot de passe
curl -X POST http://localhost:8080/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"constructor_admin","password":"constructor123"}'
{ "token": "eyJ...", "tenant_id": "constructor-acme", "tenant_type": "constructor", "role": "admin" }
POST /v1/auth/refresh Renouveler un token JWT JWT

Retourne un nouveau token à partir d'un token encore valide.

curl -X POST http://localhost:8080/v1/auth/refresh \
  -H "Authorization: Bearer $TOKEN"
{ "token": "eyJ..." }

Robots

GET /v1/robots Liste des robots du tenant JWT
curl http://localhost:8080/v1/robots -H "Authorization: Bearer $TOKEN"
[{ "robot_id": "BDY-042", "tenant_id": "client-alpha", "last_seen_ms": 1744000000000 }]
GET /v1/client/robots/:id/timeline Timeline d'activité d'un robot JWT
curl "http://localhost:8080/v1/client/robots/BDY-042/timeline" \
  -H "Authorization: Bearer $TOKEN"

Insights LLM

GET /v1/insights Liste des insights générés JWT
Query paramTypeDescription
robot_id?stringFiltrer par robot
limit?integerNombre max (défaut 20, max 100)
curl "http://localhost:8080/v1/insights?limit=5" -H "Authorization: Bearer $TOKEN"
POST /v1/insights/analyze Déclencher une analyse LLM JWT
ChampTypeDescription
kind*stringfleet_health | feature_adoption_report | user_journey_analysis | friction_emerging_usage | cross_environment_comparison | predictive_maintenance | robot_anomaly | daily_digest
robot_id?stringRequis pour robot_anomaly, daily_digest
ollama_url?stringDéfaut: valeur de ROBOVIS_OLLAMA_URL, sinon http://localhost:11434
model?stringDéfaut: mistral
curl -X POST http://localhost:8080/v1/insights/analyze \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind":"friction_emerging_usage"}'

Webhooks

Les webhooks envoient un POST vers votre URL à chaque événement. Payload JSON signé optionnellement avec un secret HMAC.

GET /v1/webhooks Lister les webhooks du tenant JWT
curl http://localhost:8080/v1/webhooks -H "Authorization: Bearer $TOKEN"
POST /v1/webhooks Créer un webhook JWT

Événements disponibles : insight.created · anomaly.critical · prediction.high_risk · robot.offline · report.ready · * (tous)

ChampTypeDescription
url*stringURL de destination (HTTPS recommandé)
events*string[]Liste des événements à écouter
secret?stringSecret HMAC pour la vérification
curl -X POST http://localhost:8080/v1/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.internal/hooks/robovis",
    "events": ["insight.created", "anomaly.critical"],
    "secret": "votre_secret_hmac"
  }'

Payload webhook

{
  "event": "insight.created",
  "timestamp": "2026-04-08T14:30:00Z",
  "tenant_id": "constructor-acme",
  "data": {
    "insight_id": "ins_abc123",
    "kind": "friction_emerging_usage",
    "severity": "critical"
  }
}
DELETE /v1/webhooks/:id Supprimer un webhook JWT
curl -X DELETE http://localhost:8080/v1/webhooks/wh_abc123456 \
  -H "Authorization: Bearer $TOKEN"

Client — Prévisions

GET /v1/client/fleet-health Santé de la flotte client JWT (client)
curl http://localhost:8080/v1/client/fleet-health \
  -H "Authorization: Bearer $CLIENT_TOKEN"
[{ "robot_id": "BDY-042", "health_score": 82, "risk_level": "low", "predicted_failure": "none" }]
GET /v1/client/predictions Prédictions de panne JWT (client)
curl http://localhost:8080/v1/client/predictions \
  -H "Authorization: Bearer $CLIENT_TOKEN"

Tenant

GET /v1/tenant/settings Paramètres du tenant courant JWT
curl http://localhost:8080/v1/tenant/settings -H "Authorization: Bearer $TOKEN"

Exemples d'intégration

Python

import requests

BASE = "http://localhost:8080"

# Login
r = requests.post(f"{BASE}/v1/auth/login",
    json={"username": "constructor_admin", "password": "constructor123"})
token = r.json()["token"]
headers = {"Authorization": f"Bearer {token}"}

# Lister les insights
insights = requests.get(f"{BASE}/v1/insights?limit=10", headers=headers).json()
for ins in insights:
    print(ins["kind"], ins["analysis_text"][:80])

JavaScript / fetch

const BASE = "http://localhost:8080";

const { token } = await fetch(`${BASE}/v1/auth/login`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ username: "constructor_admin", password: "constructor123" })
}).then(r => r.json());

const insights = await fetch(`${BASE}/v1/insights`, {
  headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json());

console.log(insights);

curl — flux complet

TOKEN=$(curl -s -X POST http://localhost:8080/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"constructor_admin","password":"constructor123"}' | jq -r .token)

# Déclencher une analyse
INSIGHT_ID=$(curl -s -X POST http://localhost:8080/v1/insights/analyze \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind":"friction_emerging_usage"}' | jq -r .insight_id)

# Lire le résultat
curl -s "http://localhost:8080/v1/insights?limit=1" \
  -H "Authorization: Bearer $TOKEN" | jq '.[0].analysis_text'