Nordlet

← Blog

Vorab-Testplan für eine Buchhaltungs-API

Ein Zuverlässigkeits-Leitfaden für Entwicklungsteams: doppelte Schreibvorgänge, Idempotenz-Wiederverwendung, Webhook-Signaturen, ungeordnete Ereignisse, Dezimalbeträge, Scopes, Periodensperren und Wiederherstellung.

Nordlet Team · · 16 Min. Lesezeit

Ein 201 Created von einer Buchhaltungs-API besagt fast gar nichts. Es bestätigt lediglich, dass der Server geantwortet hat. Es bestätigt jedoch nicht, dass genau eine Rechnung existiert, dass Soll und Haben übereinstimmen, dass die Belegnummer genau einmal vergeben wurde oder dass ein erneuter Versuch nach einem Verbindungsabbruch nicht versehentlich eine zweite Kopie bucht. Die meisten Duplikate in der Produktionsumgebung von Buchhaltungssystemen entstehen genau durch diese Lücke: eine Mutation, die auf dem Server erfolgreich war, während der Client mit einem unbekannten Ergebnis dastand und im Hintergrund stillschweigend einen erneuten Versuch mit einem frischen Schlüssel unternahm.

Dieser Plan richtet sich an Teams, die eine Buchhaltungs-API evaluieren, bevor sie diese in echte Bücher integrieren. Der Schwerpunkt liegt auf dem Fehlerverhalten, nicht auf dem Idealfall (Happy Path). Jeder der nachfolgenden Bereiche beschreibt, was getestet, was zugesichert und wann ein Test als bestanden gewertet wird. Der Implementierungskontext ist hier Nordlet, dessen API mit bereichsbeschränkten Bearer-Token (scoped bearer keys), Dezimalstring-Beträgen, Idempotenzschlüsseln und signierten Webhooks arbeitet. Für die genaue Endpunktsyntax und Antwortstrukturen lesen Sie die Seiten API-Konventionen und Erste Schritte, anstatt sich auf Annahmen zu verlassen.

Was „Bestanden“ tatsächlich bedeutet

Ein Test beweist erst dann, dass eine Buchhaltungsintegration sicher ist, wenn er die Semantik überprüft und nicht nur die Statuscodes. Für jedes Szenario sollte die Testsuite Folgendes bestätigen:

  • Geschäftlicher Nebeneffekt: Es existiert exakt ein Kunde, eine Rechnung, ein Buchungssatz, eine Nummernzuteilung oder ein Zahlungsübergang.
  • Buchhalterische Integrität: Soll entspricht Haben, und die monetäre Genauigkeit bleibt bei der Serialisierung erhalten.
  • Wiederholungsverhalten: Ein erneuter Versuch liefert das ursprüngliche Ergebnis anstelle eines neuen Datensatzes.
  • Dauerhaftigkeit: Audit-Einträge und Webhook-Ereignisse sind vorhanden, sobald die Operation festgeschrieben (committed) ist.
  • Fehler ohne Nebeneffekte: Abgelehnte Anfragen verbrauchen keine Belegnummern und schreiben keine partiellen Buchungszeilen.
  • Wiederherstellung: Ein vorübergehender Fehler kann ohne Duplizierung oder dauerhaften Verlust erneut versucht werden.

Die API-Richtlinien von Google ziehen hier eine klare Grenze: Nur Operationen, deren wiederholte Ausführung denselben Endzustand hinterlässt, können sicher wiederholt werden. Zudem sollte eine API kennzeichnen, welche Operationen idempotent sind, anstatt jeden Fehler blind zu wiederholen.

Einrichtung einer eigenständigen, beobachtbaren Umgebung

Verwenden Sie ein Testmandant (sandbox company) und keine echten Bücher. Ein Nordlet-Testmandant nutzt dieselben Module und das gleiche API-Verhalten wie ein echtes Unternehmen, ist jedoch als Testdaten gekennzeichnet, weshalb er sich sicher für hochvolumige Duplikats- und Fehlertests eignet. Dieses Kennzeichen ist nach der Erstellung unveränderlich, sodass echte Bücher später nicht mehr als Testdaten deklariert werden können. Beachten Sie, dass die Nutzung der Sandbox genau wie die Nutzung in einem echten Unternehmen gemessen und abgerechnet wird. Bemessen Sie Ihre Volumentests daher anhand Ihres Preismodells.

