Zum Inhalt springen

API-Übersicht

Tocco-Mate exponiert eine schlanke REST-API. Alle Endpoints (außer /healthz) erfordern einen Bearer-Token im Authorization-Header.

Terminal-Fenster
curl -H "Authorization: Bearer $API_TOKEN" \
http://localhost:3000/api/noten

$API_TOKEN findest du nach dem ersten Start in data/.api-token oder in den Logs (AUTO-GENERATED API TOKEN).

MethodePfadBeschreibung
GET/healthzHealth-Check (kein Auth)
MethodePfadBeschreibung
GET/api/statusScheduler- und Server-Status
MethodePfadBeschreibung
GET/api/settingsSettings lesen
PATCH/api/settingsSettings ändern (validiert + persistiert)
MethodePfadBeschreibung
GET/api/notenNoten (?semester=S1&sortBy=note)
GET/api/noten/:id/pruefungenLB / ZP / OTHER eines Moduls
GET/api/history/:idNotenverlauf eines Moduls
GET/api/statsGesamt-Statistiken
MethodePfadBeschreibung
GET/api/stundenplanTermine (?from=YYYY-MM-DD&limit=100)
POST/api/stundenplan/clearAlle Stundenplan-Einträge löschen
MethodePfadBeschreibung
POST/api/scrapeManuellen Scrape auslösen
MethodePfadBeschreibung
GET/api/eventsSSE-Stream für Live-Status (akzeptiert ?token=…)
GET/api/logsLetzte Log-Zeilen
MethodePfadBeschreibung
GET/api/push/vapid-keyVAPID-Public-Key der PWA
POST/api/push/subscribePush-Subscription registrieren
DELETE/api/push/subscribePush-Subscription entfernen
POST/api/push/testTest-Push an alle Subscriptions

Alle Endpoints antworten mit JSON. Standard-Envelope:

{
"data": { /* Payload */ },
"error": null
}

Bei Fehlern:

{
"data": null,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing bearer token"
}
}
Terminal-Fenster
curl -H "Authorization: Bearer $API_TOKEN" \
"http://localhost:3000/api/noten?semester=S1&sortBy=note"
Terminal-Fenster
curl -H "Authorization: Bearer $API_TOKEN" \
"http://localhost:3000/api/noten/M114/pruefungen"
const es = new EventSource('/api/events?token=' + API_TOKEN);
es.onmessage = (e) => {
const data = JSON.parse(e.data);
console.log('event:', data.type, data.payload);
};

Event-Typen: scrape:start, scrape:phase, scrape:done, note:new, note:changed, room:changed.

const reg = await navigator.serviceWorker.ready;
const sub = await reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(vapidPublicKey),
});
await fetch('/api/push/subscribe', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(sub),
});
EndpointLimit
/api/* (Auth-Fehler)10 / 15 min, 50 / 6 h
/api/events (Auth-Fehler)60 / 15 min
/api/scrapeImplicit (single-flight) — gleichzeitige Aufrufe werden serialisiert

Siehe Sicherheit.

Default: kein CORS-Header — die API ist same-origin only (vom Dashboard / Mobile-PWA aus).

Wenn du externe Clients brauchst, ergänze einen CORS-Middleware-Hook in src/server.js.