LedgerLou Docs ist für Desktop optimiert.

Bitte öffne diese Seite auf einem Gerät mit breiterem Bildschirm.

LedgerLou Ledger Engine

LedgerLou Journal

Das Herzstück von LedgerLou: alle Buchungen landen hier als unveränderliche Einträge im Hauptbuch. Per REST API oder via MCP — jede Buchung folgt denselben GoBD-Regeln und ist vollständig nachvollziehbar.

API Reference
Manuelle BuchungenEinfache und Split-Buchungen direkt erfassen
Agentische BuchungenMCP Agent bucht mit Bestätigungsschleife
GoBD append-onlyKeine stille Änderung — je ein SHA256-Hash
Revisionssicheres StornoGegenbuchung statt Überschreiben
BelegverknüpfungDokument und Buchung in einem Schritt

Kernkonzepte

LedgerLou ordnet das Hauptbuch in drei Ebenen:

Journal -> Intents -> Buchungszeilen

Das Journal ist die Gesamtsicht. Darin liegen viele Intents. Jeder Intent gruppiert eine oder mehrere Buchungszeilen, die gemeinsam einen Buchungsvorgang bilden.

KonzeptWas es istPersistenz
JournalAppend-only Gesamtschau aller Intents eines Mandantenledger_events (GoBD-konform, hash-gekettet)
IntentFachliche Klammer für genau einen Buchungsvorgang innerhalb des JournalsKein eigener Datensatz — als intent_id in ledger_events, documents, bank_transactions u. a.
BuchungszeileEinzelne Soll/Haben-Zeile innerhalb eines Intentsledger_events (1+ Zeilen pro Intent)

Praktisch bedeutet das:

  • Das Journal listet alle Intents chronologisch.
  • Ein Intent gruppiert die Zeilen, die gemeinsam zu einem Vorgang gehören.
  • Eine Buchung kann aus einer oder mehreren Buchungszeilen bestehen, je nach Split und Steuerlogik.

Journal

Das Journal ist die ledger_events-Tabelle — der unveränderliche Kern von LedgerLou. Jede bestätigte Buchung schreibt hier append-only Zeilen:

  • Append-only — DB-Trigger verhindern UPDATE und DELETE (§ 146 AO / GoBD)
  • Hash-Kette — jede Zeile enthält einen audit_hash über die eigenen Felder plus den Hash der Vorgängerzeile — Manipulation wäre sofort erkennbar
  • Lückenlose Nummerierungjournal_number ist eine pro-Mandant monoton steigende Sequenz ohne Lücken
  • Intent-Gruppierung — Split-Buchungen schreiben mehrere Zeilen mit derselben intent_id

GET /v1/journal gibt diese Zeilen angereichert mit Kontonamen, verknüpften Dokumenten und Source-Metadaten zurück.

Intent

Ein Intent ist eine UUID, die einen Buchungsvorgang als Einheit kennzeichnet. Er entsteht im Moment der Buchungsbestätigung und verknüpft alle Zeilen dieses Vorgangs — bei Split-Buchungen können das mehrere ledger_events-Zeilen sein, die dennoch dieselbe intent_id tragen.

Gleichzeitig ist der Intent das gemeinsame Bindeglied aller Module: Banktransaktionen und Dokumente bekommen nach ihrer Verarbeitung eine intent_id zugewiesen, die auf die zugehörigen Buchungszeilen zeigt.

Ein Intent kann nicht gelöscht werden. Fehler werden durch ein Storno korrigiert: dabei entsteht ein neuer Intent mit vertauschten Konten, der über reverses_intent_id auf den ursprünglichen verweist — beide Einträge bleiben im Journal sichtbar. Ohne expliziten Korrekturmodus wird das Storno mit heutigem Datum in der aktuellen offenen Periode gebucht; die Ursprungsperiode bleibt unverändert.

Buchungszeilen und Buchungsvorgang

Ein Buchungsvorgang erzeugt einen Intent und schreibt eine oder mehrere Buchungszeilen ins Journal. Jede Buchung muss balanciert sein (Soll = Haben) — der Validator lehnt unausgeglichene Buchungen ab, bevor irgendetwas in die Datenbank geschrieben wird.

Buchungen entstehen auf drei Wegen:

QuelleWeg
Direkt via APIPOST /v1/bookings — rohe Journalzeilen explizit übergeben, sofort gebucht
Bank-AbgleichBuchung entsteht beim Zuordnen einer Banktransaktion zu einem offenen Posten
StornoGegenbuchung mit vertauschten Konten unter einer neuen Intent-ID

Intent-Lebenszyklus

