Rechnungs-API
REST-Endpoint zum Erstellen und Ausstellen von Rechnungen aus externen Systemen, authentifiziert über rotierbare API-Tokens.
Die Rechnungs-API erstellt und stellt Rechnungen über einen einzelnen REST-Endpoint aus. Der Absender ist an das verwendete Token gebunden und wird nicht im Request übergeben. Ausgestellte Rechnungen erhalten eine fortlaufende, lückenlose Nummer und ein PDF; der Vorgang ist nicht umkehrbar.
Verhalten im Überblick:
- Jeder erfolgreiche Request stellt die Rechnung sofort und endgültig aus.
- Kunden werden über eine bestehende ID referenziert oder — bei Angabe eines Namens — neu angelegt. Aufträge (Bookings) sind über die API nicht referenzierbar; entsprechende Felder werden abgelehnt.
- Beträge werden als String im deutschen Zahlenformat (
"1.234,50") oder als Zahl akzeptiert.
Paketabhängig: Die Rechnungs-API ist ein eigenes Paket-Feature. Ist es nicht freigeschaltet, antwortet der Endpoint mit
403 FEATURE_LOCKED.
Endpoint
POST https://app.kreativmind.at/api/public/invoices
Content-Type: application/json
Authorization: Bearer <token>
Authentifizierung
Die Authentifizierung erfolgt über ein Bearer-Token im Authorization-Header. Tokens werden unter Einstellungen → Rechnungen verwaltet und sind an genau einen Absender gebunden.
- Das Token wird bei Erstellung und Rotation genau einmal im Klartext ausgegeben und serverseitig ausschließlich als SHA-256-Hash gespeichert.
- Rotation invalidiert das bisherige Token sofort; die Absender-Bindung bleibt bestehen.
- Widerrufene Tokens werden mit
403 TOKEN_REVOKEDabgewiesen.
Beispiel
curl -X POST https://app.kreativmind.at/api/public/invoices \
-H "Authorization: Bearer $INVOICE_API_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-2026-0042" \
-d '{
"client": {
"name": "Musterfirma GmbH",
"email": "office@musterfirma.at",
"addressStreet": "Hauptstraße 1",
"addressZip": "1010",
"addressCity": "Wien"
},
"serviceDate": "2026-06-30",
"items": [
{
"name": "Fotoshooting",
"unit": "Std",
"unitPrice": "120,00",
"quantity": "3",
"taxRate": "20"
}
]
}'
Request
Der Request-Body ist JSON. Erforderlich sind eine Kundenreferenz, ein Leistungszeitpunkt und mindestens eine Position. Nicht gesetzte optionale Felder fallen auf die Vorgaben des Absenders zurück.
Kunde
Entweder wird eine bestehende Kunden-ID übergeben oder — ohne ID — mindestens client.name. Im zweiten Fall wird der Kunde angelegt; die erzeugte ID wird in der Antwort zurückgegeben und kann für Folgerechnungen wiederverwendet werden.
| Feld | Typ | Beschreibung |
|---|---|---|
client.id | string | ID eines bestehenden Kunden. Muss zum Konto gehören, sonst 422. |
client.name | string | Erforderlich, wenn client.id fehlt. Legt einen neuen Kunden an. |
client.email | string | Optional; nur bei Neuanlage berücksichtigt. |
client.addressStreet / addressZip / addressCity / addressCountry | string | Optional; nur bei Neuanlage berücksichtigt. |
Die Neuanlage zählt gegen das Kunden-Limit des Pakets (403 LIMIT_REACHED bei Überschreitung).
Leistungszeitpunkt
Mindestens eines der folgenden Felder ist erforderlich (422 VALIDATION_ERROR andernfalls):
| Feld | Typ | Beschreibung |
|---|---|---|
serviceDate | date | Leistungsdatum, ISO 8601 (2026-06-30). |
serviceFrom / serviceTo | date | Leistungszeitraum. serviceTo ist optional. |
servicePeriodText | string | Freitext, z. B. "Juni 2026". |
Positionen (items[])
Mindestens eine Position ist erforderlich.
| Feld | Typ | Beschreibung |
|---|---|---|
name * | string | Bezeichnung der Position. |
unitPrice * | string | number | Netto-Einzelpreis. |
quantity * | string | number | Menge. |
unit | string | Einheit. Standard: "Stk". |
taxRate | string | number | USt-Satz in Prozent. Ohne Angabe gilt der Standardsatz des Absenders. |
discountPercent | string | number | Positionsrabatt in Prozent. |
Weitere Felder
| Feld | Typ | Beschreibung |
|---|---|---|
title / introText / footerText | string | Rechnungstitel, Einleitungs- und Fußtext. Ohne Angabe gelten die Absender-Vorgaben. |
dueDate | date | Fälligkeitsdatum. Ohne Angabe wird das Zahlungsziel des Absenders angewendet. |
currency | string | ISO-Währungscode. Standard: EUR. |
discountType / discountValue | enum / string | number | Gesamtrabatt: NONE, PERCENT oder AMOUNT mit zugehörigem Wert. |
skontoPercent / skontoDays | string | number / number | Skonto in Prozent und Tagen. |
Antwort
201 Created mit den Referenzen der ausgestellten Rechnung:
{
"invoiceId": "cmck3…",
"number": "2026-014",
"clientId": "cmck1…",
"clientCreated": true,
"pdfUrl": "https://app.kreativmind.at/api/public/billing/…/pdf",
"viewUrl": "https://app.kreativmind.at/inv/…"
}
| Feld | Typ | Beschreibung |
|---|---|---|
invoiceId | string | ID der erzeugten Rechnung. |
number | string | Vergebene, lückenlose Rechnungsnummer. |
clientId | string | ID des verknüpften Kunden. |
clientCreated | boolean | true, wenn der Kunde durch diesen Request angelegt wurde. |
pdfUrl | string | Öffentlicher PDF-Download der Rechnung. |
viewUrl | string | Öffentliche Ansichtsseite der Rechnung. |
Fehler
Fehlerantworten sind JSON mit einem maschinenlesbaren Code. Validierungsfehler enthalten zusätzlich Feldcodes im Objekt fields.
| Status | Code | Bedeutung |
|---|---|---|
| 401 | NOT_AUTHENTICATED | Authorization-Header fehlt, Token unbekannt oder rotiert. |
| 403 | TOKEN_REVOKED | Token wurde widerrufen. |
| 403 | SENDER_ARCHIVED | Der gebundene Absender ist archiviert. |
| 403 | TENANT_LOCKED | Das Konto ist gesperrt. |
| 403 | FEATURE_LOCKED / LIMIT_REACHED / NO_PACKAGE | Feature nicht im Paket bzw. Paketlimit erreicht. |
| 422 | VALIDATION_ERROR | Ungültiger Request. fields benennt die betroffenen Felder, z. B. { "client.name": "REQUIRED" }. |
| 500 | SERVER_ERROR | Unerwarteter Fehler. Request mit demselben Idempotency-Key wiederholen. |
Enthält der Body bookingId oder orderId, wird der Request mit 422 und { "bookingId": "NOT_ALLOWED" } abgelehnt.
Idempotenz
Der optionale Header Idempotency-Key verhindert doppelte Rechnungen bei Wiederholungen (Timeouts, automatische Retries). Ein wiederholter Request mit demselben Key liefert die ursprünglich erzeugte Rechnung mit 200 zurück, statt eine weitere Nummer zu vergeben.
Idempotency-Key: order-2026-0042
Empfohlen wird ein stabiler, fachlicher Schlüssel pro Vorgang, etwa die interne Vorgangs- oder Bestell-ID des aufrufenden Systems.