Hagemeister Conception

E-Rechnungen in FileMaker erstellen

Praxisanleitung von Rechnungs-JSON und Schema-Response bis zu XML, PDF/A-3 und abschließender Validierung.

Der eingesetzte Mikro-Webdienst speichert keine Rechnungsdaten; sie werden ausschließlich im flüchtigen RAM-Arbeitsspeicher verarbeitet. Die Nicht-Speicherung der Rechnungsdaten wird vertraglich zugesichert.

Anleitung: E-Rechnungen in FileMaker erstellen

Rechnungsdaten → XML erzeugen → ggf. PDF/A-3 erzeugen → validieren → erst dann versenden

Das folgende Muster erzeugt aus FileMaker-Rechnungsdaten ein strukturiertes Rechnungs-XML und optional aus XML und Sicht-PDF eine hybride PDF/A-3-Datei. Die erzeugte Rechnung muss vor dem Versand abschließend validiert werden.

Alle Codebeispiele verwenden englische FileMaker-Scriptschritte und -Optionen. Tabellenauftreten, Feldnamen und sichtbare Dialogtexte bleiben lösungsspezifisch.

Wichtig: URLs, Modellnamen und Zugangsdaten sind Platzhalter. Speichern Sie API-Schlüssel geschützt und aktivieren Sie bei jedem HTTPS-Aufruf Verify SSL Certificates.
Abschließende Validierung erforderlich: Eine technisch erfolgreich erzeugte XML- oder PDF/A-3-Datei ist noch nicht automatisch eine gültige E-Rechnung. Validieren Sie das Ergebnis vor dem Versand gegen Schema, Profil und Geschäftsregeln. Die Umsetzung in FileMaker beschreibt die Anleitung zum E-Rechnungsvalidierer und zur Visualisierung.

1. Ablauf und Voraussetzungen

FileMaker-Daten
  -> Rechnungs-JSON
  -> API-Aufruf 1
  <- Rechnungs-XML
  -> XML + Sicht-PDF als Base64
  -> API-Aufruf 2
  <- PDF/A-3 als Base64
  -> abschließende Validierung
FeldTypVerwendung
Rechnungen::ErstellungsRequestTextoptional: gesendetes Rechnungs-JSON
Rechnungen::ERechnungXMLContainererzeugte strukturierte Rechnung
Rechnungen::SichtPDFContainersichtbares Rechnungs-PDF
Rechnungen::PDF_A_3Containerfertige hybride PDF/A-3-Datei
Rechnungen::API_AntwortTextvollständige Antwort des letzten API-Aufrufs
Rechnungen::ErstellungsstatusTexttechnischer und fachlicher Gesamtstatus
Rechnungen::ValidierungsberichtText/Containervollständiger Validierungsbericht

In der Beispielimplementierung werden unter anderem diese Modelle verwendet:

ModellVerwendung
Facturxen16931Factur-X/ZUGFeRD auf Basis von EN 16931
Ubl21UBL 2.1 Invoice
Ubl21cnUBL 2.1 Credit Note
Cii16buncoupledUN/CEFACT CII D16B, uncoupled
Cii16bcoupledUN/CEFACT CII D16B, coupled

Wichtiger Unterschied zwischen EN16931 und EXTENDED:

ZUGFeRD/Factur-X gibt es in der aktuellen Version 2.5.2 auch im Profil EXTENDED. Dieses Profil basiert auf EN 16931, geht aber über deren semantisches Datenmodell hinaus und ermöglicht zusätzliche Strukturen und Kardinalitäten. Während bestimmte Elemente im EN16931-Profil nur einmal vorkommen können, sind sie im EXTENDED-Profil als wiederholbare Elemente abgebildet.

Dazu gehören unter anderem:

  • applicable_trade_tax
  • defined_trade_contact
  • specified_trade_payment_terms

Das ist ein wichtiger Unterschied für die technische Umsetzung: EXTENDED ist nicht einfach EN16931 mit einigen zusätzlichen Feldern.

Der Webdienst kann Rechnungen in diesem Profil über den separaten Endpunkt POST <API-BASIS-URL>/Facturxextended erzeugen.

2. Schema-Elemente abrufen

