4 min read
SAF-T (PT) XSD 1.04_01: official download and what changed in 2022
Where to download AT's official SAF-T (PT) schema, the version in force in 2026, how it differs from the 2016 file many tools still ship, and how to validate against it.
The current version: 1.04_01
The SAF-T (PT) structure in force is version 1.04_01, introduced by Portaria n.º 302/2016 with effect from 1 January 2017. Its XML namespace is urn:OECD:StandardAuditFile-Tax:PT_1.04_01, and every file you submit declares <AuditFileVersion>1.04_01</AuditFileVersion> in the header. As of September 2026, AT has not announced a version 1.05.
Official download
AT publishes the schema on the Portal das Finanças:
https://info.portaldasfinancas.gov.pt/apps/saft-pt04/SAFTPT1.04_01.xsd
Take it from there rather than from a copy bundled in a library or an old project. The file is encoded in Windows-1252, like the SAF-T files themselves.
Same version number, two different files
AT revised the XSD on 17 May 2022 without changing the version number. Many tools and libraries still ship the earlier 2016 file, and the two do not accept the same documents:
| What | 2016 file | 2022 file (current) |
|---|---|---|
Header/CompanyAddress | Postal code must be NNNN-NNN; country fixed to PT | Any postal code up to 20 characters; any country code |
| Currency codes | No SLE or VED | ISO 4217 list includes SLE and VED |
HashControl on manually issued documents | The reference after M may contain extra slashes | Must be a single series/number, without extra slashes or spaces |
In practice, validating against the 2016 file reports companies with a foreign address or an unusual postal code as invalid, even though AT accepts them. SAFTCheck validates against the 2022 file.
ATCUD in the XSD
The schema only declares ATCUD as text of up to 100 characters. It does not define the format: that comes from Portaria n.º 195/2020 (article 3), which requires the series validation code issued by AT (at least 8 characters), a dash, and the document's sequential number. A file can therefore pass the XSD with a malformed ATCUD and still be rejected. Check an ATCUD or read the format rules and common errors.
Validating against the XSD yourself
The file uses XSD 1.1 features: it declares vc:minVersion="1.1" and contains xs:assert rules. Java's Xerces (in XSD 1.1 mode) handles it. libxml2, which PHP, Python's lxml and xmllint rely on, does not support XSD 1.1. With libxml2 you have to remove the xs:assert elements and turn the xs:all block in GeneralLedgerEntries (the journal Lines) into an unbounded xs:choice, because libxml2 rejects maxOccurs="unbounded" inside xs:all.
Those asserts check real business rules, for example that a zero-rated line carries a tax exemption reason. A file that passes a stripped-down schema can still be rejected.
The fastest check
If you just need to know whether a file passes, upload it to SAFTCheck. It validates against the current 2022 schema and also runs the checks the XSD cannot express: encoding, BOM, NIF check digits, ATCUD, header dates and totals. The first validation is free and needs no account, and files are deleted within 60 minutes.
Related: how to validate a SAF-T (PT) before submitting to AT and the UTF-8 encoding error.