KSeF-UPO-API: Statusabfragen und belastbare Nachweise

So entwickeln Sie einen zuverlässigen KSeF-UPO-API-Ablauf: Status abfragen, endgültige Fehler behandeln, UPO-XML prüfen und belastbare Annahmenachweise archivieren.

Ernest Bursa

Ernest Bursa

Founder · · 13 Min. Lesezeit
Polish software engineer in a Warsaw office reviewing a green 200 invoice status and verified XML receipt beside an archive box

Um eine KSeF-UPO sicher abzurufen, speichern Sie die vom Sendeaufruf zurückgegebene Rechnungsreferenz. Fragen Sie anschließend den Rechnungsstatus ab, bis er einen endgültigen Zustand erreicht, und akzeptieren Sie ausschließlich Status 200 zusammen mit einer KSeF-Nummer. Laden Sie dann das UPO-XML herunter, prüfen Sie den Antwort-Hash, das Schema und die XAdES-Signatur und archivieren Sie exakt die empfangenen Bytes. Weder eine erfolgreiche Antwort auf den Sendeaufruf noch eine ablaufende UPO-URL beweisen, dass KSeF die Rechnung angenommen hat.

Was beweist die Annahme einer Rechnung durch KSeF?

Die Annahme setzt das abgeschlossene asynchrone Ergebnis voraus, nicht nur eine erfolgreiche HTTP-Übermittlung. Der Sendeaufruf gibt eine Rechnungs-referenceNumber zurück und stößt die Prüfung an. Er weist weder die endgültige KSeF-Nummer zu noch beweist er, dass das Dokument die KSeF-Prüfungen bestanden hat.

Diese Unterscheidung ist die Grundlage einer zuverlässigen Integration. Ihre Anwendung kann eine ordnungsgemäße Antwort vom Sende-Endpunkt erhalten, obwohl die Rechnung noch auf ihre Validierung wartet. Markieren Sie die Rechnung bereits zu diesem Zeitpunkt als angenommen, eilt Ihr lokaler Status dem offiziellen System voraus. Dadurch könnten Sie einem Kunden fälschlich einen Erfolg melden, nachgelagerte Buchhaltungsprozesse zu früh anstoßen oder die Kennungen verlieren, mit denen Sie eine spätere Ablehnung nachvollziehen könnten.

Der offizielle Leitfaden für interaktive Sitzungen beschreibt die Prüfung nach der Übermittlung als asynchron. Speichern Sie die zurückgegebene Rechnungsreferenz sofort zusammen mit Ihrer lokalen Rechnung und der Sitzungsreferenz. Diese drei Kennungen erfüllen unterschiedliche Aufgaben:

  • Ihre lokale Rechnungs-ID verknüpft den Ablauf mit Ihrem eigenen Geschäftsvorgang.
  • Die Sitzungsreferenz bezeichnet die für den Transport verwendete KSeF-Sitzung.
  • Die Rechnungsreferenz bezeichnet diese Übermittlung, während KSeF sie verarbeitet.
  • Die KSeF-Nummer wird erst nach der Annahme vergeben und anschließend Teil des Nachweises.

Warten Sie im Erfolgsfall auf den Rechnungsstatus 200, vergewissern Sie sich, dass die Antwort die KSeF-Nummer enthält, und rufen Sie die UPO ab. Das KSeF-2.0-Handbuch des Ministeriums, Teil II erklärt, dass bei der Annahme eine KSeF-Nummer vergeben und die UPO als separates XML-Dokument bereitgestellt wird.

Daraus ergibt sich ein klares Statusmodell: übermittelt, in Verarbeitung, angenommen oder fehlgeschlagen. Fassen Sie übermittelt und angenommen nicht zu einem Status zusammen. Die HTTP-Antwort belegt den Transport; Status 200, die KSeF-Nummer und die geprüfte UPO belegen das abgeschlossene Ergebnis.

Welchen KSeF-Status-Endpunkt sollten Sie abfragen?