Der Schema-Endpunkt liefert die technisch verfügbaren XML- und JSON-Pfade sowie die erwarteten Datentypen. Er ersetzt nicht die fachliche Dokumentation des gewählten Rechnungsprofils. Das Vorhandensein eines Elements im Schema bedeutet nicht, dass es im jeweiligen Geschäftsfall zulässig, erforderlich oder ausreichend ist.

GET <API-BASIS-URL>/<SCHEMA-ENDPUNKT>/<MODELLNAME>
Accept: application/json
x-api-key: <API-KEY>

1Schema abrufen

Set Error Capture [ On ]
Allow User Abort [ Off ]

Set Variable [ $schemaName ; Value: "Facturxen16931" ]
Set Variable [ $apiKey ; Value: Einstellungen::API_Key ]
Set Variable [ $url ; Value:
    "<API-BASIS-URL>/<SCHEMA-ENDPUNKT>/" & $schemaName
]
Set Variable [ $schemaResponse ; Value: "" ]
Set Variable [ $responseHeaders ; Value: "" ]

Set Variable [ $curlOptions ; Value:
    "--request GET" & ¶ &
    "--header " & Quote ( "Accept: application/json" ) & ¶ &
    If ( not IsEmpty ( $apiKey ) ;
        "--header " & Quote ( "x-api-key: " & $apiKey ) & ¶ ; "" ) &
    "--dump-header $responseHeaders" & ¶ &
    "--connect-timeout 15" & ¶ &
    "--show-error" & ¶ &
    "--max-time 120"
]

Insert from URL [
    Select ;
    With dialog: Off ;
    Target: $schemaResponse ;
    $url ;
    Verify SSL Certificates ;
    cURL options: $curlOptions
]

Set Variable [ $lastError ; Value:
    JSONSetElement ( "{}" ;
        [ "code" ; Get ( LastError ) ; JSONNumber ] ;
        [ "detail" ; Get ( LastErrorDetail ) ; JSONString ]
    )
]
Set Variable [ $fmError ; Value: JSONGetElement ( $lastError ; "code" ) ]
Set Variable [ $fmErrorDetail ; Value: JSONGetElement ( $lastError ; "detail" ) ]
Set Variable [ $formattedResponse ; Value:
    JSONFormatElements ( $schemaResponse )
]

If [ $fmError ≠ 0 or Left ( $formattedResponse ; 1 ) = "?" ]
    Exit Script [ Text Result: $lastError ]
End If

If [ JSONGetElementType ( $schemaResponse ; "" ) ≠ JSONArray ]
    Exit Script [ Text Result: "Die Schema-Antwort ist kein JSON-Array." ]
End If

Set Variable [ $schemaElements ; Value:
    JSONListValues ( $schemaResponse ; "" )
]

3. Rechnungs-JSON erzeugen

WertFileMaker-Konstante
Text, Codes, IDs und DatumsstringsJSONString
Mengen, Preise, Prozente und SummenJSONNumber
Wahr/FalschJSONBoolean
Objekt oder ArrayJSONObject / JSONArray

Formatierte Zahlenstrings wie "1.234,56" dürfen nicht als Rechnungsbetrag übertragen werden.

2Rechnungskopf aufbauen

Set Variable [ $json ; Value: "{}" ]

Set Variable [ $json ; Value:
    JSONSetElement ( $json ;
        [ "exchanged_document_context.guideline_specified_document_context_parameter.id.value" ;
          "urn:cen.eu:en16931:2017" ; JSONString ] ;
        [ "exchanged_document.id.value" ;
          Rechnungskopfdaten::Rechnungsnummer ; JSONString ] ;
        [ "exchanged_document.type_code.value" ;
          Rechnungskopfdaten::Dokumententyp ; JSONString ] ;
        [ "exchanged_document.issue_date_time.date_time_string.format" ;
          "102" ; JSONString ] ;
        [ "exchanged_document.issue_date_time.date_time_string.value" ;
          dateformat102 ( Rechnungskopfdaten::Rechnungsdatum ) ; JSONString ] ;
        [ "supply_chain_trade_transaction.applicable_header_trade_settlement.invoice_currency_code.value" ;
          "EUR" ; JSONString ]
    )
]

Das Beispiel zeigt zentrale Pfade. Pflichtfelder hängen von Dokumenttyp, Profil und Geschäftsfall ab. Käufer, Verkäufer, Steuern, Summen und Zahlungsdaten müssen entsprechend dem abgerufenen Schema ergänzt werden.

