Tutorials8 Min. Lesezeit

ZUGFeRD-Rechnungen aus Excel erstellen: VBA-Makro mit API-Anbindung

Schritt-für-Schritt-Anleitung: Excel-Rechnungen per VBA-Makro an die Vellonode API senden und als ZUGFeRD 2.4 PDF zurückbekommen. Funktioniert auf Windows und macOS.

VT

Vellonode Team

Redaktion

|

Warum Excel-Rechnungen ein E-Rechnungs-Problem haben

Viele kleine Unternehmen, Freelancer und Handwerksbetriebe erstellen ihre Rechnungen in Excel. Das funktioniert — bis der Kunde eine E-Rechnung im ZUGFeRD- oder XRechnung-Format verlangt. Spätestens seit der E-Rechnungspflicht für B2B ab 2025 wird das zum echten Problem.

Die naheliegende Lösung wäre, auf eine Rechnungssoftware umzusteigen. Aber wer mit Excel-Vorlagen arbeitet, hat oft gute Gründe dafür: individuelle Kalkulation, branchenspezifische Layouts oder schlicht die Gewohnheit eines eingespielten Workflows.

Die bessere Lösung: Excel behalten, E-Rechnung per API nachrüsten. Ein VBA-Makro exportiert die Rechnung als PDF und schickt sie an die Vellonode API. Zurück kommt ein validiertes ZUGFeRD 2.4 PDF — ohne Systemwechsel.

So funktioniert die Anbindung

Der Ablauf ist in drei Schritte aufgeteilt:

  1. Excel exportiert die Rechnung als PDF (über die eingebaute PDF-Export-Funktion)
  2. Ein VBA-Makro sendet das PDF an die API (per curl — auf Windows und macOS verfügbar)
  3. Die API liefert ein ZUGFeRD-PDF zurück (automatisch im Downloads-Ordner gespeichert)

Voraussetzungen

  • Ein Vellonode-Konto (kostenlos registrieren unter vellonode.de/auth/register)
  • Einen API-Key (unter Einstellungen → API im Dashboard erstellen)
  • Ihre Organization-ID (ebenfalls unter Einstellungen → API sichtbar, mit Kopier-Button)
  • Excel mit VBA-Unterstützung (Excel 2016 oder neuer, Windows und macOS)
  • Windows 10 oder neuer (curl ist vorinstalliert) bzw. macOS (curl ist vorinstalliert)

Windows 7/8/8.1? Das Makro benötigt curl, das erst ab Windows 10 vorinstalliert ist. Auf älteren Versionen können Sie curl manuell nachrüsten: Laden Sie die Windows-Version von curl.se/windows herunter und legen Sie die curl.exe in C:\Windows\System32. Danach funktioniert das Makro wie beschrieben.

VBA-Makro einrichten

  1. In Excel Alt + F11 drücken (öffnet den VBA-Editor)
  2. Im Projektfenster links: Rechtsklick auf das Arbeitsmappen-Projekt → Einfügen → Modul
  3. Den kompletten VBA-Code (siehe unten) in das neue Modul einfügen
  4. apiKey und orgId mit Ihren echten Werten ersetzen
  5. Datei als .xlsm (Makro-aktivierte Arbeitsmappe) speichern

Für einen Button: Entwicklertools → Einfügen → Schaltfläche → auf dem Blatt aufziehen → ExportAndConvert als Makro zuweisen. Falls der Reiter „Entwicklertools" fehlt: Datei → Optionen → Menüband anpassen → Entwicklertools aktivieren.

Kompletter VBA-Code

Der Code funktioniert auf Windows und macOS. Auf beiden Plattformen wird curl verwendet — die plattformspezifischen Unterschiede (Pfade, Shell-Aufrufe) werden automatisch über #If Mac Then behandelt.

Kopieren Sie den gesamten Code in ein einzelnes VBA-Modul:

Sub ExportAndConvert()
    Dim pdfPath As String

#If Mac Then
    pdfPath = Environ("HOME") & "/rechnung_export.pdf"
#Else
    pdfPath = Environ("TEMP") & "\rechnung_export.pdf"
#End If

    If Application.CountA(ActiveSheet.UsedRange) = 0 Then
        MsgBox "Das aktive Blatt ist leer."
        Exit Sub
    End If

    On Error Resume Next
    Kill pdfPath
    On Error GoTo 0

    ActiveSheet.ExportAsFixedFormat _
        Type:=xlTypePDF, _
        Filename:=pdfPath, _
        Quality:=xlQualityStandard, _
        OpenAfterPublish:=False

    If Dir(pdfPath) = "" Then
        MsgBox "PDF konnte nicht erzeugt werden. " & _
               "Bitte Druckbereich setzen unter " & _
               "Seitenlayout > Druckbereich."
        Exit Sub
    End If

    Call SendToVellonodeAPI(pdfPath)
End Sub