Fragen Sie den Status einer einzelnen Rechnung ab, wenn Sie das Ergebnis genau dieser Rechnung benötigen. Verwenden Sie GET /sessions/{referenceNumber}/invoices/{invoiceReferenceNumber} mit der bei der Übermittlung gespeicherten Sitzungs- und Rechnungsreferenz.

Laut der offiziellen OpenAPI-Spezifikation kann die Antwort den KSeF-Rechnungsstatus, die lesbare lokale Rechnungsnummer, die KSeF-Nummer, den Rechnungs-Hash, das Eingangsdatum, das Rechnungsdatum, den Zeitpunkt der dauerhaften Speicherung, den Ausstellungsmodus sowie eine ablaufende UPO-Download-URL samt Ablaufzeitpunkt enthalten. Speichern Sie nützliche Felder, sobald sie verfügbar sind, statt auf den Abschluss der gesamten Sitzung zu warten.

Der Sitzungs-Endpunkt GET /sessions/{referenceNumber} erfüllt einen anderen Zweck. Er meldet den Sitzungsstatus und Summen wie invoiceCount, successfulInvoiceCount und failedInvoiceCount. Für eine geschlossene Sitzung kann er außerdem Referenzen und Download-URLs für zusammengefasste UPO-Seiten zurückgeben.

Diese Summen eignen sich für den Abgleich. Sie zeigen, ob die Zahl der von Ihnen erfassten Einzelergebnisse mit KSeF übereinstimmt. Sie verraten jedoch nicht, welcher lokalen Rechnung welche KSeF-Nummer zugewiesen wurde. Eine Sitzung kann zudem sowohl erfolgreiche als auch fehlgeschlagene Rechnungen enthalten. Deshalb kann ein Ergebnis auf Sitzungsebene den Datensatz der einzelnen Rechnung nicht ersetzen.

Nutzen Sie beide Ansichten gezielt:

  1. Fragen Sie den Status pro Rechnung ab, um die in Ihrem Produkt oder ERP angezeigte Rechnung zu steuern.
  2. Lesen Sie den Sitzungsstatus, um Summen abzugleichen und gegebenenfalls zusammengefasste UPO-Seiten abzurufen.
  3. Untersuchen Sie jede Abweichung zwischen den Sitzungszählern und Ihren gespeicherten Rechnungsergebnissen.

Der offizielle Leitfaden zum Sitzungsstatus und UPO-Abruf dokumentiert beide Ebenen. Ihre klare Trennung verhindert einen häufigen Zuordnungsfehler: Sitzungsreferenz, Rechnungsreferenz und KSeF-Nummer als austauschbare Werte zu behandeln.

Welche Rechnungsstatuscodes sind endgültig?

Eine Statusabfrage muss bei jedem dokumentierten endgültigen Zustand enden, nicht nur bei Erfolg. Die Codes 100 und 150 bedeuten weiterhin laufende Verarbeitung. Code 200 steht für Erfolg. Die unten aufgeführten 4xx- und 5xx-Ergebnisse erfordern eine Fehlerbehandlung oder manuelle Prüfung.

Code Bedeutung Einordnung für den Produktivbetrieb
100 Zur weiteren Verarbeitung angenommen Nicht endgültig
150 In Verarbeitung Nicht endgültig
200 Erfolg Endgültiger Erfolg
405 Wegen eines Sitzungsfehlers abgebrochen Endgültiger Fehler
410 Ungültiger Berechtigungsumfang Endgültiger Fehler
415 Rechnung mit Anhang kann nicht gesendet werden Endgültiger Fehler
430 Fehler bei der Prüfung der Rechnungsdatei Endgültiger Fehler
435 Fehler bei der Dateientschlüsselung Endgültiger Fehler
440 Doppelte Rechnung Endgültiger Fehler, strukturierte Erweiterungen prüfen
450 Fehler bei der semantischen Rechnungsvalidierung Endgültiger Fehler
500 Unbekannter Fehler Endgültiger Fehler, manuell prüfen
550 Vorgang vom System abgebrochen Untersuchen, dann gegebenenfalls auf Vorgangsebene erneut versuchen

