Skip to content

D406 — SAF-T (Standard Audit File for Tax)

The fișierul standard de control fiscal — a large, structured export of a company's accounting master data and transactions in a fixed OECD-derived XML shape. This file is a completion guide: what the declaration reports, who files it and when, and a section-by-section semantic map of the schema — followed by the technical XSD/DUK layer. This is the best-effort form: the schema is an order of magnitude larger than any other declaration (873 element declarations, ~130 KB, root AuditFile) and a real file is produced by the caller's ERP/accounting system, so the guide maps the reporting sections rather than authoring a full instance from scratch. ANAF's validator jar (D406Validator.jar / D406TValidator.jar) and the schema-definition workbook are the authority; this guide is a distilled bridge, not a re-implementation. The worked example is the committed minimal instance tests/fixtures/declaratii/d406t-minimal.xml, re-validated clean on 2026-07-17.

SAF-T replaces the ad-hoc data extracts a tax inspection used to request with a single standardized file: the chart of accounts, customer/supplier masters, the tax and unit-of-measure tables, the full general-ledger journal, and the source documents (sales, purchases, payments, stock movements, asset transactions) for a period. ANAF ingests it into its analytics and reconciles it against the taxpayer's other filings — it is informative (no tax is self-assessed on it), but it exposes the accounting detail behind every other return.

  • Legal basis: the SAF-T reporting obligation sits in the Fiscal Procedure Code (Legea 207/2015); the D406 model, structure, and filing procedure are approved by OPANAF 1783/2021 (and subsequent amendments), which ANAF's SAF-T project page cites as the governing order. Failure to file by the deadline is a contravention under art. 337¹ of Legea 207/2015 (fine 1 000–5 000 lei), plus a fine for incorrect/incomplete filing.
  • Schema version: the current XSD is Ro_SAFT_Schema_v249_2025.xsd (schema v2.4.9, republished 19.02.2026), namespace mfp:anaf:dgti:d406t:declaratie:v1, root AuditFile. The authoritative element table and nomenclatures live in the companion workbook RO_SAFT_SchemaDefCod_16.02.2026.xlsx — consult it, not just the XSD, when composing a real file.
  • Periodicity: SAF-T is filed monthly by taxpayers on a monthly VAT fiscal period, and quarterly by taxpayers on a quarterly or annual VAT period (and by persons not registered for VAT). The Assets section is filed annually and Stocks only on ANAF's request — see below.

Who files & when

  • Who — the obligation was phased in by taxpayer category (the ANAF SAF-T page and ANAF regional notices give the onboarding dates):
Category SAF-T obligation from
Large taxpayers on 1 Jan 2022 who were also large in 2021 1 Jan 2022
Large taxpayers newly classified large on 1 Jan 2022 (not large in 2021) 1 Jul 2022
Medium taxpayers (as classified on 31 Dec 2021) 1 Jan 2023
Small taxpayers and non-residents VAT-registered in Romania 1 Jan 2025

From 1 January 2025 the obligation therefore covers all remaining active companies (small and medium included) plus non-residents holding a Romanian VAT code. A handful of categories are exempted or file a reduced set by separate order; the taxpayer's own classification is authoritative.

  • Deadline — the last calendar day of the month following the reporting period (the month after a reporting month; the month after quarter-end for a quarterly filer), rolled to the next working day when it falls on a weekend or public holiday. (For December 2025 / Q4 2025 this pushed the deadline to 2 February 2026.)
  • The three file variants — one schema, three submission cadences signalled in the Header:
  • Periodic D406 (monthly or quarterly): Header + MasterFiles + GeneralLedgerEntries + SourceDocuments, minus the asset/stock sections.
  • Assets (Active) — the AssetTransactions / asset master content, filed once a year, by the deadline for filing the annual financial statements (not the monthly deadline).
  • Stocks (Stocuri) — the PhysicalStock content, filed only when ANAF requests it, within a deadline ANAF sets that may not be shorter than 30 calendar days from the request.
  • Grace period — the first submissions are penalty-free (an on-ramp for correctly assembling the file), and the grace window shrinks with each period:
  • Monthly filers: 6 months grace for the first reference month, then 5, 4, 3, 2 for the next four — i.e. the fifth report is the last with any grace, and from the sixth the standard deadline binds.
  • Quarterly filers: 3 months grace for the first quarter (e.g. Q1 2025 filable up to 30 June 2025); from the second quarter the standard deadline binds.
  • Corrections — there is no partial amendment. A correction is a complete corrected file re-submitted for the same period (a rectifying D406 replacing the prior one); the reporting-period identity in the Header is what ties the correction to the original. The exact rectification flag is defined in the schema workbook / filing instructions.