3Positionen ergänzen

Go to Record/Request/Page [ First ]

Loop [ Flush: Always ]
    Set Variable [ $i ; Value: Get ( RecordNumber ) - 1 ]
    Set Variable [ $path ; Value:
        "supply_chain_trade_transaction.included_supply_chain_trade_line_item[" & $i & "]"
    ]

    Set Variable [ $json ; Value:
        JSONSetElement ( $json ;
            [ $path & ".associated_document_line_document.line_id.value" ;
              Get ( RecordNumber ) ; JSONString ] ;
            [ $path & ".specified_trade_product.name.value" ;
              Rechnungspositionen::Artikelname ; JSONString ] ;
            [ $path & ".specified_line_trade_delivery.billed_quantity.value" ;
              Rechnungspositionen::Menge ; JSONNumber ] ;
            [ $path & ".specified_line_trade_delivery.billed_quantity.unit_code" ;
              Rechnungspositionen::EinheitenCode ; JSONString ] ;
            [ $path & ".specified_line_trade_settlement.applicable_trade_tax.rate_applicable_percent.value" ;
              Steuerschlüssel::Steuersatz ; JSONNumber ] ;
            [ $path & ".specified_line_trade_settlement.specified_trade_settlement_line_monetary_summation.line_total_amount.value" ;
              Rechnungspositionen::GesamtNetto ; JSONNumber ]
        )
    ]

    Go to Record/Request/Page [ Next ; Exit after last: On ]
End Loop

Set Variable [ $formattedJSON ; Value: JSONFormatElements ( $json ) ]
If [ Left ( $formattedJSON ; 1 ) = "?" ]
    Exit Script [ Text Result: $formattedJSON ]
End If
If [ JSONGetElementType ( $json ; "" ) ≠ JSONObject ]
    Exit Script [ Text Result: "Das Rechnungs-JSON muss ein Objekt sein." ]
End If

4. Rechnungs-XML erzeugen

POST <API-BASIS-URL>/<JSON-ZU-XML-ENDPUNKT>/<MODELLNAME>
Content-Type: application/json
Body: <RECHNUNGS-JSON>

Response:
{ "message": "...", "xml_output": "<XML-KLARTEXT>" }

4XML-Request senden

Set Variable [ $model ; Value: "Facturxen16931" ]
Set Variable [ $apiKey ; Value: Einstellungen::API_Key ]
Set Variable [ $url ; Value:
    "<API-BASIS-URL>/<JSON-ZU-XML-ENDPUNKT>/" & $model
]
Set Variable [ $response ; Value: "" ]
Set Variable [ $responseHeaders ; Value: "" ]
Set Variable [ $requestData ; Value: $json ]

Set Variable [ $curlOptions ; Value:
    "--request POST" & ¶ &
    "--header " & Quote ( "Content-Type: application/json" ) & ¶ &
    If ( not IsEmpty ( $apiKey ) ;
        "--header " & Quote ( "x-api-key: " & $apiKey ) & ¶ ; "" ) &
    "--data @$requestData" & ¶ &
    "--dump-header $responseHeaders" & ¶ &
    "--connect-timeout 15" & ¶ &
    "--show-error" & ¶ &
    "--max-time 120"
]

Insert from URL [
    Select ;
    With dialog: Off ;
    Target: $response ;
    $url ;
    Verify SSL Certificates ;
    cURL options: $curlOptions
]

Set Variable [ $lastError ; Value:
    JSONSetElement ( "{}" ;
        [ "code" ; Get ( LastError ) ; JSONNumber ] ;
        [ "detail" ; Get ( LastErrorDetail ) ; JSONString ]
    )
]
Set Variable [ $fmError ; Value: JSONGetElement ( $lastError ; "code" ) ]
Set Variable [ $fmErrorDetail ; Value: JSONGetElement ( $lastError ; "detail" ) ]
Set Field [ Rechnungen::API_Antwort ; $response ]

Die Fehlerwerte müssen innerhalb desselben ersten Set Variable-Schritts nach Insert from URL erfasst werden. --data @$requestData übergibt den Inhalt der FileMaker-Variablen direkt.

5HTTP und Response prüfen