Diese Bedeutungen stammen aus SessionInvoiceStatusResponse im aktuellen OpenAPI-Vertrag. Speichern Sie den empfangenen numerischen Code, die Beschreibung, Einzelheiten und strukturierten Erweiterungen. Der lesbare Text unterstützt den Betrieb, der Code bietet der Anwendungslogik dagegen einen stabilen Entscheidungspunkt.

Behandeln Sie den Duplikatstatus 440 mit besonderer Sorgfalt. Er kann strukturierte Angaben zur ursprünglichen Sitzung und KSeF-Nummer enthalten. Diese Angaben dienen der Prüfung, erlauben aber nicht, den neuen Versuch stillschweigend als Erfolg zu verbuchen. Stellen Sie erst dann eine Verbindung zum Original her, wenn Ihre Regeln für Rechnungsidentität und Hash bestätigen, dass beide Datensätze dasselbe Dokument darstellen.

Ihr Parser sollte auch unbekannte Felder tolerieren. Im API-Änderungsprotokoll steht, dass zusätzliche Eigenschaften hinzukommen können, ohne als inkompatible Änderung zu gelten. Unbekannte Statuscodes müssen die Rechnung in die manuelle Prüfung verschieben. Sie dürfen niemals standardmäßig als Annahme gewertet werden.

Wie sollte die Statusabfrage im Produktivbetrieb funktionieren?

Statusabfragen im Produktivbetrieb sollten fortsetzbar, begrenzt und auf die verfügbaren Kontingente abgestimmt sein. Speichern Sie jeden Versuch, verwenden Sie exponentiell wachsende Wartezeiten mit zufälliger Streuung, beachten Sie Retry-After und verschieben Sie ungewöhnlich lange laufende Vorgänge in den Abgleich, statt sie endlos abzufragen.