Filling guide

Unlike the attribute-only declarations (D300), SAF-T is a deep element tree. anafpy does not author it field-by-field — the ERP does — so the value-add here is a map of the reporting sections onto the wire elements, so an agent can reason about a file the accounting system produced and about what ANAF will reconcile. The full element list is the workbook; the structure/validator gotchas are in the DUK reference — this section is the semantic bridge between them.

Top-level shape. AuditFile has four reporting blocks under the root:

Block Carries SME reality
Header Entity identity (Company), reporting period (SelectionCriteria), DefaultCurrencyCode, TaxAccountingBasis (accounting regime: A normal, IFRS, BANK, INSURANCE, IFN, NORMA39, …), and the reporting-type marker Always present; small errors here (wrong period, wrong regime code) fail structure validation before any data is read
MasterFiles The reference tables the ledger and documents point at The bulk of a first file; must be internally consistent with the entries
GeneralLedgerEntries The accounting journal for the period (JournalTransactionTransactionLine) with NumberOfEntries / TotalDebit / TotalCredit control totals The double-entry backbone; every line references an AccountID and carries TaxInformation
SourceDocuments The commercial documents behind the ledger Where SAF-T ties to e-Factura / D300 / D394

MasterFiles sub-sections (the reference data):

Element Reports
GeneralLedgerAccountsAccount Chart of accounts: AccountID, AccountDescription, StandardAccountID (the standardized RO plan code), AccountType, opening/closing balances
CustomersCustomer / SuppliersSupplier Partner masters with CustomerID/SupplierID, AccountID, and a CompanyStructure (name, address, RegistrationNumber)
TaxTableTaxTableEntry The tax codes used (TaxType 300 = VAT), each TaxCodeDetails giving TaxCode, TaxPercentage, BaseRate (a fraction, 1.00 not 100.00), country
UOMTableUOMTableEntry Units of measure (UN/ECE codes, H87 = piece)
ProductsProduct Goods/services catalogue (may be empty for a services-only nil file)
PhysicalStock Inventory positions — populated only in the Stocks variant
Owners, AssetsAsset Ownership / fixed-asset registers — Assets populated in the Assets variant
AnalysisTypeTable, MovementTypeTable Analytic/movement nomenclatures — present but empty in the current wire (their children answer maxOccurs=0; see the DUK reference)

SourceDocuments sub-sections (the commercial layer):

Element Reports Reconciles against
SalesInvoicesInvoice Issued invoices (header + lines + tax) e-Factura, D300 output VAT, D394
PurchaseInvoicesInvoice Received invoices D300 input VAT, D394
PaymentsPayment Receipts/payments (relevant under cash accounting) D300 exigibility timing
MovementOfGoods Goods movements — present but empty in the current wire
AssetTransactions Asset acquisitions/disposals/depreciation The Assets annual variant

Identifiers and nomenclatures. Partner identifiers (CustomerID/SupplierID, partner RegistrationNumber) carry a 2-char ID-type prefix from the SAF-T nomenclature (00 + CUI for a Romanian company, check-digit-verified; 080000000000000 is the generic no-ID person code). The prefix table, the reporting-type codes, the account-type and tax-code lists are all in the RO_SAFT_SchemaDefCod_*.xlsx workbook — it is the source of truth for every coded value, and the DUK reference records the structure traps converged when building the minimal file.

