Öffentliche API
Buchungen von aussen einliefern und dein Kontenbuch auslesen — Token, Idempotenz und die Grenzen, die du kennen solltest, bevor du ein Skript schreibst.
Unter /api/public/* liegt eine REST-Schnittstelle, mit der ein Skript, ein Automatisierungsdienst oder eine App Buchungen einliefern und dein Kontenbuch lesen kann. So kommen die Zeilen von FinReader in die App.
Die Endpunkte selbst stehen hier bewusst nicht. Sie sind in einer OpenAPI-Datei beschrieben, die aus dem Code erzeugt wird und damit immer aktuell ist — eine Abschrift hier wäre in einem Monat falsch. Zum Ausprobieren:
- Swagger UI: cash-flow.wi-wo.ch/api/public/docs
- Rohe Spezifikation:
/api/public/openapi
Auf dieser Seite steht das, was in der Spezifikation nicht steht und sich auch nicht ändert.
Anmeldung
Ein Token erstellst du unter Einstellungen → API-Tokens. Es wird einmal angezeigt; danach liegt nur noch ein Hash davon in der Datenbank, und niemand — auch die betreibende Person nicht — kann es dir noch einmal zeigen. Verloren heisst neu ausstellen.
Mitschicken als Bearer-Token:
Authorization: Bearer cfjm_dein-token
Ein Token kann alles
Es gibt keine Scopes. Ein gültiges Token darf alles, was die API kann, auf allen Daten deines Accounts: Buchungen anlegen, offene Buchungen lesen und löschen, Konten und Kategorien auflisten. Du kannst kein Token ausstellen, das nur schreiben oder nur ein Konto sehen darf.
Praktisch heisst das: gib ein Token nur an etwas weiter, dem du deinen ganzen Account anvertraust, und leg pro Client ein eigenes an — dann kannst du eines zurückziehen, ohne die anderen zu treffen. Zurückziehen geht sofort und wirkt beim nächsten Aufruf.
Es gibt kein Rate Limit
Die API drosselt nichts. Ein Skript in einer Endlosschleife bremst deine eigene Instanz, und niemand hält es auf. Bau die Pausen in deinen Client ein.
Zweimal schicken ist sicher
Buchungen, die du als offen einlieferst, kannst du mit zwei Feldern eindeutig machen:
external_source— wer sie geschickt hat, z. B.FinReaderexternal_ref— deine eigene ID für genau diesen Vorgang
Kommt dieselbe Kombination ein zweites Mal, legt die App keine zweite Zeile an. Sie gibt die bestehende zurück, mit deduplicated: true und Status 200 statt 201.
Das ist die Rettung für jeden Client mit wackeliger Verbindung: Timeout beim Senden, nochmal schicken, kein Duplikat. Ohne external_ref gibt es diesen Schutz nicht — dann ist jeder Aufruf eine neue Buchung.
Löschen geht über dieselbe Kombination. Eine bereits bestätigte Zeile lässt sich nicht mehr löschen (Status 409): daraus ist eine echte Buchung geworden, und die gehört dir, nicht dem Client.
Nichts wird ungefragt gebucht
Was über die API kommt, landet unter Offen und wartet. Kategorie, Beschreibung und Notiz können vorgeschlagen werden — von deiner eigenen Historie oder vom KI-Assistenten —, aber gebucht wird erst, wenn du bestätigst. Siehe Offene Buchungen.
Drei Endpunkte gehören dem Betrieb
/api/public/metrics, /api/public/prune-audit und /api/public/process-recurring nehmen kein persönliches Token, sondern ein Server-Geheimnis aus den Umgebungsvariablen. Sie sind für Cronjobs und Monitoring gedacht, nicht für Clients; ist die Variable nicht gesetzt, antworten sie mit 503 statt offen zu stehen. Details stehen im README des Projekts.
Wenn etwas schiefgeht
Fehler kommen als JSON, {"error": "..."}. Bei ungültigen Feldern liegt unter details dazu, welches Feld warum abgelehnt wurde. Interne Datenbankfehler werden protokolliert, aber nicht ausgeliefert — im Log der Instanz steht mehr als in der Antwort.