Bereiten Sie vor dem Schreiben von Tests Folgendes vor:

  • Ein dediziertes Testmandant mit isSandbox: true.
  • Einen Test-API-Schlüssel, der ausschließlich auf die zu testenden Module beschränkt ist.
  • Einen Webhook-Endpunkt oder einen lokalen Tunnel, der den rohen Anfragekörper (raw request body) beibehält.
  • Vorkonfigurierte Kunden, Lieferanten und einen bekannten Kontenrahmen.
  • Mindestens zwei Abrechnungsperioden: eine geöffnete und eine gesperrte.
  • Eine Testuhr oder ein Datumsfixture, falls die Implementierung dies unterstützt.
  • Einen lokalen Speicher, der jeden Anfrageversuch, Idempotenzschlüssel, Antwort-Hash, die Webhook-Zustellung und jedes Abstimmergebnis (reconciliation result) protokolliert.

Führen Sie keine Duplikattests mit gemeinsam genutzten Staging-Daten durch. Ein verirrter Kunde oder eine verirrte Rechnung aus einem früheren Testlauf macht spätere Zusicherungen unklar.

Ihr Fixture für jede Mutation sollte die Methode, den Endpunkt, den vollständigen Body, den Idempotenzschlüssel, den Schlüsselbereich (key scope), eine Client-Korrelations-ID, Start- und Endzeitstempel, den Antwortstatus, Header, Body, die Anforderungs-ID (request ID) sowie die Information erfassen, ob die Verbindung vor dem Eintreffen der Antwort abbrach. Verwenden Sie feste Dezimalstrings wie "75.0000" für Geldbeträge. Nordlet bildet Geldwerte als Dezimalstrings mit bis zu vier Nachkommastellen ab, und das Beispiel für Rechnungen verwendet dieses Format.

Die andere Hälfte der Einrichtung besteht aus dem Injizieren von Fehlern. Ihr Test-Harness sollte in der Lage sein, eine Antwort zu verzögern, eine TCP-Verbindung zu trennen, nachdem der Server die Anfrage erhalten hat, synthetische 429/500/502/503/504-Antworten zurückzugeben, einen Nicht-2xx-Status vom Webhook-Empfänger zu senden, denselben Webhook zweimal zuzustellen, Ereignisse umzuordnen, ein einzelnes Byte eines Webhook-Bodys zu beschädigen, die Nutzlast eines Idempotenzschlüssels bei gleicher Schlüsselbeibehaltung zu verändern, zwei identische Anfragen gleichzeitig auszuführen und eine Periode zwischen der Einrichtung und der Buchung zu sperren. Diese Szenarien sind mehr wert als hundert Happy-Path-Beispiele.

Sperren des Vertrags vor dem Schreiben der Wiederholungslogik

Generieren oder rufen Sie das OpenAPI-Schema ab und gleichen Sie es mit Ihrem Client ab. Nordlet veröffentlicht seine OpenAPI-Spezifikation in der API-Referenz und generiert seine typisierten SDKs aus genau derselben Spezifikation, weshalb schemagestützte Tests handgeschriebenen Annahmen überlegen sind.

Überprüfen Sie Pflichtfelder und Typen, Dezimalstring-Felder, Datums- und Zeitstempelformate, erlaubte Aktionen und Bereiche, die Struktur des Fehler-Envelopes, Webhook-Ereignisschemas, welche Mutationen einen Idempotenzschlüssel akzeptieren und welche Antwortfelder das erstellte Objekt identifizieren.

Bestehenskriterien. Der Client lehnt ungültige Payloads lokal ab, sofern das Schema dies vorsieht. Die Antworten des Server stimmen mit dem dokumentierten Schema überein. Ungültige Dezimalzahlen, falsche Daten und fehlende Pflichtfelder führen zu strukturierten Validierungsfehlern. Für deterministische Validierungsfehler wird kein Wiederholungsversuch unternommen.

