API-Dokumentation
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:
lesenfür alle GET-Anfragen (auch PDF und XRechnung),schreibenfü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."
}
| Status | Bedeutung |
|---|---|
401 | Schlüssel fehlt, ist unbekannt, gesperrt oder abgelaufen. |
403 | Anfrage über HTTP statt HTTPS, Konto gesperrt, kein Business-Tarif oder dem Schlüssel fehlt das Recht. |
404 | Die Rechnung gibt es nicht — oder sie gehört zu einem anderen Konto. Beides sieht gleich aus. |
422 | Eingaben ungültig (mit errors je Feld) oder die Rechnung lässt sich so nicht ausstellen (mit fehlt). |
429 | Ratenbegrenzung ü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.
| Feld | Typ | Beschreibung |
|---|---|---|
id | Zahl | nur lesen |
rechnungsnummer | Text, max. 100 | Pflicht; je Konto eindeutig |
typ | ausgang | eingang | Pflicht; ausgestellt oder erhalten |
datum | Datum JJJJ-MM-TT | Pflicht; Rechnungsdatum |
faellig_am | Datum | null | nicht vor datum |
bezahlt_am | Datum | null | Pflicht, wenn status = bezahlt |
kunde_lieferant | Text, max. 255 | Pflicht; Name des Empfängers bzw. Lieferanten |
beschreibung | Text, max. 5.000 | Pflicht ohne positionen; Art und Umfang der Leistung |
netto_betrag | Zahl | Pflicht ohne positionen; in Euro |
ust_satz | 0 | 7 | 19 | Pflicht, außer jede Position hat ihren eigenen; Kleinunternehmer: 0. Bei gemischten Sätzen der mit dem größten Nettoanteil |
ust_betrag, brutto_betrag | Zahl | nur lesen; gerechnet |
status | offen | bezahlt | ohne Angabe offen |
notizen | Text | null | intern |
jahr | Zahl | nur lesen; aus datum |
gebucht | true | false | ob die Rechnung in der Buchhaltung erfasst ist |
has_attachment | true | false | nur lesen; ob ein PDF anhängt (Feld pdf beim Anlegen/Ändern, als multipart/form-data) |
created_at | JJJJ-MM-TT hh:mm:ss | nur lesen |
| Für PDF und XRechnung (§ 14 Abs. 4 UStG) — optional beim Speichern, nötig beim Ausstellen: | ||
empfaenger_strasse, empfaenger_plz, empfaenger_ort | Text | null | Anschrift des Empfängers |
empfaenger_land | zwei Buchstaben | ISO 3166-1, ohne Angabe DE |
empfaenger_ust_idnr | Text | null | bei Leistungen ins EU-Ausland |
empfaenger_email | E-Mail | null | für die XRechnung Pflicht |
kaeufer_referenz | Text | null | Leitweg-ID bei Behörden, sonst etwa die Bestellnummer |
leistungsdatum, leistung_bis | Datum | null | Tag der Leistung oder Zeitraum |
| Positionen — Liste, höchstens 200: | ||
positionen[].beschreibung | Text, max. 1.000 | Pflicht |
positionen[].menge | Zahl, bis 3 Nachkommastellen | ohne Angabe 1; nicht 0 |
positionen[].einheit | UN/ECE-Code | ohne 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[].einzelpreis | Zahl | Pflicht; netto in Euro, negativ für einen Nachlass |
positionen[].ust_satz | 0 | 7 | 19 | ohne Angabe der Satz im Kopf — so entstehen gemischte Sätze |
steueraufschluesselung | Liste | nur lesen; je Satz ust_satz, netto, ust_betrag (§ 14 Abs. 4 Nr. 8 UStG) |
positionen[].position, positionen[].netto | Zahl | nur 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 Rechnungjahr,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]