Set Variable [ $headerLines ; Value:
    Substitute ( $responseHeaders ; Char ( 13 ) ; "" )
]
Set Variable [ $headerIndex ; Value: ValueCount ( $headerLines ) ]
Set Variable [ $httpStatusLine ; Value: "" ]

Loop [ Flush: Always ]
    Exit Loop If [ $headerIndex < 1 ]
    Set Variable [ $httpStatusLine ; Value:
        GetValue ( $headerLines ; $headerIndex )
    ]
    Exit Loop If [ Left ( $httpStatusLine ; 5 ) = "HTTP/" ]
    Set Variable [ $headerIndex ; Value: $headerIndex - 1 ]
End Loop

Set Variable [ $httpStatus ; Value:
    If ( Left ( $httpStatusLine ; 5 ) = "HTTP/" ;
        GetAsNumber ( MiddleWords ( $httpStatusLine ; 2 ; 1 ) ) ; 0 )
]
Set Variable [ $formattedResponse ; Value: JSONFormatElements ( $response ) ]

If [ ( $fmError ≠ 0 and $httpStatus = 0 ) or
     Left ( $formattedResponse ; 1 ) = "?" ]
    Exit Script [ Text Result: $lastError ]
End If
If [ JSONGetElementType ( $response ; "" ) ≠ JSONObject ]
    Exit Script [ Text Result: "Die API-Antwort ist kein JSON-Objekt." ]
End If

Set Variable [ $responseKeys ; Value: JSONListKeys ( $response ; "" ) ]
Set Variable [ $xmlText ; Value:
    If ( not IsEmpty ( FilterValues ( $responseKeys ; "xml_output" ) ) ;
        JSONGetElement ( $response ; "xml_output" ) ; "" )
]
Set Variable [ $apiDetail ; Value:
    If ( not IsEmpty ( FilterValues ( $responseKeys ; "detail" ) ) ;
        JSONGetElement ( $response ; "detail" ) ; "" )
]

If [ $httpStatus < 200 or $httpStatus ≥ 300 or
     not IsEmpty ( $apiDetail ) or IsEmpty ( $xmlText ) ]
    Exit Script [ Text Result:
        JSONSetElement ( "{}" ;
            [ "status" ; "api_error" ; JSONString ] ;
            [ "http_status" ; $httpStatus ; JSONNumber ] ;
            [ "detail" ; $apiDetail ; JSONString ]
        )
    ]
End If

Set Variable [ $xmlContainer ; Value:
    TextEncode ( $xmlText ; "utf-8" ; 3 )
]
Set Field [ Rechnungen::ERechnungXML ; $xmlContainer ]

5. Sicht-PDF und PDF/A-3 erzeugen

6Sicht-PDF erzeugen

Set Variable [ $pdfContainer ; Value: "" ]

Save Records as PDF [
    Restore ;
    Save to: Target ;
    Target: $pdfContainer ;
    With dialog: Off ;
    Current record
]

Set Variable [ $pdfError ; Value: Get ( LastError ) ]
If [ $pdfError ≠ 0 or IsEmpty ( $pdfContainer ) ]
    Exit Script [ Text Result: "Das Sicht-PDF konnte nicht erzeugt werden." ]
End If
Set Field [ Rechnungen::SichtPDF ; $pdfContainer ]

Das Rechnungs-Drucklayout und der richtige Datensatz müssen aktiv sein. Der Scriptschritt setzt das Zugriffsrecht Allow printing voraus.

7PDF/A-3-Request senden

If [ IsEmpty ( Rechnungen::SichtPDF ) or
     IsEmpty ( Rechnungen::ERechnungXML ) ]
    Exit Script [ Text Result: "Sicht-PDF oder Rechnungs-XML fehlt." ]
End If

Set Variable [ $requestData ; Value:
    JSONSetElement ( "{}" ;
        [ "pdf" ; Base64EncodeRFC ( 4648 ; Rechnungen::SichtPDF ) ; JSONString ] ;
        [ "xml" ; Base64EncodeRFC ( 4648 ; Rechnungen::ERechnungXML ) ; JSONString ]
    )
]
Set Variable [ $url ; Value: "<API-BASIS-URL>/<PDFA3-ENDPUNKT>" ]
Set Variable [ $apiKey ; Value: Einstellungen::API_Key ]
Set Variable [ $response ; Value: "" ]
Set Variable [ $responseHeaders ; Value: "" ]