Zu erkennendes Fehlerbild. Ein Client parst "121.0000" in eine Gleitkommazahl im Binärformat (binary float) und serialisiert später einen leicht abweichenden Betrag. Ganze Zahlen funktionieren; Mehrwertsteuerzeilen und Bruchteilmengen schlagen fehl. Testen Sie Geldbeträge durchgehend als Strings.

Autorisierung und Mandantenisolation

Verwenden Sie getrennte Schlüssel für Lese- und Schreibvorgänge. Testen Sie anschließend die gesamte Matrix: fehlender Schlüssel, ungültiger Schlüssel, gültiger Schlüssel mit unzureichendem Modul-Scope, gültiger Schlüssel mit dem richtigen Scope, ein Schlüssel, der zu einem anderen Unternehmen gehört, sowie der Versuch, ein Objekt aus einem anderen Unternehmen zu lesen.

Zusicherungen:

  • Fehlende oder ungültige Anmeldeinformationen geben 401 zurück.
  • Ein gültiger Schlüssel ohne die erforderliche Berechtigung gibt 403 zurück.
  • Bei keinem der beiden Fehler wird ein buchhalterischer Nebeneffekt erzeugt.
  • Eine erfolgreiche Anfrage kann die Datensätze eines anderen Unternehmens weder lesen noch verändern.
  • Sicherheitsfehler werden niemals automatisch wiederholt.

Bestehenskriterium. Sie können sowohl die Korrektheit der Autorisierung als auch die Mandantenisolation durch anschließende Lesevorgänge nachweisen, nicht nur anhand von Statuscodes.

Nachweis einer sauberen Transaktion

Führen Sie einen kleinen, deterministischen Ablauf aus: Erstellen oder finden Sie einen Testkunden, erstellen Sie eine Rechnung mit Dezimalstring-Beträgen, geben Sie diese frei, lesen Sie die Rechnung und deren buchhalterische Auswirkungen, lesen Sie den Auditeintrag und empfangen Sie den Webhook. Das „Erste Schritte“-Beispiel von Nordlet zeigt, dass bei der Rechnungsausstellung lückenlos eine Nummer vergeben, die Offenheit der Periode überprüft und in derselben Transaktion ein ausgeglichener Buchungssatz erzeugt wird.

Stellen Sie sicher, dass die Rechnung den erwarteten Zustand erreicht, die Belegnummer exakt einmal vergeben wird, Soll und Haben übereinstimmen, MwSt. und Zeilensummen der erwarteten kaufmännischen Rundung entsprechen, der Auditeintrag den Akteur und die Änderung benennt, der Webhook schließlich zugestellt wird und die API-Antwort sowie ein anschließender Lesevorgang hinsichtlich Rechnungs-ID und Status übereinstimmen.

Ein wichtiger Unterschied, den man im Auge behalten sollte: Das Eintreffen eines Webhooks ist kein Beweis dafür, dass die Mutation erfolgreich festgeschrieben wurde. Die API-Antwort zusammen mit einem erneuten Lesevorgang bilden Ihre primären Transaktionszusicherungen. Der Webhook beweist lediglich die nachgelagerte Benachrichtigung und wird separat getestet.

Idempotenz: Gleicher Schlüssel, gleicher Body

Generieren Sie einen Schlüssel pro logischer Geschäftseroperation, nicht einen Schlüssel pro Netzwerkversuch. Senden Sie die Mutation mit dem Schlüssel K und dem Body B, speichern Sie die erstellte ID und senden Sie danach exakt dieselbe Anfrage erneut.

Stellen Sie sicher, dass die zweite Antwort dieselbe Operation repräsentiert, die Objekt-ID identisch ist und genau ein Geschäftsobjekt, ein Buchungssatz, eine Belegnummer und ein finanzieller Effekt existieren. Die wiederholte Antwort sollte den dokumentierten Wiederholungs-Header enthalten – im Fall von Nordlet x-idempotent-replay: true –, und das Audit-Protokoll darf keine zweite Mutation aufweisen.

