Zum Inhalt springen
HTTP-API

HTTP-API

Jeder Client von samudo, die Web-Oberfläche eingeschlossen, benutzt diese API und nichts sonst. Die Kommandozeile deckt sie ganz ab, also ist samu <kommando> --format json der schnellste Weg, eine Antwort zu sehen. Die Wire-Typen sind das Rust-Crate samu-api (nur serde, eigens versioniert); JSON-Beispiele jedes Typs liegen in crates/samu-api/tests/fixtures/.

Konventionen

  • IDs sind UUIDv7, Zeitstempel ISO 8601 in UTC mit Z, Zeitspannen ISO-8601-Dauern (PT15M, P2D).
  • Ein Datum ist {"date": "2026-11-20"} (ein ganzer Tag, keine Zone) oder {"at": "2026-11-20T09:00:00+01:00[Europe/Berlin]"} (ein Zeitpunkt mit seiner Zone).
  • Felder, die ein Leser nicht kennt, bleiben erhalten; Enum-Werte einer neueren Version lesen sich als unknown und werden nie zurückgeschrieben.
  • Fehler sind ein Statuscode mit {"error": "not_found", "message": "…"}; Arten sind etwa unauthorized, not_found, offline (eine Replik ohne ihren Server).

Anmelden

POST /login
{"account": "privat", "password": "…", "device": "laptop"}

antwortet mit einem Sitzungs-token und seinem Ablauf und setzt für Browser ein Cookie. Das Token als Authorization: Bearer <token> senden. Mit "kind": "agent" ist die Sitzung die eines Agenten: Was sie schreibt, ist als solches markiert. GET /session zeigt die Sitzung sowie Zone und Einstellungen des Kontos; POST /logout beendet sie.

Koppeln: POST /pair/code (noch einmal mit dem Passwort) macht einen Einmal-Code für zehn Minuten; POST /pair tauscht ihn auf dem neuen Gerät gegen eine Sitzung.

Lesen

Route
GET /availableoffene Aufgaben mit Verfügbarkeit, jedem Grund, Zustand und nächstem Zustand; Filter: nur verfügbar, heute, Projekt, alle, Scope, Perspektive
GET /available/projects, /available/foldersProjekte (stuck, Review fällig) und Ordner
GET /forecastdie Abschnitte des Forecasts, jede Zeile mit dem Grund, warum sie dort steht
GET /objects/{id}ein Objekt beliebiger Art
GET /objects/{id}/logbooksein Verlauf
GET /changes?after=<seq>jedes Objekt, das sich nach einer Änderungsnummer geändert hat, für den Cache eines Clients
GET /habits, /habits/{id}Stand, Serien und Einträge der Gewohnheiten
GET /appointmentsTermine einiger Tage, Wiederholungen aufgefaltet
GET /clocks/report, GET /reportZeit und Bericht
GET /scopes/scheduledwelchen Scope die Zeitpläne jetzt wählen, und bis wann
GET /blobs/{sha256}die Datei hinter einem Anhang
GET /exportdas ganze Konto (siehe Selbst hosten)
GET /health{"status": "ok", "version": …, "api": …}, ohne Sitzung

Schreiben

Fast jedes Schreiben ist eine Liste von Änderungen an POST /changes. Eine Änderung ist eine von:

{"op": "create", "object": "<id>", "kind": "task", "value": {…ganzes Objekt…}, "hlc": …}
{"op": "set",    "object": "<id>", "field": "due", "value": {"date": "2026-11-20"}, "hlc": …}
{"op": "add",    "object": "<id>", "field": "tags", "element": "<tag id>", "position": 0, "hlc": …}
{"op": "remove", "object": "<id>", "field": "tags", "element": "<tag id>", "hlc": …}
{"op": "delete", "object": "<id>", "hlc": …}

set mit null leert ein Feld; eine Property ist das Feld properties.<schlüssel>. create ist über die ID idempotent, also macht ein Client die ID selbst und darf dieselbe Änderung zweimal senden. Änderungen an Zuständen und am Erledigen dürfen eine note fürs Logbuch tragen.

hlc ist ein Stempel einer hybriden logischen Uhr, {"wall": <ms>, "counter": n, "device": "laptop"}. Der Server entscheidet je Feld: Der spätere Stempel gewinnt. Jede Änderung bekommt ein Ergebnis:

{"outcome": "applied", "seq": 185}
{"outcome": "superseded", "by": {"wall": …, "counter": 0, "device": "phone"}}
{"outcome": "rejected", "reason": "field \"due\" expects {\"date\"} or {\"at\"}"}

Schreiben mit eigener Logik hat eigene Routen:

Route
POST /captureeine Zeile der Schnellerfassung: Vorschau, anlegen oder auf eine Aufgabe anwenden
POST /objects/{id}/deletelöschen, mit dem, was daran hängt
PUT /blobs/{sha256}eine Datei hochladen; danach einen Anhang anlegen, der sie nennt
POST /rendereine Notiz oder ein Kommentar als Dokumentbaum
PUT /calendars/{id}/source, POST /calendars/{id}/refresh, POST /calendars/discoverKalenderquellen
POST /appointments/{id}/editeinen Termin oder Vorkommen davon ändern
GET, POST /hooksWebhooks des Kontos
POST /hooks/{name}eine signierte Zustellung von außen, ohne Sitzung

Live

GET /events ist ein Strom von Server-Sent Events. Ein Ereignis changed trägt nur IDs, nie Inhalt:

{"seq": 184, "gone": ["…"], "added": ["…"], "changed": ["…"], "config": false}

Ein Client lädt neu, was er zeigt; config: true heißt, die Einstellungen des Kontos haben sich geändert. Ein Ereignis reset ({"seq": 190}) heißt: alles, was man zeigt, von Grund auf neu laden.

Routen der Web-Oberfläche

/ und /lib/… liefern die Web-Oberfläche aus dem Binary; /o/{id} öffnet darin ein Objekt.