API-Dokumentation

Version 1  |  Basis-URL https://steuerkompakt.de/api/v1

Mit der SteuerKompakt-API legt ein anderes Programm — etwa ein CRM oder ein Shop — Rechnungen an, liest sie aus und holt die fertige Rechnung als PDF oder XRechnung ab. Die API ist Teil des Business-Tarifs, spricht JSON und ist nur über HTTPS erreichbar.

Zugang

Jede Anfrage trägt einen API-Schlüssel im Kopf Authorization:

Authorization: Bearer sk_live_…
  • Schlüssel legt der Eigentümer oder ein Administrator in der App unter API-Schlüssel an (Menü unten links). Der Klartext wird genau einmal angezeigt — danach kennt ihn auch SteuerKompakt nicht mehr, gespeichert ist nur ein Hash.
  • Jeder Schlüssel hat Rechte: lesen für alle GET-Anfragen (auch PDF und XRechnung), schreiben für Anlegen, Ändern und Löschen. Schlüssel aus der Zeit vor den Rechten dürfen beides.
  • Jeder Schlüssel hat ein Ablaufdatum und lässt sich jederzeit sperren.
  • Der Schlüssel gehört auf einen Server, nicht in Browser-JavaScript: wer die Seite öffnet, könnte ihn dort lesen. Die API sendet deshalb bewusst keine CORS-Kopfzeilen.

Ratenbegrenzung

Je Schlüssel 120 Anfragen pro Minute; Anfragen ohne Schlüssel zählen je IP-Adresse mit höchstens 20 pro Minute. Jede Antwort nennt den Stand in X-RateLimit-Limit und X-RateLimit-Remaining. Darüber gibt es 429 mit Retry-After (Sekunden bis zum nächsten Versuch).

Fehler

Jede Fehlerantwort hat "success": false und in error eine Meldung auf Deutsch, die sich einem Menschen zeigen lässt:

{
  "success": false,
  "error": "Dieser API-Schlüssel ist am 31.12.2026 abgelaufen."
}
StatusBedeutung
401Schlüssel fehlt, ist unbekannt, gesperrt oder abgelaufen.
403Anfrage über HTTP statt HTTPS, Konto gesperrt, kein Business-Tarif oder dem Schlüssel fehlt das Recht.
404Die Rechnung gibt es nicht — oder sie gehört zu einem anderen Konto. Beides sieht gleich aus.
422Eingaben ungültig (mit errors je Feld) oder die Rechnung lässt sich so nicht ausstellen (mit fehlt).
429Ratenbegrenzung überschritten.

Bei ungültigen Eingaben stehen die Meldungen je Feld in errors; message fasst sie zusammen:

{
  "success": false,
  "error": "Die Angaben sind unvollständig oder ungültig.",
  "message": "Rechnungsnummer muss ausgefüllt werden. (und 1 weiterer Fehler)",
  "errors": {
    "rechnungsnummer": ["Rechnungsnummer muss ausgefüllt werden."],
    "ust_satz": ["Der gewählte Wert für USt-Satz ist ungültig."]
  }
}

Das Rechnungsobjekt

Beträge rechnet SteuerKompakt. Übergeben werden netto_betrag und ust_satz; ust_betrag, brutto_betrag und jahr entstehen daraus und lassen sich nicht von außen setzen. Ein negativer Nettobetrag ist eine Rechnungskorrektur.

Positionen. Statt beschreibung und netto_betrag kann eine Rechnung positionen tragen. Dann ist netto_betrag ihre Summe und beschreibung ihre Zusammenfassung (oder die mitgeschickte). Jede Position kann ihren eigenen Steuersatz tragen. Die Steuer wird je Satz auf die Summe gerechnet, ust_betrag ist ihre Summe. Ein ust_satz allein beim Ändern gilt für alle Positionen. Wer beim Ändern nur netto_betrag schickt, ersetzt die Positionen durch diesen einen Betrag; ohne beides bleiben sie, wie sie sind. In der Antwort steht immer mindestens eine Position. Eine Rechnung ohne gespeicherte Positionen hat genau eine aus dem Kopf.