Sub SendToVellonodeAPI(pdfPath As String)
    Dim apiKey As String
    apiKey = "vk_live_IhrKeyHier"  ' API-Key aus dem Dashboard

    Dim orgId As String
    orgId = "IHRE_ORG_ID"  ' Organization-ID aus dem Dashboard

    Dim apiUrl As String
    apiUrl = "https://vellonode.de/api/v1/invoices/convert" _
           & "?organizationId=" & orgId

    Dim responsePath As String
    Dim scriptPath As String
    Dim dlFolder As String

#If Mac Then
    responsePath = Environ("HOME") & "/rechnung_response.json"
    scriptPath = Environ("HOME") & "/vellonode_upload.sh"
    dlFolder = "/Users/" & Environ("USER") & "/Downloads/"

    Open scriptPath For Output As #3
    Print #3, "#!/bin/bash"
    Print #3, "rm -f '" & responsePath & "'"
    Print #3, "curl -s -o '" & responsePath & "' \"
    Print #3, "  -X POST \"
    Print #3, "  -H 'Authorization: Bearer " & apiKey & "' \"
    Print #3, "  -F 'file=@" & pdfPath & "' \"
    Print #3, "  -F 'format=zugferd,json' \"
    Print #3, "  '" & apiUrl & "'"
    Close #3

    Shell "/bin/bash " & scriptPath
#Else
    responsePath = Environ("TEMP") & "\rechnung_response.json"
    scriptPath = Environ("TEMP") & "\vellonode_upload.bat"
    dlFolder = Environ("USERPROFILE") & "\Downloads\"

    Open scriptPath For Output As #3
    Print #3, "@echo off"
    Print #3, "del /f """ & responsePath & """ 2>nul"
    Print #3, "curl -s -o """ & responsePath & """ ^"
    Print #3, "  -X POST ^"
    Print #3, "  -H ""Authorization: Bearer " & apiKey & """ ^"
    Print #3, "  -F ""file=@" & pdfPath & """ ^"
    Print #3, "  -F ""format=zugferd,json"" ^"
    Print #3, "  """ & apiUrl & """"
    Close #3

    Shell "cmd /c """ & scriptPath & """", vbHide
#End If

    ' Warten bis curl fertig ist (max 60 Sekunden)
    Dim waitCount As Integer
    waitCount = 0
    Do While waitCount < 60
        Application.Wait Now + TimeValue("00:00:01")
        waitCount = waitCount + 1
        If Dir(responsePath) <> "" Then
            If FileLen(responsePath) > 0 Then Exit Do
        End If
    Loop

    If Dir(responsePath) = "" Or FileLen(responsePath) = 0 Then
        MsgBox "Zeitueberschreitung - keine Antwort vom Server." _
             & vbCrLf & "Bitte Internetverbindung und " _
             & "API-Key pruefen."
        Exit Sub
    End If

    ' JSON lesen
    Dim jsonData() As Byte
    Open responsePath For Binary As #2
    ReDim jsonData(LOF(2) - 1)
    Get #2, , jsonData
    Close #2
    Dim jsonStr As String
    jsonStr = StrConv(jsonData, vbUnicode)

    ' ZUGFeRD-URL extrahieren (PDF bevorzugt, Fallback auf XML)
    Dim fileStart As Long
    Dim zugferdExt As String
    fileStart = InStr(jsonStr, """zugferd_pdf""")
    If fileStart > 0 Then
        zugferdExt = ".pdf"
    Else
        fileStart = InStr(jsonStr, """zugferd_xml""")
        zugferdExt = ".xml"
    End If

    If fileStart = 0 Then
        MsgBox "Keine ZUGFeRD-Datei in der Antwort." _
             & vbCrLf & "Details: " & responsePath
        Exit Sub
    End If

    Dim urlStart As Long
    urlStart = InStr(fileStart, jsonStr, """url"":""") + 7
    Dim urlEnd As Long
    urlEnd = InStr(urlStart, jsonStr, """")
    Dim zugferdUrl As String
    zugferdUrl = Mid(jsonStr, urlStart, urlEnd - urlStart)

    ' ZUGFeRD-Datei herunterladen
    Dim tempDlPath As String
    Dim dlScriptPath As String

#If Mac Then
    tempDlPath = Environ("HOME") & "/rechnung_zugferd" _
               & zugferdExt
    dlScriptPath = Environ("HOME") & "/vellonode_download.sh"

    Open dlScriptPath For Output As #3
    Print #3, "#!/bin/bash"
    Print #3, "curl -s -o '" & tempDlPath _
            & "' '" & zugferdUrl & "'"
    Close #3

    Shell "/bin/bash " & dlScriptPath