Zwei Speicherregeln verändern, was Ihre Wiederholungsschleife (retry loop) erwarten sollte, weshalb Sie diese direkt testen sollten: Ein gespeicherter 4xx-Fehler wird wie jede andere Antwort wiederholt, während ein 5xx-Fehler überhaupt nicht gespeichert wird. Ein erneuter Versuch nach einem Serverfehler führt die Operation daher erneut aus, anstatt sie zu wiederholen. Schlüssel laufen zudem ab (bei Nordlet nach 24 Stunden), was den Zeitraum einschränkt, in dem eine Wiederholung verfügbar ist.

Die Dokumentation von Nordlet verspricht, dass das Hinzufügen eines Idempotency-Key-Headers verhindert, dass eine wiederholte Anfrage ein Duplikat erstellt, und die API-Konventionen definieren den exakten Wiederholungs-Header und die Anforderung einer byte-genauen Antwort. Dieses Prinzip entspricht dem veröffentlichten Modell von Stripe: Ein Schlüssel identifiziert die logische Operation, Wiederholungen geben das gespeicherte Ergebnis zurück, und ein mit anderen Parametern wiederverwendeter Schlüssel wird abgelehnt, anstatt stillschweigend geändert zu werden.

Bestehenskriterium. Es existiert genau ein finanzieller Zustandsübergang, unabhängig davon, wie oft der Client innerhalb des Wiederholungsfensters dieselbe Anfrage sendet.

Idempotenz: Gleicher Schlüssel, geänderter Body

Senden Sie die ursprüngliche Anfrage mit dem Schlüssel K und dem Body B1, gefolgt von einer zweiten Anfrage mit dem Schlüssel K und dem Body B2, bei der sich mindestens ein Betrag, Kunde, Datum oder eine Zeile unterscheidet.

Erwartetes Ergebnis: Die Anfrage wird mit dem dokumentierten Fehler bei Schlüsselwiederverwendung abgelehnt – Nordlet gibt 422 idempotency_key_reuse zurück –, der ursprüngliche Datensatz bleibt unberührt, es erscheint kein zweiter Datensatz, keine Nummer und keine Audit-Änderung, und der Client „repariert“ dies nicht durch Generierung eines neuen Schlüssels. Das stillschweigende Akzeptieren von B2 würde Wiederholungsschlüssel unsicher machen.

Gleichzeitige doppelte Anfragen (Concurrent Duplicates)

Setzen Sie zwei identische Anfragen mit demselben Schlüssel im selben Moment ab. Abhängig vom dokumentierten Verhalten wird eine ausgeführt, während die andere einen Konflikt wegen laufender Verarbeitung erhält – Nordlet gibt 409 idempotency_in_progress zurück –, oder beide beobachten schlussendlich dasselbe Ergebnis.

Stellen Sie sicher, dass beide Aufrufe nicht unabhängig voneinander finanzielle Effekte erzeugen können, höchstens eine Belegnummer vergeben wird, ein temporärer Konflikt mit demselben Schlüssel anstelle eines neuen wiederholt wird, die finale Ressource vollständig und lesbar ist und der Idempotenzdatensatz nicht dauerhaft blockiert bleibt.

Fehlerbild. Eine Wiederholungsbibliothek, die pro Versuch eine frische UUID generiert, macht aus einer logischen Operation mehrere unabhängige Schreibvorgänge und untergräbt die Idempotenz vollständig.

Das ungewisse Ergebnis nach einem Verbindungsabbruch

Dies ist die wichtigste Simulation für die Produktionsumgebung überhaupt. Senden Sie eine Mutation mit dem Schlüssel K, lassen Sie sie vom Server verarbeiten, trennen Sie die Verbindung, bevor die Antwort eintrifft, protokollieren Sie das Ergebnis als unbekannt, versuchen Sie es dann erneut mit demselben Schlüssel K und gleichen Sie das Ergebnis ab, indem Sie die Ressource und die Audit-Daten lesen.