Set Variable [ $curlOptions ; Value:
    "--request POST" & ¶ &
    "--header " & Quote ( "Content-Type: application/json" ) & ¶ &
    If ( not IsEmpty ( $apiKey ) ;
        "--header " & Quote ( "x-api-key: " & $apiKey ) & ¶ ; "" ) &
    "--data @$requestData" & ¶ &
    "--dump-header $responseHeaders" & ¶ &
    "--connect-timeout 15" & ¶ &
    "--show-error" & ¶ &
    "--max-time 120"
]

Insert from URL [
    Select ;
    With dialog: Off ;
    Target: $response ;
    $url ;
    Verify SSL Certificates ;
    cURL options: $curlOptions
]

Set Variable [ $lastError ; Value:
    JSONSetElement ( "{}" ;
        [ "code" ; Get ( LastError ) ; JSONNumber ] ;
        [ "detail" ; Get ( LastErrorDetail ) ; JSONString ]
    )
]
Set Variable [ $fmError ; Value: JSONGetElement ( $lastError ; "code" ) ]
Set Variable [ $fmErrorDetail ; Value: JSONGetElement ( $lastError ; "detail" ) ]
Set Field [ Rechnungen::API_Antwort ; $response ]

# Determine $httpStatus with the block from step 5
Set Variable [ $formattedResponse ; Value: JSONFormatElements ( $response ) ]
If [ ( $fmError ≠ 0 and $httpStatus = 0 ) or
     Left ( $formattedResponse ; 1 ) = "?" ]
    Exit Script [ Text Result: $lastError ]
End If
If [ JSONGetElementType ( $response ; "" ) ≠ JSONObject ]
    Exit Script [ Text Result: "Die API-Antwort ist kein JSON-Objekt." ]
End If

Set Variable [ $responseKeys ; Value: JSONListKeys ( $response ; "" ) ]
Set Variable [ $pdfBase64 ; Value:
    If ( not IsEmpty ( FilterValues ( $responseKeys ; "pdf" ) ) ;
        JSONGetElement ( $response ; "pdf" ) ; "" )
]
Set Variable [ $apiDetail ; Value:
    If ( not IsEmpty ( FilterValues ( $responseKeys ; "detail" ) ) ;
        JSONGetElement ( $response ; "detail" ) ; "" )
]

If [ $httpStatus < 200 or $httpStatus ≥ 300 or
     not IsEmpty ( $apiDetail ) or IsEmpty ( $pdfBase64 ) ]
    Exit Script [ Text Result:
        JSONSetElement ( "{}" ;
            [ "status" ; "api_error" ; JSONString ] ;
            [ "http_status" ; $httpStatus ; JSONNumber ] ;
            [ "detail" ; $apiDetail ; JSONString ] ;
            [ "response" ; $response ; JSONString ]
        )
    ]
End If

Set Variable [ $fileName ; Value:
    "E-Rechnung " & Rechnungskopfdaten::Rechnungsnummer & ".pdf"
]
Set Variable [ $pdfaContainer ; Value:
    Base64Decode ( $pdfBase64 ; $fileName )
]
Set Field [ Rechnungen::PDF_A_3 ; $pdfaContainer ]

Der Dateiname im zweiten Parameter von Base64Decode sorgt dafür, dass FileMaker echte PDF-Containerdaten erzeugt. Übergeben Sie Base64 ohne ein data:application/pdf;base64,-Präfix.

6. API-Responses vollständig auswerten

Die Endpunkte liefern unterschiedliche JSON-Strukturen. Speichern Sie die vollständige Antwort immer in Rechnungen::API_Antwort und lesen Sie erwartete Felder erst aus, nachdem HTTP-Status, JSON-Syntax und JSON-Wurzeltyp geprüft wurden.

Schema-Response

[
  [
    "<XML-PFAD>",
    "<JSON-PFAD>",
    "<FELDTYP>",
    "<XML-ELEMENT>"
  ],
  [
    "<XML-PFAD>",
    "<JSON-PFAD>",
    "<FELDTYP>",
    "<XML-ELEMENT>"
  ]
]
PositionInhaltBeispielziel in FileMaker
1vollständiger XML-PfadSchema::Xml_Pfad
2beim Request zu verwendender JSON-PfadSchema::Json_Pfad
3erwarteter DatentypSchema::Feldtyp
4zugehöriges XML-ElementSchema::Xml_Element

