Facturen via Peppol versturen met VBA of Visual Basic (VB6)

Wil je e-facturen via Peppol versturen vanuit Excel/Access (VBA) of VB6? In dit artikel lees je wat Peppol is, welke libraries je nodig hebt (o.a. VBA-Web van Tim Hall), hoe je een Peppol Certified Access Point (zoals Scrada) koppelt en krijg je voorbeeldcode om direct te starten.

Waarom VBA of Visual Basic?

Veel bedrijfsoplossingen zijn historisch gebouwd in VBA (Visual Basic for Applications) of Visual Basic 6 (VB6). Hoewel de IDE van VB6 niet meer wordt ondersteund, draaien de meeste VB6-applicaties nog steeds op moderne Windows-versies. VBA is nog altijd beschikbaar in Microsoft Excel en Access (ook op macOS), waardoor je bestaande oplossingen kunt uitbreiden.

Kort samengevat: VBA en VB6 delen dezelfde basis. Wat je in VBA bouwt, werkt vaak met minimale aanpassingen ook in VB6, en omgekeerd.

Wat is Peppol?

Peppol (Pan-European Public Procurement On-Line) is een Europees netwerk om gestandaardiseerd en veilig elektronische documenten (zoals e-facturen) uit te wisselen tussen bedrijven (B2B) en overheden (B2G). In België is een algemene B2B-e-factureringsverplichting vanaf 1 januari 2026 aangekondigd. Controleer altijd de actuele regelgeving voor jouw sector en land. Meer informatie over Peppol kun je terugvinden in onze Blog post ‘Wat is Peppol?‘ .

Benodigdheden (tooling & libraries)

  • Peppol Certified Access Point (AP): bijvoorbeeld Scrada. Je verzendt/ontvangt Peppol-documenten via hun API.
  • VBA-Web van Tim Hall: Maakt HTTP-requests, JSON opbouw/parsing en authenticatie in VBA eenvoudig. Werkt op Windows én Mac.
  • VBA-Dictionary van Tim Hall: Cross-platform Dictionary als alternatief voor Scripting.Dictionary (ActiveX) wat niet beschikbaar is op Mac.
  • (Optioneel) VB6: gebruik desnoods WinHTTP of MSXML2.ServerXMLHTTP voor HTTP-requests als je niet met VBA-Web werkt.

Werking in het kort (Peppol + API)

  1. Kies een Access Point (bijv. Scrada) en maak een (test)account aan.
  2. Haal je credentials op: Company ID, API key en eventueel wachtwoord.
  3. Installeer VBA-Web en voeg de modules toe aan je project (IWebAuthenticator, WebClient, WebRequest, WebResponse, WebHelpers).
  4. Bouw je e-factuur in object structuur van uw AP of maak uw eigen UBL 2.1/Peppol BIS (XML) bestand die je AP verwacht.
  5. POST je document via de API van je Access Point.
  6. Controleer de response (tracking, status, foutmeldingen).

Scrada als Peppol Certified Access Point

Scrada biedt twee API-varianten:

  • Peppol Only API – richt zich op ontwikkelaars die enkel een API nodig hebben om facturen op Peppol te plaatsen of af te halen.
  • Full API – naast Peppol-verzending ook fallback e-mail, doorsturen naar boekhoudpakketten, etc.

Extra voordeel: omdat het niet altijd vanzelfsprekend is om zelf een correcte UBL 2.1/Peppol BIS (XML) te maken, voorziet Scrada een eenvoudige manier om een object aan te maken dat door Scrada automatisch wordt omgezet naar een geldig Peppol BIS-bestand. Zo hoef je niet zelf alle XML-tags en -structuren op te bouwen, maar kun je in een eenvoudiger formaat werken.

Je kunt een Peppol Only account aanvragen via info@scrada.be of je registreren via https://my.scrada.be voor de full-variant. Toegang tot testomgevingen (verbonden met de Peppol-testomgeving) kun je ook aanvragen via info@scrada.be.

Na registratie vind je:

  • API key en wachtwoord via Menu → Instellingen → API Keys
  • Company ID via Menu → Instellingen → Bedrijf

Op onze postman pagina https://www.postman.com/scrada/overview/overview kunnen verschillende voorbeelden gevonden worden van het gebruik van onze API zoals versturen via API, ontvangen via API, verstuurde UBL bestanden downloaden, …

Voorbeeld: Factuur via Peppol versturen met VBA (Excel/Access)

Constanten definiëren

We definiëren 3 constanten om onze CompanyID, API Key en wachtwoord in te bewaren:

Public Const COMPANY_ID_SCRADA = ""
Public Const API_KEY_SCRADA = ""
Public Const PASSWORD_SCRADA = ""

Factuur versturen via Peppol (Peppol Only)