Stellen Sie sicher, dass der erneute Versuch die ursprüngliche oder die dokumentierte Wiederholungsantwort liefert, genau ein finanzieller Nebeneffekt existiert, der Client die Operation erst nach einer erfolgreichen Wiederholung oder einem Abgleichslesevorgang als abgeschlossen markiert und kein neuer Schlüssel generiert wird. Ein Timeout bedeutet nicht, dass „nichts passiert ist“. Stripe beschreibt Idempotenz präzise als Schutz vor Verbindungsfehlern, bei denen der Server eine Mutation bereits verarbeitet haben könnte, bevor der Client die Antwort empfangen konnte.

Eine konservative Wiederholungsrichtlinie

Entscheidungen über Wiederholungen hängen sowohl vom Fehler ab als auch davon, ob die Operation idempotent ist, und nicht allein von der HTTP-Methode.

Normalerweise wiederholbar, Beibehaltung desselben Schlüssels: Verbindungsabbruch oder Timeout nach einer idempotenten Mutation, 408, 429 nach Berücksichtigung von retry-after sowie 502/503/504. Eine dokumentierte Antwort zur laufenden Idempotenz kann nach einer kurzen Verzögerung wiederholt werden.

Nicht wiederholbar ohne Abgleich: Validierungsfehler vom Typ 400/422, Authentifizierungsfehler vom Typ 401/403, 404 für eine fehlende Ressource, geschäftliche 409-Konflikte, die nicht im Zusammenhang mit einem laufenden Schlüssel stehen, eine veränderte Nutzlast bei einem bestehenden Schlüssel sowie Ablehnungen aufgrund von Periodensperren.

Stellen Sie sicher, dass ein begrenzter exponentieller Backoff mit Jitter (Zufallsstreuung) verwendet wird, maximale Versuche und verstrichene Zeiten explizit festgelegt sind, retry-after bei Ratenbegrenzungen eingehalten wird, derselbe Schlüssel über Wiederholungen hinweg beibehalten wird, für jede neue Operation ein neuer Schlüssel verwendet wird und Protokolle den ursprünglichen Versuch von Wiederholungen trennen.

Testen Sie die Ratenbegrenzung separat. Überschreiten Sie die dokumentierte Schwelle – Nordlet erlaubt standardmäßig 300 Anfragen pro Minute und API-Schlüssel, wobei einige nicht authentifizierte Endpunkte niedrigere Limits pro Adresse haben –, und bestätigen Sie, dass der Server eine Antwort zur Ratenbegrenzung zurückgibt, der Client retry-after als Verzögerung und nicht als Fehler interpretiert, er pausiert anstatt Hämmern auszulösen, und ein erneuter Versuch der gedrosselten Mutation den ursprünglichen Schlüssel wiederverwendet. Die x-ratelimit-*-Header melden das verbleibende Budget, was gute Vorab-Prüfungen ermöglicht. Halten Sie Ratenbegrenzungstests von Finanzprüfungen fern, es sei denn, Ihr Test-Fixture kann einen gedrosselten Versuch von einem festgeschriebenen unterscheiden.

Überprüfung von Webhook-Signaturen

Erstellen Sie einen Empfänger, der die Rohbytes (raw bytes) beibehält. Erfassen Sie für jedes Ereignis den rohen Body, lesen Sie den Header x-nordlet-signature, berechnen Sie das erwartete HMAC-SHA256 mit dem Abonnement-Geheimnis (subscription secret), vergleichen Sie es mit einer Timing-resistenten Funktion (constant-time function), parsen Sie JSON erst nach der Verifizierung, protokollieren Sie die Zustellung und geben Sie nach dauerhafter Annahme ein schnelles 2xx zurück. Nordlet signiert einen HMAC über den rohen Body, sendet ihn als sha256=<hex> und versucht Zustellungen bei Fehlschlägen mit exponentiellem Backoff erneut. Die Webhook-Richtlinien von Stripe bekräftigen, dass der unmodifizierte rohe Body mittels eines zeitkonstanten Vergleichs überprüft werden muss.

Führen Sie negative Tests durch: korrekter Body und korrektes Geheimnis, korrekter Body mit falschem Geheimnis, ein um ein Byte veränderter Body, neu serialisiertes JSON mit veränderten Leerzeichen, ein fehlender Header, eine fehlerhafte Signatur, eine wiederholte alte Zustellung (sofern das Schema einen Zeitstempel enthält) sowie eine gültige Signatur, die an das falsche Abonnement zugestellt wird.