#Else
    tempDlPath = Environ("TEMP") & "\rechnung_zugferd" _
               & zugferdExt
    dlScriptPath = Environ("TEMP") & "\vellonode_download.bat"

    Open dlScriptPath For Output As #3
    Print #3, "@echo off"
    Print #3, "curl -s -o """ & tempDlPath _
            & """ """ & zugferdUrl & """"
    Close #3

    Shell "cmd /c """ & dlScriptPath & """", vbHide
#End If

    ' Warten bis Download fertig
    waitCount = 0
    Do While waitCount < 30
        Application.Wait Now + TimeValue("00:00:01")
        waitCount = waitCount + 1
        If Dir(tempDlPath) <> "" Then
            If FileLen(tempDlPath) > 0 Then Exit Do
        End If
    Loop

    Dim savePath As String
    savePath = dlFolder & "rechnung_zugferd" & zugferdExt

    If Dir(tempDlPath) <> "" And FileLen(tempDlPath) > 0 Then
#If Mac Then
        ' Mac: per VBA aus Sandbox in Downloads kopieren
        Dim dlData() As Byte
        Open tempDlPath For Binary As #2
        ReDim dlData(LOF(2) - 1)
        Get #2, , dlData
        Close #2

        Open savePath For Binary As #2
        Put #2, , dlData
        Close #2
#Else
        ' Windows: binaer lesen und schreiben (FileCopy
        ' scheitert wenn curl die Datei noch sperrt)
        On Error Resume Next
        Kill savePath
        On Error GoTo 0

        Dim dlData() As Byte
        Open tempDlPath For Binary Access Read As #2
        ReDim dlData(LOF(2) - 1)
        Get #2, , dlData
        Close #2

        Open savePath For Binary As #2
        Put #2, , dlData
        Close #2
#End If
        MsgBox "ZUGFeRD-Datei gespeichert unter:" _
             & vbCrLf & savePath
    Else
        MsgBox "Download fehlgeschlagen." & vbCrLf _
             & "URL (24h gueltig):" & vbCrLf _
             & zugferdUrl
    End If
End Sub

Speichern Sie den API-Key niemals direkt im Makro-Code, wenn die Datei mit anderen geteilt wird. Besser: Den Key in einer separaten, geschützten Zelle oder einer Umgebungsvariable ablegen.

Das Ergebnis: Ein Button in Excel

Nach der Einrichtung haben Sie einen Button in Excel, der:

  1. Die aktuelle Rechnung als PDF exportiert
  2. Das PDF an die Vellonode API sendet
  3. Die fertige ZUGFeRD-Datei im Downloads-Ordner speichert

Der gesamte Vorgang dauert wenige Sekunden. Ihre Excel-Vorlage bleibt unverändert — die E-Rechnungsfähigkeit kommt durch die API.

Die API liefert bevorzugt ein ZUGFeRD-PDF zurück — ein PDF mit eingebetteter XML. Falls die PDF-Einbettung nicht möglich ist (z.B. bei unvollständigen Rechnungsdaten), wird automatisch die ZUGFeRD-XML heruntergeladen.

Hinweise für macOS

Auf macOS gelten einige Besonderheiten:

  • Excel-Sandbox: Dateien werden zunächst im internen Excel-Verzeichnis erzeugt und dann per VBA in den Downloads-Ordner kopiert
  • Falls macOS nach Ordnerzugriff fragt → Erlauben klicken
  • Das temporäre PDF wird im Arbeitsverzeichnis von Excel erzeugt, nur die fertige ZUGFeRD-Datei landet im Downloads-Ordner

Typischer Einsatz in der Praxis

Handwerksbetrieb mit individueller Kalkulation: Ein Elektroinstallateur kalkuliert Angebote und Rechnungen in Excel mit eigenen Formeln für Materialzuschläge, Fahrtkosten und Stundensätze. Das Layout ist über Jahre gewachsen und funktioniert. Mit dem VBA-Makro erzeugt er aus jeder Rechnung ein ZUGFeRD-PDF — ohne eine einzige Zelle zu ändern.

Freelancer mit Rechnungsvorlage: Eine Designerin nutzt eine schlichte Excel-Vorlage mit Logo, Positionen und Bankverbindung. Ihr größter Kunde (eine Behörde) verlangt XRechnung. Statt auf teure Software umzusteigen, schickt sie die PDF-Rechnung per Makro an die API und bekommt die XRechnung-XML zurück.

Grenzen und Alternativen

Das VBA-Makro funktioniert zuverlässig für den typischen Anwendungsfall: einzelne Rechnungen manuell konvertieren. Für höhere Volumina oder automatisierte Abläufe gibt es bessere Wege:

  • Power Automate / Microsoft Flow: Kann die API ohne VBA aufrufen, z.B. ausgelöst durch einen neuen Eintrag in einer SharePoint-Liste
  • Python-Script: Für Batch-Konvertierung mehrerer Dateien — die API akzeptiert denselben POST-Request
  • Direkte Integration: Wenn Sie ohnehin eine eigene Anwendung entwickeln, nutzen Sie die API direkt aus Ihrem Backend

Die vollständige API-Dokumentation finden Sie als OpenAPI 3.1 Spezifikation unter /api/v1/openapi. Dort sind alle Felder, Fehlercodes und Formate dokumentiert.

Passende Lösungen

Bleiben Sie informiert

Erhalten Sie die neuesten Artikel zu E-Rechnung, Buchhaltung und KI-Automatisierung direkt in Ihr Postfach.

Kein Spam, jederzeit abbestellbar. Datenschutzerklärung