Maken we gebruik van de Peppol Only versie, dan kan de code om een factuur te versturen via Peppol er als volgt uitzien:

'https://www.scrada.be/api-documentation/#tag/Peppol-outbound/paths/~1v1~1company~1%7BcompanyID%7D~1peppol~1outbound~1salesInvoice/post
    Dim wClient As New WebClient
    wClient.BaseUrl = "https://apitest.scrada.be/v1/company/" & COMPANY_ID_SCRADA & "/peppol/outbound/salesInvoice"

    Dim req As New WebRequest
    req.Resource = "" 'Base URL already set
    req.Method = HttpPost
    req.Format = json

    ' Add Authorization header
    req.AddHeader "X-API-KEY", API_KEY_SCRADA
    req.AddHeader "X-PASSWORD", PASSWORD_SCRADA

    'Build JSON invoice object
    Dim invoiceObject As Dictionary
    Set invoiceObject = BuildInvoiceJsonPeppol(False)

    ' Send request
    ' This will send the invoice to Scrada API that will put the invoice on Peppol.
    ' This is done async so we have to call the status of the invoice to know if already sent on Peppol or that there was an issue.
    Set req.Body = invoiceObject
    Dim res As WebResponse
    Set res = wClient.Execute(req)

    ' Handle response
    If Not res Is Nothing Then
        If res.StatusCode >= 200 And res.StatusCode < 300 Then
            ' The content of the response contains the ID of the invoice at Scrada
            s_lastSendInvoiceIDPeppolOnly = Replace(res.Content, """, "")
            MsgBox "Invoice successfully sent. Received ID of invoice is " & res.Content, vbInformation
        Else
            MsgBox "Error sending invoice. Status: " & res.StatusCode & vbCrLf & res.Content, vbCritical
        End If
    Else
        MsgBox "Error sending invoice. No message received from Scrada.", vbCritical
    End If

Status van een factuur opvragen

Bij ontvangst van een factuur gaat Scrada deze niet onmiddellijk op Peppol plaatsen. Daarom ontvang je bij afleveren van de factuur een ID en deze ID kun je gebruiken om nadien de status op te vragen:

'https://www.scrada.be/api-documentation/#tag/Peppol-outbound/paths/~1v1~1company~1%7BcompanyID%7D~1peppol~1outbound~1document~1%7BdocumentID%7D~1info/get
    Dim wClient As New WebClient
    wClient.BaseUrl = "https://apitest.scrada.be/v1/company/" & COMPANY_ID_SCRADA & "/peppol/outbound/document/" & s_lastSendInvoiceIDPeppolOnly & "/info"

    Dim req As New WebRequest
    req.Resource = "" 'Base URL already set
    req.Method = HttpGet
    req.Format = json

    ' Add Authorization header
    req.AddHeader "X-API-KEY", API_KEY_SCRADA
    req.AddHeader "X-PASSWORD", PASSWORD_SCRADA

    ' Do API call
    Dim res As WebResponse
    Set res = wClient.Execute(req)

    ' Handle response
    If Not res Is Nothing Then
        If res.StatusCode >= 200 And res.StatusCode < 300 Then
            Dim status As String
            status = res.Data("status")
            
            If status = "Created" Then
                MsgBox "Scrada will pickup the invoice soon to send it over Peppol", vbInformation
            ElseIf status = "Processed" Then
                MsgBox "The invoice is sent over Peppol to access point with seat ID " & res.Data("peppolC3SeatID") & ". The reception ID of that access point is " & res.Data("peppolC3MessageID"), vbInformation
            ElseIf status = "Retry" Then
                MsgBox "There was an issue (" & res.Data("errorMessage") & ") when sending invoice over Peppol. Scrada will retry to send it. This is retry " & res.Data("attempt"), vbExclamation
            Else
                MsgBox "Error when sending invoice over Peppol. Status: " & status & vbCrLf & "Error: " & res.Data("errorMessage"), vbCritical
            End If
        Else
            MsgBox "Error getting status of invoice. Status: " & res.StatusCode & vbCrLf & res.Content, vbCritical
        End If
    Else
        MsgBox "Error getting status of invoice. No feedback received from Scrada.", vbCritical
    End If
    Exit Sub

Voorbeeldfunctie: BuildInvoiceJsonPeppol

In het voorbeeld hierboven wordt de factuur opgebouwd door de functie BuildInvoiceJsonPeppol. Hieronder ziet u hoe deze functie eruit kan zien.

Private Function BuildInvoiceJsonPeppol(buildForFullVersion As Boolean) As Dictionary
    Dim inv   As Object: Set inv = New Dictionary
    
    ' Invoice header
    If buildForFullVersion Then
        'The full version need also the property bookYear and journal to identify an invoice unique
        inv.Add "bookYear", ""
        inv.Add "journal", ""
    End If
    inv.Add "number", "test-json-invoice-scrada-2"
    inv.Add "externalReference", "DB_1|46a5e373-4337-4d68-92be-30ec6d2c7d98"
    inv.Add "creditInvoice", False
    inv.Add "invoiceDate", "2024-12-20"
    inv.Add "invoiceExpiryDate", "2024-12-25"
    inv.Add "buyerReference", "0150abc"

    'The full version does not need a supplier because for every supplier a company is created in Scrada and that company is used as supplier info
    If (Not buildForFullVersion) Then
        ' Supplier
        Dim sup    As Object: Set sup = New Dictionary
        sup.Add "peppolID", "9915:test-sender"
        sup.Add "name", "SupplierTradingName BV"
        
        Dim supAdr As Object: Set supAdr = New Dictionary
        supAdr.Add "street", "Main street"
        supAdr.Add "streetNumber", "1"
        supAdr.Add "streetBox", ""
        supAdr.Add "city", "Antwerpen"
        supAdr.Add "zipCode", "2000"
        supAdr.Add "countrySubentity", ""
        supAdr.Add "countryCode", "BE"
        sup.Add "address", supAdr
        
        sup.Add "vatStatus", 1
        sup.Add "legalPersonRegister", "RPR Antwerpen"
        sup.Add "vatNumber", "BE0000000097"
    
        ' Supplier extraIdentifiers (array)
        Dim extraIds As New Collection
        Dim extraId1 As Object: Set extraId1 = New Dictionary
        extraId1.Add "identifier", "ITAA nummmer: 155554"
        extraIds.Add extraId1
        sup.Add "extraIdentifiers", extraIds
        inv.Add "supplier", sup
    End If

    ' Customer
    Dim cust   As Object: Set cust = New Dictionary
    cust.Add "name", "Scrada BV"
    
    Dim custAdr As Object: Set custAdr = New Dictionary
    custAdr.Add "street", "Unknown street"
    custAdr.Add "streetNumber", "32"
    custAdr.Add "streetBox", "5"
    custAdr.Add "city", "Sint-Lievens-Houtem"
    custAdr.Add "zipCode", "9521"
    custAdr.Add "countryCode", "BE"
    cust.Add "address", custAdr
    
    cust.Add "vatNumber", "BE0793904121" 'The vat number of Scrada is used so that this test invoice will be delivered to Scrada
    inv.Add "customer", cust

    ' Delivery
    Dim deliv  As Object: Set deliv = New Dictionary
    deliv.Add "deliveryDate", "2024-12-23"
    
    Dim delAdr As Object: Set delAdr = New Dictionary
    delAdr.Add "street", "Delivery street"
    delAdr.Add "streetNumber", "2"
    delAdr.Add "city", "Gent"
    delAdr.Add "zipCode", "9000"
    delAdr.Add "countryCode", "BE"
    deliv.Add "address", delAdr
    
    inv.Add "delivery", deliv

    ' Invoice totals
    inv.Add "totalExclVat", 1302.45
    inv.Add "totalInclVat", 1575.65
    inv.Add "totalVat", 273.2
    inv.Add "currency", "EUR"
    inv.Add "payableRoundingAmount", 0.05

    ' Invoice lines (array)
    Dim lines As New Collection
    Dim ln As Dictionary

    ' Invoice line 1
    Set ln = New Dictionary
    ln.Add "lineNumber", "1"
    ln.Add "itemName", "item name"
    ln.Add "quantity", 7
    ln.Add "unitType", 103
    ln.Add "itemExclVat", 400.05
    ln.Add "vatType", 1
    ln.Add "vatPercentage", 21
    ln.Add "totalDiscountExclVat", 0
    ln.Add "totalExclVat", 2800.35
    lines.Add ln

    ' Invoice line 2
    Set ln = New Dictionary
    ln.Add "lineNumber", "2"
    ln.Add "itemName", "item name 2"
    ln.Add "quantity", -3
    ln.Add "unitType", 103
    ln.Add "itemExclVat", 500
    ln.Add "vatType", 1
    ln.Add "vatPercentage", 21
    ln.Add "totalDiscountExclVat", 0
    ln.Add "totalExclVat", -1500
    lines.Add ln

    ' Invoice line 3
    Set ln = New Dictionary
    ln.Add "lineNumber", "3"
    ln.Add "itemName", "item name 3"
    ln.Add "quantity", 2.0096
    ln.Add "unitType", 202
    ln.Add "itemExclVat", 0.5242
    ln.Add "vatType", 1
    ln.Add "vatPercentage", 6
    ln.Add "totalDiscountExclVat", 0
    ln.Add "totalExclVat", 1.05
    lines.Add ln

    ' Invoice line 4
    Set ln = New Dictionary
    ln.Add "lineNumber", "4"
    ln.Add "itemName", "item name 4"
    ln.Add "quantity", 2.0096
    ln.Add "unitType", 202
    ln.Add "itemExclVat", 0.5242
    ln.Add "vatType", 1
    ln.Add "vatPercentage", 6
    ln.Add "totalDiscountExclVat", 0
    ln.Add "totalExclVat", 1.05
    lines.Add ln

    inv.Add "lines", lines

    ' Invoice vatTotals (array)
    Dim vatTotals As New Collection
    Dim vt As Dictionary

    ' vat total 21%
    Set vt = New Dictionary
    vt.Add "vatType", 1
    vt.Add "vatPercentage", 21
    vt.Add "totalExclVat", 1300.35
    vt.Add "totalVat", 273.07
    vt.Add "totalInclVat", 1573.42
    vatTotals.Add vt

    ' vat total 6%
    Set vt = New Dictionary
    vt.Add "vatType", 1
    vt.Add "vatPercentage", 6
    vt.Add "totalExclVat", 2.1
    vt.Add "totalVat", 0.13
    vt.Add "totalInclVat", 2.23
    vatTotals.Add vt

    inv.Add "vatTotals", vatTotals

    ' paymentTerms
    inv.Add "paymentTerms", "Payment within 5 days"

    ' paymentMethods (array)
    Dim pms As New Collection
    Dim pm As Dictionary: Set pm = New Dictionary
    pm.Add "paymentType", 2
    pm.Add "paymentReference", "Snippet1"
    pm.Add "name", "AccountName"
    pm.Add "iban", "BE39900000010119"
    pm.Add "bic", "GNOMBEBB"
    pm.Add "totalPaid", 0
    pm.Add "totalToPay", 1575.7   ' JSON doesn't require trailing zero; value = 1575.70
    pms.Add pm
    inv.Add "paymentMethods", pms

    ' attachments (array)
    Dim atts As New Collection
    Dim att As Object: Set att = New Dictionary
    att.Add "filename", "invoice.pdf"
    att.Add "fileType", 1
    att.Add "mimeType", "application/pdf"
    att.Add "base64Data", "test" 'A correct base 64 must be put here if you want to add a PDF of the invoice as attachment
    att.Add "note", "Invoice"
    atts.Add att
    inv.Add "attachments", atts

    ' return invoice
    Set BuildInvoiceJsonPeppol = inv
End Function

Zoals u kunt zien kunt u zeer eenvoudig in VB6 (Visual Basic 6) of in VBA-toepassingen de functionaliteit toevoegen om facturen of documenten via Peppol te versturen. Heb je nog vragen over Peppol of hoe je dit kunt doen, neem gerust contact op met ons.

Werkend voorbeeld

Een werkend voorbeeld Excel bestand kan gedownload worden via volgende link.

Veelgemaakte valkuilen & tips

  • Formaat en validatie: zorg dat je UBL/Peppol-document valideert tegen het juiste BIS-profiel van je klant/land of maak gebruik van bijvoorbeeld Scrada object als je zelf de XML niet wil bouwen.
  • Identifier van de ontvanger: gebruik de juiste Peppol-identifier (scheme + nummer, bv. Belgisch btw-nummer). Als je gebruik maakt van het Scrada object dan wordt automatisch door Scrada de juiste Peppol-identifier bepaald adhv van de informatie dat je op klant niveau hebt voorzien.
  • Test vs productie: start in de testomgeving (test endpoints/keys) en schakel pas om naar productie als de flow stabiel is.
  • Foutafhandeling: log statuscodes en response-body.
  • Beveiliging: hard-code nooit secrets in je code; haal ze uit een versleutelde store of environment-variabelen.

FAQ (korte antwoorden)

Werkt dit op Mac?

Ja, VBA-Web en VBA-Dictionary werken op macOS. VB6 is Windows-only, maar VBA in Excel/Access draait ook op Mac.

Moet ik per se UBL-XML maken?

Voor Peppol doorgaans wel. Sommige Access Points accepteren ook JSON en zetten dit om naar UBL, maar controleer de documentatie van je AP. Bij Scrada kun je kiezen of je uw eigen UBL maakt of gebruik maakt van Scrada object dat door Scrada wodt omgezet naar juiste UBL formaat.

Is Peppol verplicht in België?

Er is een B2B-verplichting aangekondigd vanaf 1 januari 2026.

Kan ik in naam van mijn klanten verzenden?

Ja, via een Peppol Only API kun je als softwarebouwer documenten in naam van je klanten plaatsen/afhalen. Je hebt wel toestemming nodig van uw klant om dit te mogen doen.

Welke libraries heb ik nodig in VBA?

We raden VBA-Web aan. Aanvullend VBA-Dictionary voor een cross-platform Dictionary.

Try the demo

Give us a call or fill in the form below and we'll contact you. We endeavor to answer all inquiries within 24 hours on business days.