Bestehenskriterien. Nur der korrekte rohe Body und das korrekte Geheimnis werden akzeptiert. Ungültige Signaturen erhalten einen Nicht-2xx-Status. Ungültige Payloads gelangen niemals in die Buchhaltungswarteschlange. Geheimnisse verbleiben nicht in gewöhnlichen Protokollen. Der Handler bestätigt den Empfang erst, nachdem das Ereignis dauerhaft aufgezeichnet wurde.

Doppelte und ungeordnete Webhooks

Die Zustellungszuverlässigkeit ist ein anderes Problem als die API-Idempotenz, und der Empfänger muss ebenfalls idempotent arbeiten. Stellen Sie dasselbe Ereignis zweimal zu, liefern Sie ein sale_invoice.paid-Ereignis vor einem sale_invoice.issued-Ereignis aus, geben Sie nach der Persistenz, aber vor der Antwort einen 500-Fehler zurück und wiederholen Sie ein Ereignis, das der Verbraucher bereits verarbeitet hat.

Stellen Sie sicher, dass doppelte Zustellungen weder Zahlungen, Statusänderungen noch Buchungsaktionen duplizieren, dass der Deduplizierungsschlüssel die Zustellungs- oder Ereignis-ID des Anbieters verwendet, sofern eine solche existiert (oder einen dokumentierten zusammengesetzten Schlüssel, niemals einen beliebigen Zeitstempel), dass ungeordnete Ereignisse niemals neueren Zustand mit älterem überschreiben, dass der Verbraucher den aktuellen Zustand über die API abrufen kann, wenn die Reihenfolge nicht ausreicht, und dass fehlgeschlagene Verbrauchsversuche über eine Warteschlange oder einen Dead-Letter-Pfad geleitet werden. Stripe warnt ausdrücklich davor, dass die Zustellungsreihenfolge nicht garantiert ist, und empfiehlt die Speicherung verarbeiteter Ereignis-IDs.

Halten Sie den Endpunkt schlank: Validierung der Struktur, Überprüfung der Signatur, Persistenz oder Einreihung in die Warteschlange, Bestätigung, Rückgabe von 2xx. Abgleich und Benachrichtigungen gehören in die asynchrone Verarbeitung. Testen Sie dies, indem Sie die nachgelagerte Arbeit über das Zustellungs-Timeout hinaus schlafen legen; ein korrekter Empfänger bestätigt den Empfang dennoch nach dem dauerhaften Einreihen in die Warteschlange.

Offene und gesperrte Buchungsperioden

Nordlet erzwingt Periodensperren zum Buchungszeitpunkt über manuelle Buchungen, Belegflüsse und Importe hinweg, testen Sie diese Kontrolle daher an mehreren Stellen. Erstellen Sie äquivalente Belege mit Datum in einer offenen Periode, in einer gesperrten Periode, an der Grenze kurz vor der Sperrung, am ersten Tag der nächsten offenen Periode sowie mit einem gültigen Belegdatum, aber ungültigem Buchungsdatum, falls die API beides trennt.

Stellen Sie für den Fall einer gesperrten Periode sicher, dass die Anfrage mit dem dokumentierten Periodensperr-Fehler abgelehnt wird – einem 409 Conflict bei Nordlet –, dass keine Buchungszeilen geschrieben werden, keine Belegnummer verbraucht wird, kein Beleg in den Status „gebucht“ übergeht und kein Erfolgs-Webhook ausgelöst wird. Die Variante mit offener Periode sollte mit denselben finanziellen Werten erfolgreich sein.

Race-Test. Starten Sie eine Buchung für eine offene Periode, sperren Sie die Periode mitten während der Anfrage und stellen Sie sicher, dass die Transaktionsfestschreibung (commit) die Sperre nicht umgehen kann. Die entscheidende Bedingung für das Bestehen: Eine festgeschriebene Buchung darf niemals in einer Periode landen, die vor der Festschreibung der Transaktion gesperrt wurde.

