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_REVOKED abgewiesen.

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.

FeldTypBeschreibung
client.idstringID eines bestehenden Kunden. Muss zum Konto gehören, sonst 422.
client.namestringErforderlich, wenn client.id fehlt. Legt einen neuen Kunden an.
client.emailstringOptional; nur bei Neuanlage berücksichtigt.
client.addressStreet / addressZip / addressCity / addressCountrystringOptional; 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):

FeldTypBeschreibung
serviceDatedateLeistungsdatum, ISO 8601 (2026-06-30).
serviceFrom / serviceTodateLeistungszeitraum. serviceTo ist optional.
servicePeriodTextstringFreitext, z. B. "Juni 2026".

Positionen (items[])

Mindestens eine Position ist erforderlich.

FeldTypBeschreibung
name *stringBezeichnung der Position.
unitPrice *string | numberNetto-Einzelpreis.
quantity *string | numberMenge.
unitstringEinheit. Standard: "Stk".
taxRatestring | numberUSt-Satz in Prozent. Ohne Angabe gilt der Standardsatz des Absenders.
discountPercentstring | numberPositionsrabatt in Prozent.

Weitere Felder

FeldTypBeschreibung
title / introText / footerTextstringRechnungstitel, Einleitungs- und Fußtext. Ohne Angabe gelten die Absender-Vorgaben.
dueDatedateFälligkeitsdatum. Ohne Angabe wird das Zahlungsziel des Absenders angewendet.
currencystringISO-Währungscode. Standard: EUR.
discountType / discountValueenum / string | numberGesamtrabatt: NONE, PERCENT oder AMOUNT mit zugehörigem Wert.
skontoPercent / skontoDaysstring | number / numberSkonto 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/…"
}
FeldTypBeschreibung
invoiceIdstringID der erzeugten Rechnung.
numberstringVergebene, lückenlose Rechnungsnummer.
clientIdstringID des verknüpften Kunden.
clientCreatedbooleantrue, wenn der Kunde durch diesen Request angelegt wurde.
pdfUrlstringÖffentlicher PDF-Download der Rechnung.
viewUrlstringÖffentliche Ansichtsseite der Rechnung.

Fehler

Fehlerantworten sind JSON mit einem maschinenlesbaren Code. Validierungsfehler enthalten zusätzlich Feldcodes im Objekt fields.

StatusCodeBedeutung
401NOT_AUTHENTICATEDAuthorization-Header fehlt, Token unbekannt oder rotiert.
403TOKEN_REVOKEDToken wurde widerrufen.
403SENDER_ARCHIVEDDer gebundene Absender ist archiviert.
403TENANT_LOCKEDDas Konto ist gesperrt.
403FEATURE_LOCKED / LIMIT_REACHED / NO_PACKAGEFeature nicht im Paket bzw. Paketlimit erreicht.
422VALIDATION_ERRORUngültiger Request. fields benennt die betroffenen Felder, z. B. { "client.name": "REQUIRED" }.
500SERVER_ERRORUnerwarteter 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.