Common scenarios

SAF-T is not authored from scratch by anafpy, so there is one worked, DUK-validated example rather than a family of hand-built instances: the committed minimal file. What a real SME file adds is described, not authored.

1 — Minimal / structural instance (the committed fixture tests/fixtures/declaratii/d406t-minimal.xml). It exercises the full skeleton with one of everything: a one-account chart, one customer, one supplier, one VAT TaxTableEntry, one UOM, one balanced two-line general-ledger transaction (debit + credit, both zero-amount), the present-but-empty MovementTypeTable/Products/Owners/Assets and SourceDocumentsMovementOfGoods. It validated clean (ok, zero findings) against D406TValidator.jar J2.0.6 on 2026-07-17. This is the pipeline proof and the shape reference; it is not a realistic period (all amounts are zero, one transaction).

2 — A real monthly SME file (not authored here) adds, on top of that skeleton: the full chart of accounts with real opening/closing balances, every customer and supplier touched in the period, the complete general-ledger journal for the month (with NumberOfEntries/TotalDebit/ TotalCredit matching the lines), and populated SalesInvoices / PurchaseInvoices / Payments under SourceDocuments. Each Transaction and each TransactionLine needs both CustomerID and SupplierID; each AmountStructure needs Amount + CurrencyCode + CurrencyAmount; each line needs TaxInformation. This is the shape the ERP emits — not DUK-exercised in this repo beyond the skeleton; the caller's file is validated on its own bytes.

What is and isn't DUK-exercised here. DUK-exercised: the skeleton above (every section present, one populated GL transaction), under both -v D406T and — by swapping only the namespace — -v D406. Not exercised: a full-volume period, populated SalesInvoices/PurchaseInvoices/Payments, the annual Assets variant, and the on-demand Stocks variant. Those validate on the ERP's own output; anafpy's role is validate → render → sign → file that output, which the D406T pipeline proves end-to-end.

Special attention & gotchas

The pitfalls below trace either to direct XSD/validator verification (the skeleton structure rules, the namespace split, the present-but-empty sections, and the ID-type prefixes were each observed against D406TValidator.jar J2.0.6 when converging the minimal file — see the DUK reference) or to an authoritative source (the ANAF SAF-T page, ANAF regional notices, and OPANAF 1783/2021 for the calendar, categories, and reconciliation). No uncorroborated practitioner claim is carried.

  • The file is ERP-produced, not hand-authored. anafpy validates, renders, signs, and files the accounting system's XML; it does not compose SAF-T the way it composes an invoice. The agent's job is to reason about a file the ERP emitted and warn about deadlines/reconciliation — not to fill elements.
  • The grace period shrinks — don't bank on it. For monthly filers it steps down 6→5→4→3→2 months over the first five reports and is gone from the sixth; for quarterly filers it is 3 months for the first quarter only. A filer who treats the first grace window as permanent misses the standard last-day deadline once grace runs out. During grace, late filing is not sanctioned; after it, art. 337¹ applies (1 000–5 000 lei).
  • Assets and Stocks are separate submissions on different clocks. Assets rides the annual financial-statements deadline, not the monthly one; Stocks is filed only on ANAF's written request (≥ 30 days). Folding them into the periodic file, or expecting a monthly cadence for them, is a common misconception.
  • Reconciliation is the real filing risk, not the XML. ANAF cross-checks SAF-T against D300 (VAT return), D394 (domestic informative), and e-Factura — the same coherence the pre-filled RO e-TVA decont relies on. Output VAT in SalesInvoices should tie to D300's collected rows and to issued e-Factura; input VAT in PurchaseInvoices to D300's deductible rows; per-partner totals to D394. A SAF-T that disagrees with the period's D300/D394 invites a conformity notification even though SAF-T itself assesses no tax.
  • ID-type prefixes and coded values come from the workbook. A partner RegistrationNumber/CustomerID/SupplierID without its 2-char SAF-T ID-type prefix fails structure validation; 00+CUI is check-digit-verified. Account types, tax codes, reporting-type and unit codes are all closed nomenclatures in RO_SAFT_SchemaDefCod_*.xlsx — never invent a code.
  • Present-but-empty sections are mandatory, not optional. MovementTypeTable, AnalysisTypeTable, and SourceDocumentsMovementOfGoods must appear as empty elements in the current wire (their children answer maxOccurs=0); omitting the container is a structure error, populating it is another. Products/Owners/Assets may be empty in a periodic file.
  • D406 vs D406T is a namespace, not a content, difference. The identical body validates under both validators — -v D406 wants mfp:anaf:dgti:d406:declaratie:v1, -v D406T wants …:d406t:…. D406T is ANAF's sanctioned no-fiscal-effect test declaration (the only permitted production test filing — DESIGN.md §12); a real filing is D406. See the D406 vs D406T section.
  • Version-alignment trap. SAF-T structure rules are period-versioned inside the validator jar (parameter tables 2019-01 → 2023-01 → 2024-01 → 2025-07), so a rule that holds for one reporting period can shift for another, and the workbook's Line naming is the newer schema's while the v1 wire element is TransactionLine. Validate against the jar for the actual reporting period; do not assume last year's structure. The D406T jars ship only in the dedicated duk_SAFT distribution and are not in the DUK update feed, so the staleness check never reports D406T — see the DUK reference.