Die API veröffentlicht Grenzwerte, schreibt aber kein Abfrageintervall vor. Der offizielle Leitfaden zu den API-Grenzwerten nennt derzeit 30 Anfragen pro Sekunde, 120 pro Minute und 1.200 pro Stunde für den Status-Endpunkt einer einzelnen Rechnung. Für andere /sessions/*-Routen, darunter die Endpunkte für Sitzungsstatus und UPO, gelten 10 pro Sekunde, 120 pro Minute und 1.200 pro Stunde. Eine 429-Antwort enthält Retry-After.

Diese Kombination von Grenzwerten ist entscheidend. Eine Abfrage im Sekundentakt kann bei einem kleinen Test unterhalb der Grenze pro Sekunde bleiben und im Produktivbetrieb dennoch das Stundenkontingent ausschöpfen. Nach einer Bereitstellung oder einem Ausfall können mehrere Worker außerdem zeitgleiche Lastspitzen erzeugen. Die zufällige Streuung verteilt diese Anfragen; mit einem gespeicherten next_attempt_at lässt sich der Abfrageplan nach Neustarts fortsetzen.

submit invoice
persist local_id, session_reference, invoice_reference, submitted_hash

repeat with bounded exponential backoff and jitter:
  response = get invoice status
  persist code, details, extensions, checked_at

  if response is 429:
    schedule next attempt from Retry-After
  else if code is 100 or 150:
    schedule next attempt
  else if code is 200 and ksef_number is present:
    persist ksef_number and status timestamps
    retrieve, verify, and archive UPO
    finish as accepted
  else if code is documented terminal failure:
    finish as failed and route to the matching repair path
  else:
    stop automatic acceptance and request manual investigation

if processing exceeds the operational deadline:
  move record to reconciliation queue

Die betriebliche Frist ist Ihre Schutzvorkehrung, kein frei erfundener KSeF-Status. Sie soll verhindern, dass ein einzelner Worker endlos neue Versuche unternimmt, während der Datensatz für spätere Prüfungen erhalten bleibt. Speichern Sie mindestens den Zeitpunkt des letzten Versuchs, die Anzahl der Versuche, die Einzelheiten der letzten Antwort und den Zeitpunkt des nächsten geplanten Versuchs. Damit übersteht die Statusabfrage Prozessabstürze zuverlässig.

Wie rufen Sie UPOs für Rechnungen und Sitzungen ab?

Rufen Sie die UPO einer Rechnung ab, sobald diese Rechnung Status 200 erreicht hat; zusammengefasste UPO-Seiten rufen Sie erst ab, wenn die Bedingungen der Sitzung erfüllt sind. Das Artefakt einer einzelnen Rechnung kann bereits vorliegen, während eine interaktive Sitzung noch geöffnet ist.

KSeF stellt im aktuellen OpenAPI-Vertrag drei authentifizierte Routen bereit:

  • GET /sessions/{sessionReferenceNumber}/invoices/{invoiceReferenceNumber}/upo
  • GET /sessions/{sessionReferenceNumber}/invoices/ksef/{ksefNumber}/upo
  • GET /sessions/{sessionReferenceNumber}/upo/{upoReferenceNumber} für eine zusammengefasste UPO-Seite

Die Statusantwort kann Ihnen außerdem eine signierte upoDownloadUrl oder downloadUrl liefern. Rufen Sie diese Speicher-URL mit einem einfachen HTTP GET ab und senden Sie das KSeF-Zugriffstoken nicht mit. Laut den OpenAPI-Beschreibungen werden Downloads über diese signierten URLs nicht auf die API-Limits angerechnet und laufen zu dem in der Antwort angegebenen Zeitpunkt ab.

Diese Trennung ist wichtig. Die API-Routen erfordern einen der im aktuellen Vertrag aufgeführten Berechtigungsumfänge, darunter InvoiceWrite, Introspection, PefInvoiceWrite oder EnforcementOperations. Ältere Hinweise, laut denen der Abruf über die API ohne Authentifizierung möglich sei, entsprechen nicht dem heute maßgeblichen Vertrag. Für die KSeF-API-Route ist eine Authentifizierung erforderlich; die signierte Speicher-URL wird ohne Ihr Zugriffstoken abgerufen.

Eine Rechnungs-UPO steht zur Verfügung, nachdem die Rechnung angenommen und ihr eine KSeF-Nummer zugewiesen wurde. Die zusammengefasste UPO wird verfügbar, sobald die Sitzung geschlossen ist, alle Dokumente verarbeitet sind und mindestens eines davon sowohl eine KSeF-Nummer als auch eine dauerhafte Speicherung aufweist. Deshalb darf das Schließen einer interaktiven Sitzung keine Voraussetzung dafür sein, eine bereits verfügbare Rechnungs-UPO zu erfassen.

Wie prüfen Sie eine UPO vor der Archivierung?

Archivieren Sie die UPO erst, nachdem Sie die exakten Antwort-Bytes anhand des Transport-Hashs, des XML-Schemas, der Signatur und Ihres Übermittlungsdatensatzes geprüft haben. Das erfolgreiche Parsen des XML ist hilfreich, ersetzt aber keine vollständige Prüfung von Integrität und Identität.

Jede erfolgreiche Antwort beim Download einer Rechnung oder UPO enthält x-ms-meta-hash, einen Base64-codierten SHA-256-Hash des zurückgegebenen Dokuments. Lesen Sie den Inhalt als Bytes, berechnen Sie SHA-256 über diese unveränderten Bytes, codieren Sie das Ergebnis in Base64 und vergleichen Sie es mit dem Header, bevor Sie das XML umwandeln oder normalisieren.

Validieren Sie das XML anschließend gegen das offizielle UPO-v4-3-XSD. UPO v4-3 ist seit dem 22.12.2025 die Standardversion und verwendet ein gemeinsames Schema für Rechnungs- und Sitzungs-UPO. Es enthält TrybWysylki, das zwischen den Sendemodi Online und Offline unterscheidet. Das API-Änderungsprotokoll dokumentiert den Versionswechsel und den Umgang mit Hashes.

Validieren Sie danach die XAdES-Signatur und ihre Vertrauenskette mit dem passenden Vertrauensmaterial des Ministeriums. Vergleichen Sie schließlich die fachlichen Felder des signierten Dokuments mit Ihrem Übermittlungsdatensatz: Sitzungsreferenz, Rechnungs-Hash, NIP des Verkäufers, lokale Rechnungsnummer, KSeF-Nummer, Ausstellungsdatum, Zeitstempel der Übermittlung und des Eingangs sowie Sendemodus.

Führen Sie diese Prüfungen getrennt aus und speichern Sie jedes Ergebnis. Ein korrekter Antwort-Hash beweist, dass Sie die in dieser Antwort gelieferten Bytes gespeichert haben. Die Schemavalidierung belegt die strukturelle Konformität. Die Signaturprüfung deckt Authentizität und Integrität gemäß dem zugrunde liegenden Vertrauensmodell ab. Der Abgleich der Geschäftsfelder belegt, dass das Artefakt zu der Rechnung gehört, die Sie verarbeiten wollten.

Was sollte Ihr KSeF-Nachweisdatensatz enthalten?

Ein belastbarer KSeF-Datensatz muss Kennungen, Statusverlauf, exakte UPO-Bytes und Prüfergebnisse bewahren. Wenn Sie nur die KSeF-Nummer speichern, können Sie später nicht nachvollziehen, wie Ihr System zu seinem Ergebnis gelangt ist.

Nachweisfeld Warum Sie es aufbewahren sollten
Primärschlüssel und Geschäftsnummer der lokalen Rechnung Verknüpft den KSeF-Nachweis mit Ihrem Buchhaltungsdatensatz
Exakter Hash des übermittelten FA(3)-XML Identifiziert das gesendete Dokument und unterstützt Duplikatprüfungen
Sitzungs- und Rechnungsreferenznummern Ermöglichen Statusabfragen, UPO-Abruf und Untersuchungen durch den Support
KSeF-Nummer Hält die nach der Annahme zugewiesene Kennung fest
Letzter Statuscode, Beschreibung, Einzelheiten und Erweiterungen Bewahrt das offizielle Verarbeitungsergebnis und den strukturierten Fehlerkontext
Zeitpunkte der Rechnungsstellung, des Eingangs und der dauerhaften Speicherung Hält unterschiedliche Zeitpunkte getrennt, statt den Status aus ihrer Reihenfolge abzuleiten
Exakte UPO-XML-Bytes Bewahrt den Nachweis unabhängig von der Auslieferungsinfrastruktur
Berechneter SHA-256 und x-ms-meta-hash Dokumentiert den Vergleich zur Integritätsprüfung der Antwort
UPO-Schemaversion und Validierungsergebnis Zeigt, welcher Strukturvertrag geprüft wurde
Ergebnis der Prüfung von XAdES-Signatur und Vertrauenskette Dokumentiert die Authentizitätsprüfung
Zeitstempel von Abruf und Prüfung Zeigt, wann der Nachweis erfasst und geprüft wurde
Verlauf von Wiederholungen, Korrekturen, Korrelationen und Traces Macht Fehler reproduzierbar und betrieblich nachvollziehbar

Speichern Sie die drei KSeF-Zeitstempel als getrennte Felder. invoicingDate, acquisitionDate und permanentStorageDate bezeichnen unterschiedliche Ereignisse. Verwenden Sie ihre scheinbare Reihenfolge nicht als Ersatz für eine Zustandsmaschine. Der Statuscode und die gespeicherten Kennungen bleiben die maßgebliche Grundlage für Ablaufentscheidungen.

Bewahren Sie außerdem die Rohbytes auf, auch wenn Sie daraus bequem durchsuchbare Felder extrahieren. Ein Objektspeicherschlüssel zusammen mit einem Inhalts-Hash eignet sich gut, sofern Aufbewahrungsregeln und Zugriffskontrollen Ihren Nachweisanforderungen entsprechen. Die ablaufende URL kann das Objekt nicht ersetzen. Sie ist lediglich ein möglicher Auslieferungsweg zum Objekt.

Die Wiederherstellung beginnt mit dauerhaft gespeicherten Kennungen und dem Status, nicht mit einer zwischengespeicherten signierten URL. Läuft eine URL ab, fragen Sie KSeF erneut über den authentifizierten Ablauf ab und beschaffen Sie einen aktuellen Abrufweg.

Setzen Sie den Vorgang bei Transportproblemen oder Prozessneustarts anhand der gespeicherten Rechnungsreferenz und des letzten Abfragestatus fort. Beachten Sie bei 429 exakt Retry-After. Führen Sie bei den Statuscodes 100 und 150 den begrenzten Zeitplan fort. Beenden Sie bei einem dokumentierten endgültigen Fehler die Statusabfrage und eröffnen Sie einen zum Fehler passenden Korrekturpfad, statt die Rechnung unbesehen erneut zu übermitteln.

Status 440 verlangt einen bewussten Abgleich. Prüfen Sie die strukturierten Erweiterungen, ermitteln Sie die ursprüngliche Übermittlung und vergleichen Sie die lokale Identität mit dem unveränderlichen Rechnungs-Hash. Entscheiden Sie erst danach, ob das ursprünglich angenommene Dokument das gültige Ergebnis für Ihre lokale Rechnung ist. Eine Duplikatantwort bleibt für den versuchten Vorgang selbst ein Fehler.

Verwenden Sie die zusammengefassten Sitzungsdaten als zweite Absicherung. Vergleichen Sie invoiceCount, successfulInvoiceCount und failedInvoiceCount mit Ihren Datensätzen pro Rechnung. Eine Abweichung kann auf einen verlorenen Job, ein nicht gespeichertes Callback-Ergebnis oder eine zur manuellen Prüfung vorgemerkte Rechnung hinweisen. Der Leitfaden zu Sitzung und UPO enthält die offiziellen Felder und Verfügbarkeitsregeln auf Sitzungsebene.

Am 28.08.2026 ist KSeF API 2.6.1 die neueste Version, die als in PRD bereitgestellt ausgewiesen ist. Version 2.7.1 erreichte TEST am 26.08.2026; DEMO ist für den 15.09.2026 und PRD für den 23.09.2026 vorgesehen. Die dokumentierten Änderungen betreffen diesen Status- und UPO-Ablauf nicht. Dennoch darf die Produktivdokumentation Version 2.7.1 nicht vor diesem Bereitstellungstermin als Produktivversion bezeichnen. Prüfen Sie bei der Implementierung oder einer späteren Überarbeitung der Integration erneut das offizielle Änderungsprotokoll.

Wie KSeF Kit die Nachweiskette schließt

KSeF Kit wendet denselben nachweisorientierten Ablauf auf Stripe-Rechnungen an. Es wandelt in Stripe finalisierte Rechnungen in FA(3) um, übermittelt sie, wartet auf die Annahme, speichert die UPO und schreibt die KSeF-Nummer in die Stripe-Metadaten zurück.

Diese Umsetzung ist hilfreich, weil sie die asynchrone Grenze sichtbar hält. Die Finalisierung in Stripe wird nicht als Behauptung gewertet, KSeF habe die Rechnung angenommen. KSeF Kit wartet auf das offizielle Ergebnis und bewahrt das beweiskräftige Artefakt auf. Den Ablauf auf Produktebene finden Sie in der Dokumentation zum Einreichungsprozess; die unterstützte Stripe-Integration beschreibt die Produktseite von KSeF Kit.

Die allgemeine Regel gilt unabhängig davon, ob Sie die Integration selbst entwickeln oder ein Produkt verwenden: Speichern Sie jede Referenz, beenden Sie die Abfrage bei jedem endgültigen Status, prüfen Sie das heruntergeladene Artefakt und archivieren Sie Nachweise, die ihre URL überdauern. So wird aus einem erfolgreichen API-Aufruf ein Ergebnis, das Sie später abgleichen und belastbar belegen können.

Wenn Sie Rechnungen über Stripe ausstellen und diese Abfrage- und Nachweiskette nicht selbst entwickeln möchten, erfahren Sie, wie KSeF Kit Rechnungen einreicht und dokumentiert.

Verwandte Artikel

Bereit, smarter einzustellen?

30 Tage kostenlos testen. Wenn Sie vor Ablauf kündigen, zahlen Sie nichts. Richten Sie Ihre erste Recruiting-Pipeline in wenigen Minuten ein.

Kostenlos starten