Eigene Anwendung per API anbinden
Aktualisiert am
Mit der REST-API meldet deine eigene Anwendung (SaaS, eigener Checkout, Plattform) Transaktionen an Rechnungskit. Die vollständige Referenz findest du auf rechnungskit.de/docs/api.
Grundlagen
- Basis-URL: https://api.rechnungskit.de/v1, REST mit JSON, OpenAPI 3.1.
- Authentifizierung: Bearer-Token mit deinem API-Schlüssel.
- Beträge immer in ganzzahligen Cent, nie als Kommazahlen.
- Idempotenz: Deine Bestellnummer (orderNo) ist der natürliche Schlüssel, zusätzlich wird der Idempotency-Key-Header unterstützt. Doppelte Übermittlungen erzeugen keine doppelten Belege.
API-Schlüssel
Unter Einstellungen → API erstellst du Schlüssel:
- Zwei Berechtigungen: orders:write (Bestellungen und Fulfillments melden) und invoices:read (Belege abrufen).
- Es gibt EINEN Schlüssel-Typ (Präfix rk_key_). Ob Belege Testdaten oder echt sind, entscheidet allein der Testmodus des Projekts, nie der Schlüssel: Derselbe Schlüssel erzeugt im Testmodus Testbelege und nach dem Go-Live echte Belege; nichts muss ausgetauscht werden. Ältere Schlüssel mit rk_test_- oder rk_live_-Präfix bleiben unverändert gültig.
- Der volle Schlüssel wird genau einmal angezeigt, danach nur noch der Anfang. Ablauf wählbar (30/90/365 Tage oder ohne), Schlüssel, die über 90 Tage unbenutzt sind, werden markiert.
Wichtigste Endpunkte
- POST /v1/orders, Bestellung übermitteln (Positionen, Beträge in Cent, Zahlart). Versandkosten wahlweise als shippingGrossCents (bezahlter Bruttobetrag, Rechnungskit ermittelt die Steuer) oder als shippingNetCents plus shippingTaxRate. Bei gemischten Steuersätzen im Warenkorb teilt Rechnungskit den Versand automatisch nach dem Brutto-Warenwert auf (BFH XI R 22/22), genau wie beim Rechnungskit-Checkout; der bezahlte Betrag ändert sich dabei nie.
- GET /v1/orders/{orderNo}, Status einer Bestellung
- POST /v1/fulfillments, Versand melden (setzt das Leistungsdatum), nur für physische Ware nötig
- GET /v1/invoices, GET /v1/invoices/{reference}, Belege auflisten und abrufen
- GET /v1/invoices/{reference}/pdf und /xml, Beleg-Dateien laden
Artikel-Id je Position: productId
Jede Position darf eine productId tragen, die stabile Artikel-Id aus deinem System. Sie ist optional, aber empfohlen: Sie bindet die Position an genau ein Produkt im Rechnungskit-Katalog, auch wenn sich Name oder SKU spaeter aendern.
Ohne productId sucht Rechnungskit das Produkt zuerst ueber die SKU und, wenn auch die fehlt, ueber den exakten Namen. Aenderst du dann dein SKU-Schema oder lieferst eine SKU nach, entsteht je Variante ein neues Katalogprodukt. Das faellt zuerst dort auf, wo Produkte gepflegt werden: dieselbe Ware steht mehrfach in der Liste, und jede Fassung braucht eigene USt-Kategorie und Umsatzrealisierung.
Die Id ist beliebiger Text (zum Beispiel die Primaerschluessel-Id deiner Artikeltabelle). Wichtig ist nur, dass sie je Artikel gleich bleibt. Verschiedene productId bedeuten verschiedene Artikel, auch bei identischem Namen, das trennt echte Varianten sauber.
SaaS und digitale Leistungen: nur ein Endpunkt
Für SaaS oder rein digitale Leistungen genügt POST /v1/orders. Das Feld requiresShipping einfach weglassen (Standard false): Dann gibt es keine Erfüllungs-Wartestufe und /v1/fulfillments wird nie aufgerufen. Die Rechnung entsteht, sobald die Zahlung des angebundenen Zahlungsanbieters zur Bestellung passt (paymentRef mitschicken beschleunigt die Zuordnung). Ein "bezahlt"-Feld gibt es bewusst nicht: Den Zahlungsstatus liefert der Zahlungsanbieter, nicht der Sender.
Leistungszeitraum (SaaS/Abos): das Feld service_period
Für zeitbasierte Leistungen (SaaS, Abos) sendest du den Leistungszeitraum im optionalen Feld service_period (snake_case, nicht camelCase). Es ist ein Objekt mit den Schlüsseln start_date und end_date, jeweils als ISO-Datum im Format YYYY-MM-DD. Beide gehören zusammen: entweder beide oder keins (fehlt einer, kommt 422). end_date darf nicht vor start_date liegen.
Beispiel im Bestell-Body: "service_period": { "start_date": "2026-06-01", "end_date": "2026-06-30" }.
Der Leistungszeitraum steuert die passive Rechnungsabgrenzung (pRAP, nur Bilanzierer; bei EÜR wird sofort vereinnahmt) und landet als Leistungszeitraum auf der ZUGFeRD-Rechnung. Ein hier mitgeschickter service_period hat Vorrang vor der SaaS-Voreinstellung am Produkt. Lässt du das Feld weg, greift die Produkt-Voreinstellung (z. B. der am SaaS-Produkt hinterlegte Abrechnungsrhythmus). Der Checkout-Link (/c/…) kennt kein Feld dafür; dort kommt der Zeitraum aus der Produktkonfiguration.
Rückdatierter Leistungszeitraum: Ein start_date, das VOR dem Rechnungsdatum liegt, ist erlaubt. Liegt der Beginn im selben Wirtschaftsjahr, ist das unproblematisch (das Jahresergebnis stimmt). Beginnt der Zeitraum in einem FRÜHEREN, meist abgeschlossenen Wirtschaftsjahr, legt Rechnungskit (bei Bilanzierung) eine Aufgabe „Leistungszeitraum im Vorjahr" an: Die bereits vergangenen Monate gehören periodengerecht ins Vorjahr, ggf. ist eine Bilanzberichtigung nötig. Die Rechnung wird trotzdem erstellt; die Aufgabe ist ein Hinweis, keine Blockade.
Fehlender Leistungszeitraum bei zeitbasierten Produkten: Schickst du keinen service_period und ist am Produkt auch keine SaaS-Voreinstellung (Abrechnungszeitraum) hinterlegt, hängt es von der Gewinnermittlung ab. Bei EÜR wird sofort vereinnahmt, es passiert nichts weiter. Bei Bilanzierung braucht Rechnungskit den Zeitraum für die Rechnungsabgrenzung: Die Rechnung wird dann NICHT sofort erstellt, sondern als Aufgabe „Produkt ohne Umsatzrealisierung" unter Zu prüfen gehalten (es wird noch keine Rechnungsnummer vergeben). Du legst die Umsatzrealisierung am Produkt fest (Einstellungen → Produkte) oder schickst den service_period an der Bestellung nach; danach wird die Rechnung automatisch erstellt.
Zahlarten über die API
Die Zuordnung von Zahlungen läuft über die Zahlungsanbieter-Anbindungen (Stripe, Mollie, PayPal, Unzer), deine Anwendung liefert die Bestelldaten. Für Kauf auf Rechnung muss das Feld paymentGateway exakt einem unter Einstellungen → Connect hinterlegten Rechnungskauf-Gateway entsprechen, die Schreibweise zählt.
Überweisung über Stripe (paymentGateway stripe_transfer)
Soll dein Kunde per Überweisung zahlen und das Geld über dein Stripe-Konto ankommen, sendest du die Bestellung mit paymentGateway „stripe_transfer“ und einer E-Mail-Adresse. Bei einer Leistung entsteht die Rechnung sofort, bei Ware erst mit der Versandmeldung über /v1/fulfillments. Gleichzeitig legt Rechnungskit in deinem Stripe-Konto einen Zahlungsauftrag für Banküberweisung an. Auf der Rechnung stehen die virtuelle Stripe-IBAN deines Kunden und, als Verwendungszweck, Stripes Referenz für genau diese Zahlung. Kommt die Überweisung mit dieser Referenz an, ordnet Stripe das Geld zu, und Rechnungskit schließt den offenen Posten unter /receivables. Weil keine Stripe-Rechnung entsteht, fällt keine Invoicing-Gebühr an, nur die für die Überweisung.
Dafür braucht der Stripe-Schlüssel die Rechte Customers (Schreiben) und Payment Intents (Schreiben). Fehlt eines, entsteht keine Rechnung; stattdessen bekommst du eine dringende Aufgabe samt E-Mail, und nach dem Ergänzen holt Rechnungskit die Rechnung automatisch nach. Wird der Zahlungsauftrag in Stripe abgebrochen, bevor bezahlt ist, folgt eine Stornorechnung. Als Überweisungsbetrag gilt das Bestellbrutto, und die Rechnung trifft ihn auf den Cent.
Öffentliche Auftraggeber: leitweg_id
Die Rechnungsadresse (billing_address) nimmt neben vat_id auch leitweg_id an. Ist eine gültige Leitweg-ID gesetzt, wird die Rechnung dieser Bestellung als XRechnung 3.0 erstellt, sonst als ZUGFeRD. Eine formal ungültige Leitweg-ID beantwortet die API mit 422. Voraussetzung ist eine Telefonnummer im Rechnungskontakt unter Einstellungen, ohne sie hält Rechnungskit die XRechnung als Aufgabe an.
Testen
Nutze deinen normalen API-Schlüssel im Testmodus: gleiche Pipeline, EN-16931-Validierung und PDF-Erstellung inklusive, aber Testnummernkreis (TEST-...), keine Abrechnung, kein Versand, kein Einfluss auf DATEV/OSS/ZM. Fair Use, keine Lasttests.
Zustell-Kontrakt (Pflicht für Integratoren)
Dein System muss fehlgeschlagene Pushes wiederholen. Jeder 5xx- oder Netzwerkfehler ist transient (auch Deployments verursachen kurze 502-Fenster); wiederhole mit exponentiellem Backoff über mindestens 24 Stunden. Wiederholungen sind immer sicher: Bestellungen sind idempotent über orderNo, der Idempotency-Key-Header dedupliziert parallele Zustellungen. Zusätzlich empfohlen: ein täglicher Abgleichs-Job, der alles erneut sendet, was dein System als fehlgeschlagen markiert hat. Typischer Fehlerfall ohne Retry: Die Zahlung kommt an (PSP wiederholt automatisch), der Bestell-Push scheitert an einem einzigen 502, und die Zahlung bleibt als "Keine Bestellung" in der Klärung liegen, bis die Bestellung nachgereicht wird.
Grenzen, ehrlich benannt
- Fehlerantworten folgen den üblichen Codes (400/401/403/404/409/422/429/503), bei 429/503 mit Retry-After. Baue Backoff ein.
- Anfragen sind über die Request-ID 30 Tage in der API-Aktivität nachvollziehbar.
Wo in der App
- /settings/api, Schlüssel erstellen, Berechtigungen, Aktivität
- /settings/connect, Zahlungsanbieter und Rechnungskauf-Gateways
- /invoices, aus API-Bestellungen entstandene Belege