Ein Intent ist unveränderlich. Sobald seine Zeilen im Journal stehen, werden sie nie mehr modifiziert oder gelöscht — auch nicht, wenn nachgelagerte Module wie der Bank-Abgleich ihre Zuordnung später wieder auflösen. Korrekturen entstehen ausschließlich durch neue Intents, die über reverses_intent_id auf den Ursprung verweisen.

Drei typische Szenarien zeigen, wie sich das im Zusammenspiel mit dem Bank-Abgleich konkret verhält:

Szenario 1Bank-Abgleich gegen eine bereits bestehende Buchung

Eine Rechnung wurde bereits manuell oder per API gebucht (Intent A, zwei Zeilen). Später trifft der Zahlungseingang auf dem Bankkonto ein und wird per Bank-Abgleich auf Intent A gezogen.

  1. 1Intent A existiert bereits im Journal — die beiden Zeilen sind unveränderlich.
  2. 2Beim Zuordnen wird ausschließlich auf der Banktransaktion ein Verweis gesetzt. Intent A wird nicht angefasst.
  3. 3Beim Rückgängigmachen des Abgleichs wird dieser Verweis auf der Banktransaktion wieder geleert. Intent A bleibt unberührt, es entsteht kein Storno.
Szenario 2Ausgleichs­buchung aus dem Bank-Abgleich

Für eine offene Forderung (Intent A) wird während des Bank-Abgleichs eine neue Ausgleichs­buchung erzeugt. Diese lebt als eigener Intent B im Journal und trägt einen Settlement-Verweis auf Intent A.

  1. 1Der Abgleich erzeugt Intent B mit Herkunft „Bank-Abgleich” und einem Settlement-Verweis auf Intent A.
  2. 2Die Banktransaktion wird mit Intent B verknüpft. Intent A bleibt exakt wie zuvor — nur noch als ausgeglichen markiert.
  3. 3Beim Rückgängigmachen entsteht ein Storno-Intent C, der Intent B mit vertauschten Konten spiegelt. Intent A wird wieder als offen geführt, ohne jemals modifiziert worden zu sein.
Szenario 3Storno eines bereits abgeglichenen Intents

Intent A (etwa eine Rechnung) wurde bereits durch eine Ausgleichs­buchung B aus dem Bank-Abgleich beglichen. Jetzt stellt sich heraus, dass Intent A falsch war und storniert werden muss.

  1. 1Zuerst wird die abhängige Ausgleichs­buchung B automatisch storniert — es entsteht Intent C, der B spiegelt.
  2. 2Anschließend wird Intent A storniert — es entsteht Intent D, der A spiegelt und per Storno-Verweis auf A zeigt.
  3. 3Alle vier Intents (A, B, C, D) bleiben im Journal sichtbar. Verknüpfte Banktransaktionen werden als offen markiert und können neu zugeordnet werden.

Reversal-Logik

Ein Storno ist in LedgerLou immer ein neuer Buchungs-Intent. Die Originalzeilen bleiben unverändert stehen, die Stornozeilen spiegeln Soll und Haben, übernehmen Audit-relevante Felder wie FX-Block, external_reference, custom_metadata und tax_code, und tragen reverses_intent_id auf den stornierten Intent.

Für das Buchungsdatum gibt es zwei Modi:

ModusREST posting_modeMCP posting_modeWirkung
Aktuelle Periodecurrent_period oder weglassencurrent_period oder weglassenStorno wird mit heutigem Datum in der aktuellen offenen Periode gebucht. Das ist der Default für API und MCP, damit bestehende Integrationen stabil bleiben.
Ursprungsperiodeoriginal_periodoriginal_periodStorno wird auf das Buchungsdatum der Originalbuchung gesetzt. Das ist für Jahresabschluss- oder Periodenkorrekturen sinnvoll, solange die Ursprungsperiode noch offen ist.

original_period ist ein expliziter Korrekturmodus. LedgerLou prüft vor dem Schreiben, ob die Zielperiode offen ist. Ist sie soft-locked oder hard-locked, wird die Stornierung mit PERIOD_LOCKED abgelehnt. Dann muss die Periode bewusst wieder geöffnet werden oder die Korrektur bleibt in der aktuellen Periode.

Bei bereits abgeglichenen Intents kehrt LedgerLou zuerst abhängige Settlement-Intents um und löst die Bankverknüpfung. Gruppierte Bankabgleiche bleiben geschützt: Wenn ein Settlement noch andere aktive Intents ausgleicht, muss zuerst die Gruppenzuordnung aufgehoben werden.

curl -X POST https://api.ledgerlou.de/v1/journal/reverse \
  -H "Authorization: Bearer $LEDGERLOU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "intent_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "reason": "Falsche Kontierung",
    "posting_mode": "original_period"
  }'

Für MCP gilt dasselbe.