The hands-on SAF-T work already lives elsewhere — do not duplicate it:

  • DUK reference §"The SAF-T module (D406/D406T)" — jar sourcing (the dedicated duk_SAFT distribution; the core-jar update needed to avoid NoClassDefFoundError: dec/DECTagStruct), the structure gotchas converged when building the minimal file (ID-type prefixes, empty-but-present MovementTypeTable/MovementOfGoods, BaseRate as a fraction, F: fatal findings), and the period-versioned parameters.
  • The committed minimal instance tests/fixtures/declaratii/d406t-minimal.xml (in the repo) — re-verified clean 2026-07-17 with D406TValidator.jar J2.0.6.
  • portal-upload reference §5 — the live D406T filing on the production portal (index redacted to 1100000005).

D406 vs D406T (verified 2026-07-17)

  • Same document content, two namespaces: the identical body validates clean under both validators — -v D406 wants mfp:anaf:dgti:d406:declaratie:v1, -v D406T wants mfp:anaf:dgti:d406t:declaratie:v1. Confirmed by swapping only the namespace on the committed fixture: both returned ok=True, zero findings.
  • D406T is the sanctioned no-fiscal-effect test declaration (the only permitted production filing — DESIGN.md §12); D406 is the real filing.
  • Jar sourcing differs: D406 is in the update feed (D406_35/, J2.2.18); D406T is not — its jars ship only inside duk_SAFT_*.zip, so feed_versions never reports D406T staleness.
  • Published schema file Ro_SAFT_Schema_v249_2025.xsd declares targetNamespace mfp:anaf:dgti:d406t:declaratie:v1 (the T namespace); TaxAccountingBasis enumerates the entity regimes (A, I, IFRS, BANK, INSURANCE, NORMA39, IFN, ...).

Schema entry points (for orientation)

AuditFileHeader (with TaxAccountingBasis, TaxEntity) → MasterFiles (GeneralLedgerAccounts, Customers, Suppliers, TaxTable, UOMTable, Products, PhysicalStock, Owners, Assets, and the present-but-empty MovementTypeTable) → GeneralLedgerEntriesSourceDocuments (SalesInvoices / PurchaseInvoices / Payments / MovementOfGoods / AssetTransactions). The RO_SAFT_SchemaDefCod_*.xlsx workbook is the current, authoritative element table and nomenclature source — consult it, not just the XSD, when composing a real file.

Not attempted here

A structured authoring path for SAF-T (the way anafpy.efactura.authoring covers invoices) is out of scope for this survey. SAF-T is normally produced by the caller's ERP/accounting system; anafpy's role is validate → render → sign → file the ERP's XML, which the D406T pipeline already proves end-to-end.