- Business terms
- BT-112 Invoice total amount with VAT BT-115 Amount due for payment BT-84 Payment account identifier BT-109 Invoice total amount without VAT BT-110 Invoice total VAT amount BT-1 Invoice number
- Code samples
- VB.NET
- Published
A ZUGFeRD invoice has two parts: the PDF that people read and the embedded XML that software processes. Legally the XML counts. In many companies, however, what gets checked and approved is what the PDF shows. Nobody makes sure that both parts say the same thing.
In short: In a hybrid e-invoice the structured part – the XML – is decisive. If the visible PDF differs from it, the clerk sees another amount or other bank details than the accounting software processes. That can be a mistake or a fraud attempt. From version 11.0.0.19 the Aloaha ZUGFeRD SDK checks with a single call, CheckPDFTextAgainstXML, whether the invoice total, the amount due, the invoice number and the IBAN of the XML are also printed on the PDF pages.
Why this matters
According to the letter of the German Federal Ministry of Finance of 15 October 2024 (para. 31), the invoice data in the XML is the leading part of a hybrid format such as ZUGFeRD. If PDF and XML differ, the XML data prevails. If the PDF shows different invoice details, it may count as a further invoice for which section 14c of the German VAT Act has to be examined; input VAT can be deducted only on the basis of the structured part (para. 32). The PDF is therefore only a rendering for the human eye.
In practice it often works the other way round: the invoice arrives by e-mail, someone opens the PDF, checks amount and supplier and approves. The software then reads the XML and pays what is written there. There is no control between the two steps.
| What can happen | Consequence |
|---|---|
| Fraud: the PDF shows the known bank details and the expected amount, the XML contains another IBAN or a higher amount. | Approval follows the PDF, payment follows the XML – to the wrong account. |
| Mix-up: the XML of another invoice was embedded, for example from a test run. | An invoice nobody has seen is posted. We found exactly this in a real customer file. |
| Different versions: PDF and XML come from two program runs, and the invoice was changed in between. | Amount or VAT differ between PDF and XML. Section 14c of the German VAT Act then has to be examined as well. |
| XML replaced afterwards: a third party swaps the attachment in an intercepted invoice. | The PDF looks unchanged, the data is different. |
A formal validation against EN 16931 does not find such cases: the XML can be perfectly valid on its own. It just does not belong to the PDF.
The check: CheckPDFTextAgainstXML
The function reads the embedded XML and the text of the PDF pages and looks for the key values of the XML in the printed text. Amounts are recognised in all usual notations (1.234,56 – 1,234.56 – 1234,56 – 1 234,56).
| Value | Field | Effect on the result |
|---|---|---|
| Invoice total (gross) | BT-112 | One of the two must be printed, otherwise result 0. |
| Amount due | BT-115 | |
| Invoice number | BT-1 | Not printed: warning (result 2). |
| Payee IBAN | BT-84 | The PDF prints a different IBAN: warning (result 2). No IBAN in the PDF at all: note only. |
| Net total, VAT | BT-109, BT-110 | Note in the report only. |
| Return value | Meaning |
|---|---|
1 | The amount of the XML is printed on the PDF, nothing contradicts. |
2 | The amount is printed, but invoice number or IBAN differ. Please look at it. |
0 | Neither the invoice total nor the amount due of the XML is printed on the PDF. Stop the payment and clarify. |
-1 | Not checkable: no embedded XML, no text in the PDF (e.g. a scan), file not found or no licence. |
' VB.NET
Dim key As String = "YOUR-LICENCE-KEY"
Dim alo As New Aloaha_ZUGFeRD.XML(key)
Select Case alo.CheckPDFTextAgainstXML("C:\Inbox\INV-4711.pdf", key)
Case 1
' fits: continue processing
Case 2
' warning: show the report to a person
System.IO.File.WriteAllText("C:\Clarify\INV-4711.txt", alo.PDFTextCheckReport)
Case 0
' mismatch: block the payment, ask the supplier
System.IO.File.WriteAllText("C:\Blocked\INV-4711.txt", alo.PDFTextCheckReport)
Case Else
' not checkable: the reason is in PDFTextCheckReport or LastError
End Select
The report in PDFTextCheckReport lists every compared value on one line:
PDF text check: WARNING - the payable amount is printed, but 1 other value(s) of the XML differ from the PDF.
OK BT-112 grand total 1190.00: printed as 1.190,00
OK BT-109 net total 1000.00: printed as 1.000,00
OK BT-110 VAT total 190.00: printed as 190,00
OK BT-1 invoice number RE-1001: printed
WARNING BT-84 IBAN DE02120300000000202051: not printed - the PDF prints another IBAN: DE89370400440532013000
Rough check only: a value counts as printed when it appears anywhere in the page text.
The check runs locally. The invoice does not leave your premises.
Without programming: in the GUI and the PDF Viewer
From version 11.0.0.19 the same check is built into our applications. In the Aloaha ZUGFeRD GUI it runs for every PDF as part of Validate e-invoice…, and after merging XML and PDF the GUI warns if the two do not belong together. The Aloaha ZUGFeRD PDF Viewer shows the result as a coloured note in the toolbar when a ZUGFeRD PDF is opened.
What the test with real invoices showed
Before release we tested the comparison logic with 15 real ZUGFeRD invoices from our support:
- 12 invoices: result 1, amount and invoice number are printed on the PDF.
- 2 invoices: result 2. In one, the PDF prints two other bank accounts than the XML; in the other, the invoice number is missing from the text.
- 1 invoice: result 0. The XML came from a sample, the PDF was a real invoice – no amount matched.
So three of fifteen files deserved a second look, and none of them would have been noticed by a pure format validation.
What the check cannot do
- It is a rough check. A value counts as printed when it appears anywhere in the page text – not necessarily next to the word “total”.
- Scanned PDFs without text cannot be checked (result -1). That is not a sign of fraud.
- Bank details as an image in the letterhead: the check then finds no IBAN and only gives a note.
- No replacement for format validation or for the comparison with your master data. Only your accounting knows whether the IBAN belongs to the supplier.
Recommended sequence for incoming invoices
- Validate the format:
ValidateInvoicePDF– is the invoice valid according to EN 16931? - Compare PDF and XML:
CheckPDFTextAgainstXML– does the PDF say the same as the XML? - Read the data:
FillZUGFeRD_Structure– take amounts, VAT ID and IBAN from the XML. - Compare with master data: do VAT ID and IBAN match the known supplier? See e-invoice from a new sender: genuine or phishing? (German)
Frequently asked questions
What applies if the PDF and the XML of a ZUGFeRD invoice differ?
The XML. In hybrid formats the structured part is the leading one; the PDF is only the rendering for people.
Why is it risky to check only the PDF?
Because the software processes the XML. If it contains another amount or another IBAN than the PDF, something else is paid than was approved.
How do I check whether PDF and XML belong together?
With CheckPDFTextAgainstXML in the Aloaha ZUGFeRD SDK (from version 11.0.0.19). The function looks for the invoice total, amount due, invoice number and IBAN of the XML in the text of the PDF pages and returns 1 (match), 2 (warning), 0 (mismatch) or -1 (not checkable).
Does a validation against EN 16931 find such differences?
No. Format validation looks only at the XML. A valid XML can belong to a completely different PDF.
What does the result -1 mean?
The file cannot be checked: it contains no invoice XML, or the pages have no text, for example a scan. That is not a sign of fraud.
Does result 1 prove that PDF and XML are identical?
No. It shows that the key values of the XML are also printed on the PDF. It is a rough plausibility check, not a complete comparison.
Business terms in this article: BT-112 BT-115 BT-84 BT-109 BT-110 BT-1