FeldTypBeschreibung
idZahlnur lesen
rechnungsnummerText, max. 100Pflicht; je Konto eindeutig
typausgang | eingangPflicht; ausgestellt oder erhalten
datumDatum JJJJ-MM-TTPflicht; Rechnungsdatum
faellig_amDatum | nullnicht vor datum
bezahlt_amDatum | nullPflicht, wenn status = bezahlt
kunde_lieferantText, max. 255Pflicht; Name des Empfängers bzw. Lieferanten
beschreibungText, max. 5.000Pflicht ohne positionen; Art und Umfang der Leistung
netto_betragZahlPflicht ohne positionen; in Euro
ust_satz0 | 7 | 19Pflicht, außer jede Position hat ihren eigenen; Kleinunternehmer: 0. Bei gemischten Sätzen der mit dem größten Nettoanteil
ust_betrag, brutto_betragZahlnur lesen; gerechnet
statusoffen | bezahltohne Angabe offen
notizenText | nullintern
jahrZahlnur lesen; aus datum
gebuchttrue | falseob die Rechnung in der Buchhaltung erfasst ist
has_attachmenttrue | falsenur lesen; ob ein PDF anhängt (Feld pdf beim Anlegen/Ändern, als multipart/form-data)
created_atJJJJ-MM-TT hh:mm:ssnur lesen
Für PDF und XRechnung (§ 14 Abs. 4 UStG) — optional beim Speichern, nötig beim Ausstellen:
empfaenger_strasse, empfaenger_plz, empfaenger_ortText | nullAnschrift des Empfängers
empfaenger_landzwei BuchstabenISO 3166-1, ohne Angabe DE
empfaenger_ust_idnrText | nullbei Leistungen ins EU-Ausland
empfaenger_emailE-Mail | nullfür die XRechnung Pflicht
kaeufer_referenzText | nullLeitweg-ID bei Behörden, sonst etwa die Bestellnummer
leistungsdatum, leistung_bisDatum | nullTag der Leistung oder Zeitraum
Positionen — Liste, höchstens 200:
positionen[].beschreibungText, max. 1.000Pflicht
positionen[].mengeZahl, bis 3 Nachkommastellenohne Angabe 1; nicht 0
positionen[].einheitUN/ECE-Codeohne Angabe C62 (Stück); außerdem HUR</code>, <code>DAY</code>, <code>MON</code>, <code>LS</code>, <code>KGM</code>, <code>MTR</code>, <code>MTK</code>, <code>LTR</code>, <code>KMT
positionen[].einzelpreisZahlPflicht; netto in Euro, negativ für einen Nachlass
positionen[].ust_satz0 | 7 | 19ohne Angabe der Satz im Kopf — so entstehen gemischte Sätze
steueraufschluesselungListenur lesen; je Satz ust_satz, netto, ust_betrag (§ 14 Abs. 4 Nr. 8 UStG)
positionen[].position, positionen[].nettoZahlnur lesen; Menge × Einzelpreis, auf Cent gerundet

Endpunkte

GET /invoices

Rechnungen des Kontos, neueste zuerst. Recht: lesen.

  • limit — Anzahl, Standard 50, höchstens 200 (mehr wird gekappt, nicht abgelehnt)
  • offset — ab welcher Rechnung
  • jahr, status (offen|bezahlt), typ (ausgang|eingang) — Filter
curl https://steuerkompakt.de/api/v1/invoices?jahr=2026&status=offen \
  -H "Authorization: Bearer sk_live_…"
{
  "success": true,
  "data": [ { "id": 42, "rechnungsnummer": "RE-2026-0042", … } ],
  "limit": 50,
  "offset": 0,
  "count": 1,
  "total": 1
}

count ist die Zahl auf dieser Seite, total die Gesamtzahl — damit lässt sich blättern, ohne auf eine leere Seite zu warten.

GET /invoices/{id}

Eine Rechnung. Recht: lesen. Antwort: {"success": true, "data": {…}}.

POST /invoices

Rechnung anlegen. Recht: schreiben. Antwort 201 mit id und data.

curl -X POST https://steuerkompakt.de/api/v1/invoices \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "typ": "ausgang",
    "rechnungsnummer": "RE-2026-0042",
    "datum": "2026-09-25",
    "kunde_lieferant": "Musterkunde GmbH",
    "ust_satz": 19,
    "positionen": [
      { "beschreibung": "Beratung", "menge": 12.5, "einheit": "HUR", "einzelpreis": 95.00 },
      { "beschreibung": "Einrichtung", "einheit": "LS", "einzelpreis": 250.00 }
    ],
    "empfaenger_strasse": "Kundenweg 7",
    "empfaenger_plz": "10115",
    "empfaenger_ort": "Berlin",
    "empfaenger_email": "[email protected]",
    "leistungsdatum": "2026-09-01",
    "leistung_bis": "2026-09-30"
  }'

PUT PATCH POST /invoices/{id}

Rechnung ändern. Recht: schreiben. Geändert wird nur, was mitkommt — PUT und PATCH verhalten sich gleich. POST ist ein Ersatz für Programme, die kein PUT senden können.

DELETE /invoices/{id}

Rechnung samt Anhang löschen. Recht: schreiben. Antwort: {"success": true}.

GET /invoices/{id}/pdf

Die Ausgangsrechnung als PDF mit eingebetteter E-Rechnung (ZUGFeRD, EN 16931). Recht: lesen. Fehlen Pflichtangaben, gibt es 422 und die Liste in fehlt:

{
  "success": false,
  "error": "Die Rechnung lässt sich so nicht ausstellen.",
  "fehlt": ["Der Rechnung fehlt die Anschrift des Empfängers (Straße, PLZ; § 14 Abs. 4 Nr. 1 UStG)."]
}

GET /invoices/{id}/xrechnung

Die Ausgangsrechnung als XRechnung 3.0 (CII-Syntax). Recht: lesen. Verlangt über das PDF hinaus die E-Mail des Empfängers sowie Telefon und IBAN im Profil des Ausstellers; sonst 422 mit fehlt.

Fragen zur API: [email protected]