01 β What is actually in the code
The whole invoice, field by field
The QR defined by Despacho n.ΒΊ 8632/2022 is not a URL. It is text with fixed
fields: A the issuer's NIF, B the customer's,
F the date, G the document number, H the
ATCUD, blocks I/J/K the taxable bases and
VAT per band (mainland, Azores, Madeira), and O the total.
It has been mandatory on every invoice since 2022, which makes it the one piece of structured data that genuinely exists on all of them. So it is read from there rather than guessed from the page layout β every issuer designs the page differently, and the code is identical on all of them.
02 β One number the code does not carry
The VAT rate is computed, not copied
The code names the band β reduced, intermediate, normal β never the percentage. And the same band is 23% on the mainland, 22% in Madeira and 16% in the Azores, figures that still move with each budget.
So the rate comes out of the invoice itself: VAT divided by base. The result
is only written down if it lands on a band currently in force; if it does not, the
column shows ?%. Filling it from a fixed table would present what the
table said as what the invoice said β and would be wrong the day after a change,
with every figure still looking right.
ATCUD in a column of its own
The ATCUD identifies the document to the tax authority, and that is what a Portuguese accountant reconciles on β not the internal invoice number. It gets its own column next to the number; merging the two loses the one that is used for checking.
The NIF check digit is recomputed too (weights 9β¦2, mod 11). A wrong digit raises no error anywhere: the invoice simply never appears in the account of whoever should have had it.
999999990 is not a customer
On invoices to a final consumer the customer VAT field carries
999999990. Copied through, the ledger fills with rows for the "same"
customer, and duplicate detection starts pairing invoices that have nothing to do with
each other. Here it is left empty, which is what it means.
Credit notes (NC) carry positive amounts; only the type says the
money is going back. They are subtracted in the total at the bottom.
The one column that stays empty
The code carries the supplier's NIF, never their name β so the supplier column is blank on these rows. The name is printed on the page, but reading it out of free text means deciding which line is the company and which is the address, and being wrong sometimes. A blank cell you can fill in beats a plausible name that belongs to the wrong company.
The NIF is in the row, so a lookup or a one-off find-and-replace fills the column in seconds β and it stays correct.
What is not done here
SAF-T (PT) is not read: it is a monthly export of an entire ledger, a different problem and a different format. Invoices to public bodies sent over Peppol CIUS-PT are read like any other European UBL β those are XML.
A scanned or photographed invoice with no text layer is not read either: if the QR is legible it is used, otherwise the row comes out empty and marked, never guessed.
Trying it
Drop files on the main page β up to 10 invoices per export and 20 a day, free, no account, and the count resets at midnight. Pro lifts both limits for 29 β¬ once, with no renewal.
Nothing is uploaded
The files are read in the browser. There is no server they could go to, and it takes two minutes to confirm: open the developer tools, the Network tab, and drop an invoice in β no request goes out. Which countries are read.