Build the SAF-T (PT) File (Standard Audit File for Tax — Portugal)
Skill: Convert invoicing and accounting data into the SAF-T (PT) XML
Region: Portugal
Category: SAF-T (PT) — Standard Audit File for Tax, Autoridade Tributária e Aduaneira (AT)
Does: Takes a firm's invoicing and/or accounting data and produces the AuditFile XML defined by the Portuguese SAF-T (PT) schema — Header, MasterFiles (Customers, Products, TaxTable), GeneralLedgerEntries, and SourceDocuments/SalesInvoices, with each invoice carrying its ATCUD, the 4-character document Hash from the certified signature chain, and the TaxCountryRegion/TaxCode breakdown.
Schema version: urn:OECD:StandardAuditFile-Tax:PT_1.04_01 (Portaria n.º 302/2016, current AT XSD SAFTPT1.04_01.xsd)
The SAF-T (PT) is an AT-prescribed audit/reporting file, not a real-time message. The monthly billing SAF-T (only Header + MasterFiles/Customers/Products/TaxTable + SourceDocuments/SalesInvoices) must be submitted on the Portal das Finanças (e-Fatura / "Comunicação de faturas por SAF-T") by the 5th of the month following issue; the full accounting SAF-T (adding GeneralLedgerEntries and MovementOfGoods/WorkingDocuments/Payments) is generated annually on request or for an inspection (IES support). The AI assembles the XML from already-certified records — it cannot generate a valid invoice Hash, which is produced by the certified billing software's RSA-SHA-1 signature chain. Validate against the current
SAFTPT1.04_01.xsdbefore submission.
When this applies
- Any taxpayer using certified invoicing software in Portugal must export issued invoices monthly as a billing SAF-T (PT) for the AT (
SAFTmode= billing). This is the most common case and the focus of the worked example. - Organised-accounts taxpayers must be able to produce the full accounting SAF-T (PT) (
SAFTmode= accounting) coveringGeneralLedgerEntries, supporting the annual IES/DA declaration. - An integrated export (
SAFTmode= integrated) combines both. - Excluded: simplified-regime taxpayers below the certification threshold (who may report invoices manually on e-Fatura), and non-Portuguese establishments without a Portuguese NIF.
Conversion procedure
- Read the source. Accept the invoicing/accounting export as CSV, JSON, the ERP's own XML, or pasted text. Parse customers, products, tax rates, and each invoice with its lines. For an accounting SAF-T also read the journal/ledger entries.
- Extract fields. For every invoice capture: number (
InvoiceNoin the formType Series/Seq, e.g.FT A/123),ATCUD,InvoiceDate,InvoiceType, customer ID, each line's quantity/unit price/tax, and the document totals. For each customer/product build the MasterFiles entries. If any required field — especially the ATCUD or the line Hash chain — is missing, stop and ask; never invent them. - Normalize. Dates →
YYYY-MM-DD; date-times →YYYY-MM-DDThh:mm:ss; the Portuguese NIF is 9 digits, prefixed inCustomerTaxID/SupplierTaxIDonly where the schema's country-qualified ID is used; amounts → dot decimal, generally 2 decimals (unit prices may carry up to the schema-allowed precision);TaxCountryRegion=PT(orPT-ACAçores /PT-MAMadeira);TaxPercentageas a plain number (23,13,6,0). - Compute. Recompute every line
CreditAmount(net), per-rate tax,DocumentTotals/TaxPayable,NetTotal, andGrossTotal; reconcile against the source and flag mismatches. Do not recompute the cryptographicHash— copy the certified value verbatim (4-charHashfield is the 1st, 11th, 21st and 31st character of the full Base64 signature). - Emit the output. Build the
AuditFileper the structure below. For a billing SAF-T omitGeneralLedgerEntries,MovementOfGoods,WorkingDocuments, andPaymentsunless present; always includeHeader,MasterFiles, andSourceDocuments/SalesInvoices. - Validate. Work through the checklist; confirm
TaxRegistrationNumber,TaxEntity,SAFTmode, and per-invoiceATCUD/Hashare present and well-formed.
Source → SAF-T (PT) field map
| From the source | → Target element / field |
|---|---|
| Schema URN (fixed) | AuditFileVersion (1.04_01) |
| Company NIF | Header/TaxRegistrationNumber |
| Tax authority country | Header/TaxAccountingBasis, Header/CompanyID |
| Reporting accounting basis (F billing / C accounting / I integrated…) | Header/TaxAccountingBasis |
| Company name | Header/CompanyName |
| Fiscal year + period | Header/FiscalYear, Header/StartDate, Header/EndDate |
| Currency (EUR) | Header/CurrencyCode |
| Date file created | Header/DateCreated |
| Software certificate no. | Header/ProductID, Header/SoftwareCertificateNumber |
| Reporting mode | Header/... plus SAFTmode on SourceDocuments context |
| Customer ID / name / NIF | MasterFiles/Customer/CustomerID, CompanyName, CustomerTaxID |
| Product code / description | MasterFiles/Product/ProductCode, ProductDescription |
| Tax rate row | MasterFiles/TaxTable/TaxTableEntry (TaxType, TaxCountryRegion, TaxCode, TaxPercentage) |
Invoice number (Type Series/Seq) |
SalesInvoices/Invoice/InvoiceNo |
| ATCUD (validation code-series + seq) | SalesInvoices/Invoice/ATCUD |
| Signature hash (4 chars) | SalesInvoices/Invoice/Hash |
| Invoice status + date | DocumentStatus/InvoiceStatus, InvoiceStatusDate |
| Invoice date | Invoice/InvoiceDate |
| Invoice type (FT, FS, FR, ND, NC…) | Invoice/InvoiceType |
| Customer on the invoice | Invoice/CustomerID |
| Line number / product / qty / net | Line/LineNumber, ProductCode, Quantity, CreditAmount |
| Line tax (region/code/%) | Line/Tax/TaxType, TaxCountryRegion, TaxCode, TaxPercentage |
| Invoice tax / net / gross totals | DocumentTotals/TaxPayable, NetTotal, GrossTotal |
Every required output element appears above. Repeat Customer, Product, TaxTableEntry, Invoice, and Line once per occurrence.
Document structure
AuditFile (xmlns urn:OECD:StandardAuditFile-Tax:PT_1.04_01)
├── Header (once)
│ ├── AuditFileVersion (1.04_01)
│ ├── CompanyID
│ ├── TaxRegistrationNumber (9-digit NIF)
│ ├── TaxAccountingBasis (F | C | I | S | P | R | E | T)
│ ├── CompanyName
│ ├── BusinessName / CompanyAddress
│ ├── FiscalYear / StartDate / EndDate
│ ├── CurrencyCode (EUR)
│ ├── DateCreated
│ ├── TaxEntity (Global / cost-centre id)
│ ├── ProductCompanyTaxID
│ ├── SoftwareCertificateNumber (AT certificate number)
│ ├── ProductID (Product/Producer)
│ └── ProductVersion
├── MasterFiles (once)
│ ├── Customer ... (one per customer)
│ ├── Product ... (one per product/service)
│ └── TaxTable
│ └── TaxTableEntry ... (one per TaxCountryRegion + TaxCode + %)
├── GeneralLedgerEntries (accounting SAF-T only — omit for billing)
│ └── Journal / Transaction ...
└── SourceDocuments (once)
└── SalesInvoices
├── NumberOfEntries
├── TotalDebit
├── TotalCredit
└── Invoice ... (one per invoice)
├── InvoiceNo (e.g. "FT A/123")
├── ATCUD (validation-code-series + "-" + seq)
├── DocumentStatus (InvoiceStatus / InvoiceStatusDate / SourceID / SourceBilling)
├── Hash (4 chars from RSA-SHA-1 signature chain)
├── HashControl
├── Period (month 1–12)
├── InvoiceDate
├── InvoiceType (FT, FS, FR, ND, NC…)
├── SpecialRegimes (SelfBillingIndicator / CashVATSchemeIndicator / ThirdPartiesBillingIndicator)
├── SourceID / SystemEntryDate
├── CustomerID
├── Line ... (one per line)
│ ├── LineNumber
│ ├── ProductCode / ProductDescription / Quantity / UnitOfMeasure / UnitPrice
│ ├── TaxPointDate
│ ├── Description
│ ├── CreditAmount (or DebitAmount on credit notes)
│ └── Tax (TaxType / TaxCountryRegion / TaxCode / TaxPercentage)
└── DocumentTotals (TaxPayable / NetTotal / GrossTotal)
Notes: MasterFiles/TaxTable is mandatory in every variant. GeneralLedgerEntries appears only when TaxAccountingBasis indicates accounting/integrated. Exempt lines carry TaxCode ISE with TaxPercentage 0 and a TaxExemptionReason + TaxExemptionCode (e.g. M07) on the line.
Code tables
TaxAccountingBasis (Header — the "SAFTmode")
| Code | Meaning |
|---|---|
F |
Faturação (billing-only SAF-T) |
C |
Contabilidade (accounting) |
I |
Contabilidade integrada com faturação (integrated) |
S |
Autofaturação (self-billing) |
P |
Faturação parcial |
R |
Recibos (receipts) |
E |
Contabilidade emitida por terceiros |
T |
Documentos de transporte |
InvoiceType
| Code | Meaning |
|---|---|
FT |
Fatura (invoice, art. 36.º CIVA) |
FS |
Fatura simplificada (art. 40.º CIVA) |
FR |
Fatura-recibo |
ND |
Nota de débito (debit note) |
NC |
Nota de crédito (credit note) |
VD |
Venda a dinheiro (legacy cash sale) |
TaxType and TaxCode
TaxType |
Meaning |
|---|---|
IVA |
Imposto sobre o Valor Acrescentado (VAT) |
IS |
Imposto do Selo (stamp duty) |
NS |
Não sujeito (not subject) |
TaxCountryRegion |
Region |
|---|---|
PT |
Mainland Portugal |
PT-AC |
Açores |
PT-MA |
Madeira |
TaxCode |
Mainland % | Meaning |
|---|---|---|
NOR |
23 | Taxa normal (standard) |
INT |
13 | Taxa intermédia (intermediate) |
RED |
6 | Taxa reduzida (reduced) |
ISE |
0 | Isento (exempt — needs TaxExemptionCode/Reason) |
Selected TaxExemptionCode (when TaxCode = ISE)
| Code | Meaning |
|---|---|
M07 |
Isento art.º 9.º do CIVA |
M16 |
Isento art.º 14.º do RITI (intra-EU supply) |
M40 |
IVA – autoliquidação (reverse charge) |
Calculation rules
- Line net (
CreditAmount) =Quantity×UnitPrice(less any line discount), rounded to 2 decimals. - Line VAT = line net ×
TaxPercentage÷ 100, rounded to 2 decimals. - DocumentTotals/TaxPayable = Σ line VAT across all rates, 2 decimals.
- DocumentTotals/NetTotal = Σ line net (CreditAmount), 2 decimals.
- DocumentTotals/GrossTotal =
NetTotal+TaxPayable, 2 decimals. SalesInvoices/TotalCredit= Σ all invoices' net credit;TotalDebit= Σ debit (credit notes);NumberOfEntries= count ofInvoiceelements.- Hash (4 chars): characters at positions 1, 11, 21, 31 of the full Base64 RSA-SHA-1 signature of
InvoiceDate;SystemEntryDate;InvoiceNo;GrossTotal;PreviousHash. Never recompute or guess — copy from the certified software. Flag if absent. - ATCUD =
<validation-code-of-series>-<sequential number within series>(e.g.AAJFF7VFKR-123). The validation code is issued by the AT per series; the sequence equals the numeric part ofInvoiceNo. - Amounts in EUR, dot decimal, 2 decimals, no thousands separators.
Worked example (end-to-end billing SAF-T fragment)
Exemplo Comércio Lda (NIF 501234567, AT software certificate 1234) issues one full invoice FT A/123 on 2026-06-05 to customer Cliente Final Lda (NIF 502345678): 1 unit of product P001 ("Serviço de consultoria") at net 1000.00, VAT NOR 23% → TaxPayable 230.00, GrossTotal 1230.00. Series A has AT validation code AAJFF7VFKR, so ATCUD = AAJFF7VFKR-123. The certified signature's 4-char Hash is JpRm.
<?xml version="1.0" encoding="UTF-8"?>
<AuditFile xmlns="urn:OECD:StandardAuditFile-Tax:PT_1.04_01" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:OECD:StandardAuditFile-Tax:PT_1.04_01 SAFTPT1.04_01.xsd">
<Header>
<AuditFileVersion>1.04_01</AuditFileVersion>
<CompanyID>501234567</CompanyID>
<TaxRegistrationNumber>501234567</TaxRegistrationNumber>
<TaxAccountingBasis>F</TaxAccountingBasis>
<CompanyName>Exemplo Comercio Lda</CompanyName>
<CompanyAddress>
<AddressDetail>Rua das Flores 10</AddressDetail>
<City>Lisboa</City>
<PostalCode>1200-001</PostalCode>
<Country>PT</Country>
</CompanyAddress>
<FiscalYear>2026</FiscalYear>
<StartDate>2026-06-01</StartDate>
<EndDate>2026-06-30</EndDate>
<CurrencyCode>EUR</CurrencyCode>
<DateCreated>2026-07-02</DateCreated>
<TaxEntity>Global</TaxEntity>
<ProductCompanyTaxID>509999999</ProductCompanyTaxID>
<SoftwareCertificateNumber>1234</SoftwareCertificateNumber>
<ProductID>FaturaPro/Exemplo Software Lda</ProductID>
<ProductVersion>3.2</ProductVersion>
</Header>
<MasterFiles>
<Customer>
<CustomerID>C001</CustomerID>
<AccountID>Desconhecido</AccountID>
<CustomerTaxID>502345678</CustomerTaxID>
<CompanyName>Cliente Final Lda</CompanyName>
<BillingAddress>
<AddressDetail>Avenida Central 22</AddressDetail>
<City>Porto</City>
<PostalCode>4000-002</PostalCode>
<Country>PT</Country>
</BillingAddress>
<SelfBillingIndicator>0</SelfBillingIndicator>
</Customer>
<Product>
<ProductType>S</ProductType>
<ProductCode>P001</ProductCode>
<ProductDescription>Servico de consultoria</ProductDescription>
<ProductNumberCode>P001</ProductNumberCode>
</Product>
<TaxTable>
<TaxTableEntry>
<TaxType>IVA</TaxType>
<TaxCountryRegion>PT</TaxCountryRegion>
<TaxCode>NOR</TaxCode>
<Description>Taxa normal IVA 23%</Description>
<TaxPercentage>23.00</TaxPercentage>
</TaxTableEntry>
</TaxTable>
</MasterFiles>
<SourceDocuments>
<SalesInvoices>
<NumberOfEntries>1</NumberOfEntries>
<TotalDebit>0.00</TotalDebit>
<TotalCredit>1000.00</TotalCredit>
<Invoice>
<InvoiceNo>FT A/123</InvoiceNo>
<ATCUD>AAJFF7VFKR-123</ATCUD>
<DocumentStatus>
<InvoiceStatus>N</InvoiceStatus>
<InvoiceStatusDate>2026-06-05T10:15:00</InvoiceStatusDate>
<SourceID>admin</SourceID>
<SourceBilling>P</SourceBilling>
</DocumentStatus>
<Hash>JpRm</Hash>
<HashControl>1</HashControl>
<Period>6</Period>
<InvoiceDate>2026-06-05</InvoiceDate>
<InvoiceType>FT</InvoiceType>
<SpecialRegimes>
<SelfBillingIndicator>0</SelfBillingIndicator>
<CashVATSchemeIndicator>0</CashVATSchemeIndicator>
<ThirdPartiesBillingIndicator>0</ThirdPartiesBillingIndicator>
</SpecialRegimes>
<SourceID>admin</SourceID>
<SystemEntryDate>2026-06-05T10:15:00</SystemEntryDate>
<CustomerID>C001</CustomerID>
<Line>
<LineNumber>1</LineNumber>
<ProductCode>P001</ProductCode>
<ProductDescription>Servico de consultoria</ProductDescription>
<Quantity>1.00</Quantity>
<UnitOfMeasure>UN</UnitOfMeasure>
<UnitPrice>1000.00</UnitPrice>
<TaxPointDate>2026-06-05</TaxPointDate>
<Description>Servico de consultoria - junho 2026</Description>
<CreditAmount>1000.00</CreditAmount>
<Tax>
<TaxType>IVA</TaxType>
<TaxCountryRegion>PT</TaxCountryRegion>
<TaxCode>NOR</TaxCode>
<TaxPercentage>23.00</TaxPercentage>
</Tax>
</Line>
<DocumentTotals>
<TaxPayable>230.00</TaxPayable>
<NetTotal>1000.00</NetTotal>
<GrossTotal>1230.00</GrossTotal>
</DocumentTotals>
</Invoice>
</SalesInvoices>
</SourceDocuments>
</AuditFile>
Normalisations shown: TaxAccountingBasis F (billing-only SAF-T, so GeneralLedgerEntries omitted); date 05/06/2026 → 2026-06-05; status timestamp → 2026-06-05T10:15:00; rate 23% → 23.00; Line VAT recomputed 1000.00 × 23% = 230.00; NetTotal 1000.00; GrossTotal 1000.00 + 230.00 = 1230.00; ATCUD formed as AAJFF7VFKR-123; the 4-char Hash JpRm copied verbatim from the certified signature (not recomputed). This file is uploaded on the Portal das Finanças via the SAF-T invoice-communication channel by the 5th of the following month.
Validation checklist
- All required fields extracted; AI asked about anything missing or ambiguous (no invented NIFs, ATCUDs, dates, or amounts)
- Root
AuditFilenamespace =urn:OECD:StandardAuditFile-Tax:PT_1.04_01;AuditFileVersion=1.04_01 -
TaxAccountingBasis(SAFTmode) correct:Ffor billing-only (noGeneralLedgerEntries),C/Ifor accounting -
HeadercarriesTaxRegistrationNumber(9-digit NIF),FiscalYear,StartDate/EndDate,SoftwareCertificateNumber,ProductID -
MasterFiles/TaxTablepresent with aTaxTableEntryfor everyTaxCountryRegion+TaxCodeused - Each
InvoicehasInvoiceNo(Type Series/Seq), a well-formedATCUD(validation-code-series-seq), and the certified 4-charHash -
InvoiceTypeand per-lineTaxType/TaxCountryRegion/TaxCodeare valid codes; exempt lines carryTaxExemptionCode/Reason - Line VAT = net ×
TaxPercentage÷ 100;TaxPayable,NetTotal,GrossTotalrecomputed and reconciled, mismatches flagged -
NumberOfEntries= count of invoices;TotalCredit/TotalDebitreconcile with the lines - Amounts EUR dot-decimal 2dp; dates
YYYY-MM-DD, timestampsYYYY-MM-DDThh:mm:ss - File validates against the current
SAFTPT1.04_01.xsdbefore upload to the Portal das Finanças
Last updated: 2026-06-13 — verify the active SAF-T (PT) schema version (currently 1.04_01), the AT TaxCode/TaxExemptionCode lists, the ATCUD/series rules, and the monthly billing-SAF-T submission deadline against the current AT specification before use.