{
  "intent_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "reason": "Falsche Kontierung",
  "posting_mode": "original_period"
}

Metadaten & Externe Referenzen

Jede Buchung kann optional zwei Intent-Level-Felder mitgeben, die den Vorgang mit externen Systemen verknüpfen oder zusätzlichen Kontext liefern:

external_referenceFreitext-ID zum Verknüpfen mit externen Systemen — z. B. Rechnungsnummer, Stripe-ID oder ERP-Referenz. Max. 500 Zeichen.
custom_metadataFlaches Key-Value-Objekt für beliebigen Client-Kontext — z. B. Kostenstelle, Projekt, Tags. Max. 20 Schlüssel, 4 KB serialisiert.
Eigenschaftexternal_referencecustom_metadata
Typstring (max. 500 Zeichen)Flaches JSON-Objekt (string | number | boolean | null als Werte)
PflichtNeinNein
UnveränderlichJa (GoBD)Ja (GoBD)
Im Audit-HashJaJa (deterministische Sortierung)
FilterbarGET /v1/journal?externalReference=...
Storno-VerhaltenWird identisch vom Original übernommenWird identisch vom Original übernommen

Typische Anwendungsfälle:

  • Rechnungsnummer als Referenzexternal_reference: "RE-2025-0042" verknüpft die Buchung mit der Rechnung im ERP. Per ?externalReference=RE-2025-0042 ist der zugehörige Journal-Eintrag sofort auffindbar.
  • Kostenstelle und Projektcustom_metadata: { "cost_center": "CC-100", "project": "alpha" } ordnet die Buchung organisatorisch zu, ohne das Kontenrahmenmodell anpassen zu müssen.
  • Herkunfts-Tags für Automatisierungencustom_metadata: { "source_system": "shopify", "order_id": "ORD-9981" } gibt MCP-Agents und ETL-Pipelines einen strukturierten Rückkanal.

Fremdwährungsbuchungen

LedgerLou führt die Bücher in EUR. Buchungen in Fremdwährung (z. B. USD, GBP, CHF) werden nativ im EUR-Betrag gebucht und tragen zusätzlich einen FX-Block mit den Originaldaten:

FeldBedeutung
currencyISO 4217 Währungscode (z. B. USD)
foreign_amountBrutto-Betrag in Fremdwährung
rateUmrechnungskurs Fremdwährung → EUR (ECB-Konvention)
rate_dateStichtag des Kurses
rate_sourceQuelle (z. B. ECB, manual, bank)

Wichtige Regeln:

  • Der Aufrufer gibt den Kurs explizit an — LedgerLou ruft keine externen Kursquellen ab.
  • Der EUR-Betrag in lines muss zum FX-Block passen: foreign_amount × rate ≈ Summe der Soll-Beträge (Toleranz: max. 1 Cent oder 0,01 %).
  • Bei Split-Buchungen wird der Fremdwährungsbetrag proportional auf die Zeilen verteilt (Largest-Remainder-Verfahren, 4 Dezimalstellen).
  • Stornobuchungen übernehmen den FX-Block identisch aus dem Original — es wird kein neuer Kurs berechnet.
  • EUR-Buchungen setzen keinen FX-Block (fx: null oder Feld weglassen).
  • Eröffnungsbilanzwerte (POST /v1/bookings/opening-balances) unterstützen kein FX.

Workflow

1
Sachverhalt buchenVia REST API oder MCP. Einfache Buchung oder Split mit mehreren Positionen. Optional direkter Belegupload in einem Request.
2
Buchung landet im JournalNach Bestätigung wird die Buchung unveränderlich ins Hauptbuch geschrieben — mit Intent-ID, Zeitstempel und SHA256-Hash.
3
Journal prüfenDas Journal ist filterbar nach Konto, Zeitraum und Suchbegriff. Jeder Intent zeigt alle zugehörigen Buchungszeilen und verknüpfte Intents.
4
Fehler korrigieren via StornoFalsche Buchungen werden durch POST /v1/journal/reverse auf Intent-Ebene storniert. Standardmäßig entsteht ein neuer Storno-Intent in der aktuellen offenen Periode; mit posting_mode: “original_period” kann eine offene Ursprungsperiode korrigiert werden. Kein stilles Überschreiben — jede Korrektur ist im Audit-Trail sichtbar.

Zugangswege

Dashboard (UI)Journal durchsuchen, Buchungsdetails einsehen und Stornos auslösen.
REST APIBuchungen programmatisch erstellen und das Journal abfragen — z. B. für Integrationen, ETL-Pipelines oder automatisierte Monatsabschlüsse.
MCPMCP Agents klassifizieren Sachverhalte, erstellen Buchungsvorschläge und schreiben nach Bestätigung ins Journal.

Scopes

journal:readjournal:write