Prüfbarkeit (Auditability) und Abgleich

Bestätigen Sie für jede erfolgreiche Mutation, dass das Geschäftsobjekt existiert, der Buchungssatz mit ausgeglichenem Soll und Haben vorhanden ist, der Auditeintrag existiert, das Webhook-Ereignis vorhanden oder abrufbar ist und Ihr Operationsdatensatz auf die Anbieter-Objekt-ID verweist, wobei Wiederholungen auf dieselbe logische Operation verweisen.

Stellen Sie für jede abgelehnte Mutation sicher, dass kein partieller Beleg existiert, keine Nummer verbraucht wurde (sofern der Vertrag keine Reservierung vorsieht), kein Ledger-Eintrag existiert, kein Erfolgs-Webhook existiert und der Fehler zur Diagnose eine Anforderungs-ID (request ID) enthält. Die Konventionen von Nordlet beschreiben die Überprüfbarkeit von Mutationen und ausgeglichene Buchungssätze als Plattformgarantien, wobei der Saldierungsausgleich durch einen verzögerten Datenbank-Trigger zum Commit-Zeitpunkt und nicht nur durch den Anwendungscode erzwungen wird. Machen Sie aus diesen Garantien nachgelagerte Abgleichs-Abfragen, anstatt der HTTP-Antwort blind zu vertrauen.

Zentrale Testmatrix

Bereich Testaktion Erwartete Zusicherung Bestehenskriterium
Authentifizierung Kein Schlüssel, ungültiger Schlüssel, unzureichender Scope Strukturierter 401/403; kein Nebeneffekt Alle abgelehnten Versuche erzeugen keinen Buchungsdatensatz
Schema und Beträge Ungültige Dezimalzahl, ungültiges Datum, Pflichtfeld fehlt Feldbezogener Validierungsfehler Es erfolgt kein erneuter Versuch oder partieller Schreibvorgang
Normale Buchung Erstellen und Ausstellen einer Rechnung in einer offenen Periode Ein Beleg, ein ausgeglichener Buchungssatz, ein Auditeintrag Ausgelesener Zustand und Buchhaltung stimmen überein
Wiederholung mit gleicher ID Wiederholen derselben Mutation, gleicher Schlüssel und Body Ursprüngliches Ergebnis wiederholt; kein Duplikat Objekt-ID, Nummer, Buchungseffekt und Audit bleiben einmalig
Geänderter Body, gleicher Schlüssel Wiederverwendung des Schlüssels mit anderem Betrag Dokumentierte Ablehnung wegen Schlüsselwiederverwendung Ursprünglicher Datensatz unverändert; nichts Neues geschrieben
Verbindungsabbruch Festschreiben, Abbruch, erneuter Versuch mit gleichem Schlüssel Wiederholtes Ergebnis Exakt ein finanzieller Nebeneffekt
Gesperrte Periode Buchen eines Belegs mit Datum in einer gesperrten Periode Ablehnung wegen Periodensperre Kein Buchungssatz, keine Nummer, kein Erfolgs-Webhook
Webhook-Signatur Falsches Geheimnis, veränderter Body Nicht-2xx vom Empfänger Nur korrekter roher Body und Geheimnis werden akzeptiert

Womit ich als Erstes beginnen würde

Wenn die Zeit knapp ist, führen Sie die Tests in der Reihenfolge aus, die die teuersten Fehler aufdeckt. Beginnen Sie mit der Wiederholung nach Verbindungsabbruch, da dieses einzelne Szenario die meisten echten Duplikate verursacht. Danach das Idempotenz-Paar aus gleichem Schlüssel und geändertem Body. Folgen Sie mit den gesperrten Perioden, da eine Buchung in einem geschlossenen Monat ein Buchungsproblem darstellt, das erst spät zutage tritt. Signaturüberprüfung und ungeordnete Webhooks folgen als Nächstes, und die vollständige Schema- und Autorisierungsmatrix kann kontinuierlich in der CI laufen, sobald sich der Client stabilisiert hat.

