How to validate a SAF-T (PT) before submitting to AT
A pre-submission checklist: encoding, BOM, NIF, ATCUD, header dates, per-document date range, block totals, currency, and document status — what AT catches at intake and how to fix it before day 5.
Why pre-validate at all
The AT portal accepts your SAF-T file. Or rejects it with "ficheiro inválido". There is no middle ground and there is no useful feedback. If you submit on day 5 at 23:50 and the file bounces, you have ten minutes to find the bug and re-export from your ERP. That is the wrong time to discover that your invoice numbering reset, your NIF check-digit is wrong, or your encoding got mangled.
Pre-validation closes the gap. You upload the file to a validator that runs the same XSD plus the heuristics AT actually applies on intake — encoding, BOM, NIF Mod-11, ATCUD format, header dates, document totals, currency rates, document status consistency — and you see every issue with a line number before AT does.
What to validate, in order
- Encoding. The single most common silent rejection. AT requires Windows-1252; most ERPs export UTF-8. The XSD parser is fine with both, but AT's intake pipeline is not. See the encoding rule.
- BOM. If your ERP prepends a UTF-8 byte-order-mark before
<?xml ?>, AT rejects. Same for UTF-16 BOMs. - Schema. The XSD validates the structural shape: required elements, attribute types, enumeration values. This is what AT runs first.
schema 1.04_01is the current SAF-T (PT) version for monthly billing. - NIF Mod-11. Every
TaxRegistrationNumberandCustomerTaxID/SupplierTaxIDneeds a valid Portuguese check digit and an allowed prefix. See the NIF rule. - ATCUD format. Eight uppercase alphanumerics, dash, sequence ≥ 1. Mandatory since 2023.
- Header dates.
StartDate < EndDate,FiscalYearmatches the year ofStartDate,DateCreated >= EndDate,EndDatenot in the future. - Per-document date range. Every
Invoice,Payment,WorkDocument,StockMovementdate must fall inside the Header's reporting window. - Block totals.
SalesInvoices.NumberOfEntriesmatches the count of children;TotalDebit + TotalCreditmatches the summedGrossTotals within 0.01 €. - Currency. Foreign-currency documents need
CurrencyCode + CurrencyAmount + ExchangeRate > 0. Missing rate is invisible to the XSD; AT rejects on intake. - Document status.
InvoiceStatusin {N, S, A, R, F};InvoiceStatusDate >= InvoiceDate.
What pre-validation does NOT catch
Be honest with yourself: a validator can confirm the file is well-formed and consistent. It cannot guarantee that AT will accept it. The two things it cannot see:
- Server-side AT business rules that change without notice. AT occasionally tightens intake rules without updating the public XSD. Schema-change monitors and community advisories help — but new rejection patterns sometimes emerge first in real submissions.
- Account-level constraints. Submission window already used, taxpayer mid-suspension, certified-software registration mismatch — none of those are file-level issues; they are taxpayer-level.
For the first class, post-rejection feedback loops still matter. For the second, your accountant or AT support is the right channel.
Workflow for the day-5 deadline
- Export the monthly SAF-T from your ERP a day early — ideally day 3 of the next month.
- Run it through a pre-validator. Fix every error reported. If the encoding rule fires, run the auto-fix and re-validate.
- Re-export only when a structural issue is reported. Re-running pre-validation on the same broken file twice gets the same answer.
- Submit to AT once the validator returns clean. Save the PDF report as part of your submission folder.
Ready?
Upload your SAF-T XML and see what AT will reject — before you submit. Validate now →