{"openapi":"3.1.0","info":{"title":"VelloNode E-Rechnung API","version":"1.0.0","description":"API für die Konvertierung von PDF-Rechnungen in strukturierte Formate (ZUGFeRD 2.4, XRechnung, JSON, DATEV).","contact":{"name":"VelloNode Support","url":"https://vellonode.de"}},"servers":[{"url":"https://vellonode.de","description":"Production"}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/organizations":{"get":{"operationId":"listOrganizations","summary":"Organisationen auflisten","description":"Gibt alle Organisationen zurück, auf die der API-Key-Inhaber Zugriff hat. Die zurückgegebene ID wird als organizationId-Parameter bei der Rechnungskonvertierung benötigt.","responses":{"200":{"description":"Liste der Organisationen","content":{"application/json":{"schema":{"type":"object","properties":{"organizations":{"type":"array","items":{"$ref":"#/components/schemas/Organization"}}}}}}},"401":{"description":"Ungültiger API-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me":{"get":{"operationId":"getMe","summary":"Eigenes Benutzerprofil","description":"Gibt Informationen zum Benutzer zurück, dem der API-Key gehört. Enthält den zuletzt genutzten Login-Provider (nützlich für idp_hint).","responses":{"200":{"description":"Benutzerprofil","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"name":{"type":"string","nullable":true},"lastProvider":{"type":"string","description":"Zuletzt genutzter Login-Provider (google, microsoft-entra-id, credentials)","example":"google"}}}}}}}},"401":{"description":"Ungültiger API-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"revokeCurrentApiKey","summary":"Aktuellen API-Key widerrufen","description":"Widerruft den API-Key, der im Authorization-Header übergeben wurde. Nützlich für Logout-Flows in OAuth-Integrationen.","responses":{"200":{"description":"Key erfolgreich widerrufen","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"API-Key widerrufen."}}}}}},"401":{"description":"Ungültiger API-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/invoices/convert":{"post":{"operationId":"convertInvoice","summary":"Rechnung konvertieren (PDF, XLSX, DOCX)","description":"Extrahiert Rechnungsdaten aus einer Datei und konvertiert sie in das gewünschte Format. Unterstützte Eingabeformate: PDF, XLSX (Excel) und DOCX (Word) — Office-Dateien werden serverseitig zu PDF gerendert. Bei format=zugferd werden sowohl die XML-Datei als auch ein PDF/A-3 mit eingebettetem XML geliefert. Die organizationId ist ein Pflichtparameter — verfügbare Organisationen können über GET /api/v1/organizations abgerufen werden.\n\nDie Rechnung wird zusätzlich in der Anwendung abgelegt und erscheint unter /app/invoices — mit Richtungserkennung, Geschäftspartner- und Artikel-Zuordnung wie bei einem Upload über die Oberfläche. Das Ergebnis der Ablage steht im Feld \"stored\". Mit persist=false lässt sich die Ablage je Request abschalten; die Konvertierung zählt auch dann gegen das Monatskontingent. Die Organisation kann die Ablage außerdem dauerhaft abwählen (Einstellungen → API-Zugang) — diese Vorgabe wirkt nur einschränkend, ein persist=true im Request hebt sie nicht auf.\n\nBei format=zugferd wird die ausgelieferte hybride PDF zusammen mit ihrem XML als Dokument archiviert (\"stored.archived\") — dieselbe Regel wie beim Versand aus der Anwendung: Eine E-Rechnung, die herausgegeben wird, ist vorher abgelegt. Die Download-URLs unter \"files\" verfallen nach 24 Stunden; für die Aufbewahrung ist das archivierte Dokument maßgeblich.","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"string"},"description":"ID der Organisation (abrufbar über GET /api/v1/organizations)"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Rechnungsdatei (max. 10 MB). Unterstützte Formate: PDF (.pdf), Excel (.xlsx), Word (.docx). Office-Dateien werden serverseitig zu PDF konvertiert."},"format":{"type":"string","default":"zugferd","description":"Ausgabeformat(e), kommagetrennt: zugferd, xrechnung, json, datev","example":"zugferd,json"},"direction":{"type":"string","enum":["incoming","outgoing"],"description":"Rechnungsrichtung: incoming (Eingangsrechnung) oder outgoing (Ausgangsrechnung). Optional — wird z. B. für DATEV-Kontenzuordnung verwendet. Die in der Anwendung abgelegte Rechnung erhält ihre Richtung aus der automatischen Erkennung.","example":"incoming"},"validate":{"type":"string","enum":["kosit","none"],"default":"kosit","description":"Prüfung mit dem offiziellen KoSIT-Validator. Standardmäßig an. none überspringt sie; validation.acceptanceLevel meldet dann NICHT_GEPRUEFT."},"persist":{"type":"string","enum":["true","false"],"default":"true","description":"Ablage der Rechnung in der Anwendung. false konvertiert nur — die Rechnung erscheint dann nicht unter /app/invoices und die Download-URLs verfallen nach 24 Stunden. true ist die Vorgabe, kann die Einstellung der Organisation aber nicht überstimmen: Hat sie die Ablage abgewählt, bleibt es dabei (stored.status = skipped, Grund in stored.message).","example":"true"}}}}}},"responses":{"200":{"description":"Erfolgreiche Konvertierung","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversionResponse"}}}},"400":{"description":"Ungültige Anfrage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Ungültiger API-Key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Kontingent aufgebraucht","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuotaExceededResponse"}}}},"413":{"description":"Datei zu groß","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Nicht unterstützter Dateityp (nur PDF, XLSX, DOCX)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Extraktion oder Office-Konvertierung fehlgeschlagen (extraction_failed, office_conversion_failed) — oder die Rechnung wurde gelesen, es fehlen aber Pflichtangaben nach EN16931 (invoice_incomplete). Im letzten Fall nennt \"missingFields\" die fehlenden Felder; die Rechnung ist trotzdem abgelegt (\"stored\") und lässt sich in der Anwendung vervollständigen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IncompleteInvoiceResponse"}}}},"429":{"description":"Rate-Limit erreicht (max. 30 Anfragen pro Minute pro API-Key)","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Sekunden bis zum nächsten erlaubten Request"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Interner Serverfehler","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/files/{token}":{"get":{"operationId":"downloadFile","summary":"Konvertierte Datei herunterladen","description":"Lädt eine konvertierte Datei herunter. Links sind 24 Stunden gültig.","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"},"description":"Download-Token aus der Konvertierungs-Response"}],"responses":{"200":{"description":"Datei-Download"},"404":{"description":"Datei nicht gefunden"},"410":{"description":"Download-Link abgelaufen"}},"security":[]}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API-Key im Format vk_live_... — erstellen unter /app/settings/api"}},"schemas":{"Organization":{"type":"object","properties":{"id":{"type":"string","description":"Organisation-ID (für organizationId-Parameter)"},"name":{"type":"string"},"vatId":{"type":"string","nullable":true,"description":"USt-IdNr."},"role":{"type":"string","enum":["admin","member"]},"plan":{"type":"string","description":"Aktueller Plan (free, starter, pro, max, enterprise)"},"subscriptionStatus":{"type":"string"},"invoiceLimit":{"type":"integer","nullable":true,"description":"Monatliches Rechnungslimit (null = unbegrenzt)"}}},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}}},"QuotaExceededResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"quota_exceeded"},"message":{"type":"string"}},"required":["code","message"]},"usage":{"type":"object","description":"Aktueller Verbrauch zur Diagnose","properties":{"used":{"type":"integer","description":"Verbrauchte Einheiten im aktuellen Monat"},"limit":{"type":"integer","nullable":true,"description":"Monatliches Limit"}},"required":["used","limit"]}}},"IncompleteInvoiceResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"invoice_incomplete"},"message":{"type":"string"}}},"missingFields":{"type":"array","items":{"type":"string"},"description":"Fehlende Pflichtangaben nach EN16931 — nur bei code = invoice_incomplete.","example":["BT-1: Rechnungsnummer fehlt","Position 1: BT-152 Umsatzsteuersatz der Rechnungsposition fehlt"]},"stored":{"type":"object","description":"Die Rechnung ist trotzdem abgelegt und lässt sich in der Anwendung vervollständigen — dieselbe Datei nicht erneut senden."}}},"ConversionResponse":{"type":"object","properties":{"id":{"type":"string","example":"conv_a1b2c3d4e5f6..."},"data":{"$ref":"#/components/schemas/InvoiceData"},"validation":{"type":"object","properties":{"valid":{"type":"boolean"},"acceptanceLevel":{"type":"string","enum":["ACCEPTABLE","WARNING","REJECT","NICHT_GEPRUEFT"],"description":"Urteil des offiziellen KoSIT-Validators. NICHT_GEPRUEFT heißt: KoSIT stand nicht bereit oder wurde über validate=none abgewählt — dann stammt \"valid\" nur aus den eingebauten Regeln und sagt weniger aus."},"profile":{"type":"string","enum":["EN16931","XRechnung 3.0","ZUGFeRD 2.4 (EN16931)"],"description":"Geprüftes Profil. Bei format=xrechnung wird zusätzlich gegen XRechnung geprüft (Leitweg-ID BT-10, EAS-Codes, Verkäufer-Kontaktdaten BR-DE-2/6/7). Diese Befunde führen nicht zu einem Fehler — die Datei wird geliefert und die fehlenden Angaben stehen in errors.","example":"EN16931"},"errors":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","example":"BR-01"},"message":{"type":"string"},"field":{"type":"string","nullable":true}}}}}},"files":{"type":"object","description":"Download-URLs nach Format. Bei zugferd: zugferd_xml + zugferd_pdf.","additionalProperties":{"type":"object","properties":{"url":{"type":"string","format":"uri"}}},"example":{"zugferd_xml":{"url":"https://vellonode.de/api/v1/files/abc..."},"zugferd_pdf":{"url":"https://vellonode.de/api/v1/files/def..."}}},"stored":{"type":"object","description":"Ergebnis der Ablage in der Anwendung.","properties":{"status":{"type":"string","enum":["saved","duplicate","processing","skipped","failed"],"description":"saved = Rechnung(en) angelegt · duplicate = Datei war bereits abgelegt · processing = wird gerade von einem parallelen Request verarbeitet · skipped = nicht abgelegt (persist=false oder in den Einstellungen der Organisation abgewählt — Grund in message) · failed = Ablage fehlgeschlagen (siehe message)"},"documentId":{"type":"string","nullable":true,"description":"ID des abgelegten Dokuments"},"invoiceIds":{"type":"array","items":{"type":"string"},"description":"IDs der angelegten Rechnungen, abrufbar unter /app/invoices/{id}"},"archived":{"type":"boolean","description":"Die herausgegebene ZUGFeRD-PDF wurde samt XML als Dokument archiviert. Fehlt, wenn keine ZUGFeRD-PDF angefordert war."},"message":{"type":"string","nullable":true,"description":"Grund, falls nicht abgelegt wurde"}},"example":{"status":"saved","documentId":"clx1234567890","invoiceIds":["clx0987654321"],"archived":true}},"usage":{"type":"object","properties":{"used":{"type":"integer","description":"Verbrauchte Einheiten im aktuellen Monat"},"limit":{"type":"integer","nullable":true,"description":"Monatliches Limit (null = unbegrenzt)"}}}}},"InvoiceData":{"type":"object","properties":{"invoiceNumber":{"type":"string","nullable":true,"description":"BT-1"},"invoiceDate":{"type":"string","nullable":true,"description":"BT-2 (ISO 8601)"},"dueDate":{"type":"string","nullable":true,"description":"BT-9 (ISO 8601)"},"currency":{"type":"string","example":"EUR","description":"BT-5 (ISO 4217)"},"invoiceType":{"type":"string","nullable":true,"description":"BT-3 (380=Rechnung, 381=Gutschrift)"},"buyerReference":{"type":"string","nullable":true,"description":"BT-10 (Leitweg-ID)"},"paymentTerms":{"type":"string","nullable":true,"description":"BT-20"},"paymentReference":{"type":"string","nullable":true,"description":"BT-83 (Verwendungszweck)"},"iban":{"type":"string","nullable":true,"description":"BT-84"},"bic":{"type":"string","nullable":true,"description":"BT-86"},"paymentMeansCode":{"type":"string","nullable":true,"example":"58","description":"BT-81 Zahlungsart (UNTDID 4461): 58 SEPA-Überweisung, 59 SEPA-Lastschrift, 48/54/55 Karte, 68 Online-Zahlungsdienst, 10 bar. Derselbe Wert wie im erzeugten XML; nennt der Beleg keine, wird sie aus IBAN bzw. Mandatsreferenz abgeleitet."},"paymentMeansText":{"type":"string","nullable":true,"description":"BT-82 Zahlungsart als Text"},"seller":{"type":"object","properties":{"name":{"type":"string","nullable":true},"vatId":{"type":"string","nullable":true,"description":"USt-IdNr."},"taxNumber":{"type":"string","nullable":true},"address":{"type":"object","nullable":true,"properties":{"street":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"postalCode":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true,"description":"ISO 3166-1 alpha-2"}}},"contact":{"type":"object","nullable":true,"properties":{"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}}}}},"buyer":{"type":"object","properties":{"name":{"type":"string","nullable":true},"vatId":{"type":"string","nullable":true,"description":"USt-IdNr."},"taxNumber":{"type":"string","nullable":true},"address":{"type":"object","nullable":true,"properties":{"street":{"type":"string","nullable":true},"city":{"type":"string","nullable":true},"postalCode":{"type":"string","nullable":true},"country":{"type":"string","nullable":true},"countryCode":{"type":"string","nullable":true,"description":"ISO 3166-1 alpha-2"}}},"contact":{"type":"object","nullable":true,"properties":{"name":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}}}}},"lines":{"type":"array","items":{"type":"object","properties":{"description":{"type":"string","nullable":true},"quantity":{"type":"number","nullable":true},"unit":{"type":"string","nullable":true,"description":"UN/ECE Rec. 20/21 Code"},"unitPrice":{"type":"number","nullable":true,"description":"Netto-Einzelpreis"},"vatRate":{"type":"number","nullable":true,"description":"Steuersatz in %"},"netAmount":{"type":"number","nullable":true},"grossAmount":{"type":"number","nullable":true}}}},"taxBreakdown":{"type":"array","items":{"type":"object","properties":{"rate":{"type":"number","description":"Steuersatz in %"},"taxableAmount":{"type":"number"},"taxAmount":{"type":"number"}}}},"totals":{"type":"object","properties":{"netTotal":{"type":"number","nullable":true,"description":"BT-109"},"vatAmount":{"type":"number","nullable":true,"description":"BT-110"},"grossTotal":{"type":"number","nullable":true,"description":"BT-112"}}},"skonto":{"type":"array","nullable":true,"items":{"type":"object","properties":{"percentage":{"type":"number","nullable":true},"days":{"type":"number","nullable":true},"discountedAmount":{"type":"number","nullable":true}}}}}}}}}