Alles andere in diesem Plan unterstützt diese fünf Punkte. Bringen Sie diese für ein Testmandant (sandbox company) zum Laufen, wobei Abgleichslesevorgänge die Nebeneffekte bestätigen, und Sie wissen, dass die Integration sicher ist, bevor sie auch nur ein einziges echtes Hauptbuch berührt. Sie können in wenigen Minuten über Erste Schritte ein Testmandant und einen bereichsbeschränkten Testschlüssel erstellen und anhand der Funktionen-Liste überprüfen, welche Module Sie benötigen.

FAQ

Reicht eine 2xx-Antwort aus, um zu bestätigen, dass ein Buchungsschreibvorgang erfolgreich war?

Nein. Ein Statuscode bestätigt lediglich, dass der Server geantwortet hat, nicht jedoch, dass exakt ein Beleg, eine Nummernzuteilung und ein ausgeglichener Buchungssatz existieren. Jeder Mutationstest sollte der Antwort einen Lesevorgang des objekts, dessen buchhalterischem Effekt und dessen Auditeintrag folgen lassen. Der gefährliche Fall ist die umgekehrte Richtung: eine Operation, die erfolgreich war, während der Client niemals eine Antwort erhalten hat.

Sollte ich einen neuen Idempotenzschlüssel generieren, wenn eine Anfrage ein Timeout verursacht?

Nein, und genau das ist der Fehler, der die meisten Duplikate in Produktionsumgebungen verursacht. Der Schlüssel identifiziert die logische Geschäftseroperation und nicht den Netzwerkversuch. Wiederholen Sie denselben Schlüssel und gleichen Sie das Ergebnis anschließend durch Lesen der Ressource ab. Eine Wiederholungsbibliothek, die pro Versuch eine frische UUID generiert, macht aus einer beabsichtigten Rechnung mehrere unabhängige Schreibvorgänge.

Was passiert, wenn ich einen Idempotenzschlüssel mit einer anderen Nutzlast (Payload) wiederverwende?

Eine korrekte API lehnt diesen ab, anstatt den neuen Body stillschweigend anzuwenden. Nordlet gibt 422 idempotency_key_reuse zurück und belässt den ursprünglichen Datensatz unberührt. Ihr Client sollte dies als Programmierfehler betrachten, der behoben werden muss, und nicht als Zustand, den man durch Generierung eines neuen Schlüssels umgehen sollte.

Sind Webhooks ein Ersatz für das Auslesen des erstellten Objekts?

Nein. Die Webhook-Zustellung beweist eine nachgelagerte Benachrichtigung, jedoch nicht, dass die Transaktion wie erwartet festgeschrieben wurde, und die Zustellungsreihenfolge ist nicht garantiert. Überprüfen Sie die Signatur über den rohen Body, deduplizieren Sie anhand der Zustellungs- oder Ereignis-ID und rufen Sie den aktuellen Zustand über die API ab, wann immer die Ereignisreihenfolge allein nicht ausreicht, um zu entscheiden, was sich geändert hat.

Wie teste ich das Buchen in eine gesperrte Buchungsperiode?

Erstellen Sie äquivalente Belege in einer offenen und in einer gesperrten Periode und stellen Sie sicher, dass der gesperrte Fall ohne Buchungszeilen, ohne verbrauchte Belegnummer, ohne Statusübergang und ohne Erfolgs-Webhook abgelehnt wird. Führen Sie danach das Race-Szenario aus: Starten Sie eine Buchung für eine offene Periode und sperren Sie die Periode mitten in der Anfrage. Eine festgeschriebene Buchung darf niemals in einer Periode landen, die vor dem Commit der Transaktion gesperrt wurde.

Kann ich hochvolumige Duplikattests in einem Testmandanten ausführen?

Ja. Ein Testmandant verhält sich wie ein echtes Unternehmen, ist als Testdaten gekennzeichnet und wird sofort anstatt erst nach Ablauf der Aufbewahrungsfrist gelöscht. Daher ist er der richtige Ort für destruktive Tests und Duplikattests. Die Nutzung der Sandbox wird dennoch wie eine echte Nutzung gemessen und abgerechnet. Planen Sie das Volumen daher sorgfältig, anstatt endlose Schleifen auszuführen.