SAFTCheck
Blog

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:

What2016 file2022 file (current)
Header/CompanyAddressPostal code must be NNNN-NNN; country fixed to PTAny postal code up to 20 characters; any country code
Currency codesNo SLE or VEDISO 4217 list includes SLE and VED
HashControl on manually issued documentsThe reference after M may contain extra slashesMust 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.

Other posts