Die Schema-Antwort ist auf Root-Ebene ein JSONArray. Jeder Array-Eintrag ist wiederum ein Array mit vier Positionen. Ein Fehlerobjekt darf deshalb nicht wie eine Schemaliste importiert werden.

Erfolgreiche XML-Response

{
  "message": "Invoice processed successfully.",
  "xml_output": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
}
ElementDatentypBedeutung
messageTextallgemeine Erfolgsmeldung des Dienstes
xml_outputTextvollständiges Rechnungs-XML als Klartext, nicht Base64

Die Zeichen \" und \n gehören nur zur JSON-Darstellung. JSONGetElement ( $response ; "xml_output" ) liefert den normalen XML-Text. Wandeln Sie ihn anschließend mit TextEncode ( $xmlText ; "utf-8" ; 3 ) in Containerdaten um.

Erfolgreiche PDF/A-3-Response

{
  "message": "PDF/A wurde erfolgreich erstellt",
  "pdf": "JVBERi0xLj..."
}
ElementDatentypBedeutung
messageTextallgemeine Erfolgsmeldung des Dienstes
pdfTextvollständige PDF/A-3-Datei als Base64-kodierter Text

pdf ist weder eine URL noch rohe Binärdaten. Dekodieren Sie den Wert mit Base64Decode ( $pdfBase64 ; $fileName ); der Dateiname mit Endung .pdf sorgt für echte PDF-Containerdaten.

Fehler-Response

{
  "detail": "<FEHLERBESCHREIBUNG>"
}

Typische Beispiele sind:

{ "detail": "Invalid API Key" }
{ "detail": "Invalid JSON element" }
{ "detail": "XML is not valid." }
EbenePrüfungBedeutung
FileMaker/cURLGet ( LastError )Scriptschritt oder Übertragung fehlgeschlagen
Externe BibliothekGet ( LastErrorDetail )cURL-, TLS-, HTTP- oder Netzwerkdiagnose
HTTP$httpStatusStatus außerhalb von 200 bis 299
APIdetailfachlicher oder serverseitiger Fehler
Reihenfolge: Zuerst die letzte HTTP-Statuszeile bestimmen, danach Transportfehler, JSON-Syntax und Wurzeltyp prüfen und erst dann xml_output, pdf oder detail auslesen. Eine HTTP-Antwort mit Status 200 ersetzt nicht die abschließende fachliche Validierung.

7. Validierung und Gesamtstatus

Eine erfolgreiche API-Response bestätigt nur die technische Erzeugung. Vor dem Versand müssen XML-Schema, Profil, Geschäftsregeln, Summen und bei hybriden Rechnungen zusätzlich PDF/A-3 sowie das eingebettete XML validiert werden. Das passende FileMaker-Script und die Auswertung der Prüfberichte finden Sie in der Anleitung zum E-Rechnungsvalidierer.
StatusBedeutung
transport_errorDer Dienst konnte nicht erreicht werden.
invalid_responseDie Antwort war kein erwartetes JSON-Objekt.
http_errorHTTP-Status außerhalb von 200 bis 299.
xml_createdXML erzeugt, aber noch nicht abschließend validiert.
pdfa3_createdPDF/A-3 erzeugt, aber noch nicht abschließend validiert.
validation_failedSchema-, Profil- oder Geschäftsregel verletzt.
created_and_validatedErzeugung und Validierung waren erfolgreich.

Nur created_and_validated darf einen automatischen Versand freigeben.

8. Abnahmetest

  1. gültige Rechnung für jedes produktiv verwendete Modell,
  2. fehlendes Pflichtfeld, falscher Datentyp und ungültiger Modellname,
  3. leeres sowie syntaktisch ungültiges JSON,
  4. korrekter und ungültiger API-Schlüssel,
  5. TLS-Fehler, nicht erreichbarer Endpunkt und Timeout,
  6. gültiges und beschädigtes Sicht-PDF beziehungsweise XML,
  7. HTTP-Fehler mit JSON-Body und unerwartete Nicht-JSON-Antwort,
  8. fachlich fehlerhafte Rechnung, die der Validator ablehnt,
  9. Ausführung in FileMaker Pro und gegebenenfalls als Server-Script.

Technische Referenz

← Zurück zur E-Rechnungserstellung