ANAF compliance · SAF-T · D406

You validate and read the SAF-T file, in one call.

Check a SAF-T (D406) file against the official ANAF XSD (v2.4.9) plus checks of our own, read it as JSON with a per-section summary and render it as a PDF — all through one API, without storing anything.

We do not build the declaration from scratch — the file is produced by your ERP or accounting software. We validate it, unpack it and give you the verdict plus the summary. Processing happens in memory; the content never touches a disk of ours.

A file in, the verdict and the summary outPOST · in memory · zero retention
POST /saft/v1/validate
// multipart: fisier=D406.xml

// → { valid: true, standard: "D406", xsd_checked: "v2.4.9",
//     errors: [], warnings: [] }

POST /saft/v1/parse      // the same file, unpacked

{
  "header":  { "firma": "RO12345678", "perioada": "2026-07", "versiune": "2.4.9" },
  "rezumat": {
    "master_files": { "conturi": 412, "clienti": 1380, "furnizori": 210 },
    "jurnal":       { "nr_jurnale": 8, "total_debit": 4820140.55, "total_credit": 4820140.55 }
  }
}
What you get One POST endpoint, one SAF-T file, one response. No SPV account held by us, no file written to disk — only the validation, the summary and the verdict. Filing D406 in SPV stays with you, using your own credentials.
Standard
D406 SAF-T
Namespace
mfp:anaf:dgti:d406t
Official XSD
ANAF v2.4.9
Operations
validate · parse · render (no build)
Retention
none
01 The problem

A valid SAF-T file is hard to check. And it is not your product.

Between the file your ERP exports and a D406 that ANAF accepts at filing sits a layer of rules — schema, structure, accounting balance — that someone has to check beforehand.

A

An enormous file

SAF-T is not a form, it is an XML with an AuditFile root and the namespace mfp:anaf:dgti:d406t:declaratie:v1 — master data, the whole accounting journal and the source documents. Tens of thousands of lines, with strict structure and order.

B

The official v2.4.9 schema

The structure is checked against the official ANAF XSD, version 2.4.9. A missing element, a wrong type, a muddled order, and the file is rejected at validation.

C

Master files

The chart of accounts, customers, suppliers, the tax table, products, stock, fixed assets. Each section has its own mandatory fields and codes from the official lists.

D

Accounting journal

The complete general ledger, with every accounting entry. The debit=credit balance has to close — one difference, however small, and the declaration is wrong.

E

Source documents

Sales and purchase invoices, payments, stock movements. Linked to master files and to the journal, with coherence between totals and entries.

F

Rules that change

The schema gets revised, versions succeed one another (v2.4.9 today), the structure gets adjusted. What passed last year can fail today, and you find out from the rejection, not from an announcement.

None of this sets you apartYour customer does not pay you because you know the structure of an AuditFile or because you close the debit=credit balance by hand. They pay you for your product. The checking layer is pure cost — written once and maintained indefinitely — and it is exactly what we move onto our side.
02 What it does

Three operations and a code list. No generation.

Each is an independent POST call. We do not build the file — we validate it, read it and render it. You use the one you need.

POST /validate

Validate

You send an existing SAF-T file and get the verdict. We check it against the official ANAF XSD v2.4.9 plus checks of our own — the AuditFile root, the header, the debit=credit balance of the journal. You get what was checked, the errors and the warnings.

POST /parse

Read

A SAF-T file becomes clean JSON: the header (company, period, currency, software, version) and a per-section summary — how many accounts, customers, suppliers, products, how many journals with total debit and credit, how many documents. You read it without touching the XML.

POST /render

Render

From the file comes a human-readable summary PDF, generated locally. The header and per-section totals, for the file or for a review, without an external rendering service.

GET /codes

Code lists

The official lists D406 uses — tax codes, account types, units of measure — served as a reference, so you can check from the form before generating.

03 Zero retention

Your accounting goes nowhere. Not to us, not to ANAF.

This is the answer to “why would I send my whole ledger to a third party”. Because, in practice, you are not sending it anywhere — we process and forget.

01

Processed in memory

The file is never written to disk. It arrives in the request, is validated and read in memory and is gone when the response leaves. There is no SAF-T file of yours at our end.

02

Local validation

The official v2.4.9 XSD and our own checks run on our side, on the server holding your response. We do not send the file to ANAF to find out whether it is valid — the rules are here, the verdict is local.

03

Logs without content

What we keep is a result code and a duration — that is all. The VAT number, the accounts, the partners, the amounts go into no log, neither ours nor an observability service’s.

04

The verdict only

An optional header tells us to return only the verdict and the summary, with nothing from the content of the lines. For integrations where you want the validation but would rather the data did not travel back through the response.

Why it matters to youA SAF-T file holds the entire ledger: customers, suppliers, balances, invoices, stock, fixed assets. A service that stores it becomes a target and a liability. We chose the version where there is nothing to steal: a stateless tool that validates and reads and does not remember.
04 Official validation

We do not just say “invalid”. We say exactly what and where.

We run the official v2.4.9 XSD in full, locally, plus checks of our own, and give you the diagnosis the DUK Integrator validator does not state as clearly before filing.

Official v2.4.9 XSD schema

We check the structure against the official ANAF XSD, version 2.4.9: elements, types, order, cardinalities. If a mandatory field is missing or a type does not match, we catch it before it ever reaches SPV.

Our own checks

On top of the XSD we run our own checks: the AuditFile root and the correct namespace, a complete and coherent header, the debit=credit balance of the accounting journal. The things that pass the schema and still make the file wrong.

Diagnosis, not just a verdict

The response tells you what was checked, whether the file is valid, plus the list of errors and warnings with the rule and the place involved. The difference between knowing there is a problem and knowing where it is.

No filing in SPV

Validation is entirely local: by default, nothing leaves us for ANAF. Filing D406 through SPV stays with you, using your own credentials — we give you the verdict and the summary before that step.

05 What we cover

From the chart of accounts to the source documents.

The real sections of a D406 file, not just the header. Each validated and read, with the totals counted.

Header Chart of accounts Customers Suppliers Tax table Products Stock Fixed assets General ledger Debit=credit balance Sales invoices Purchase invoices Payments Stock movements

We cover the complete D406 file, with master files, accounting journal and source documents. If you hit a section we do not handle correctly, write to us — real cases take priority in what we build.

06 Integration

A SAF-T file in. The verdict and the summary out.

You send the file and get the validation verdict or the JSON with header and summary. No mandatory SDK — the HTTP client you already have.

POST/api/anaf/v1/saft/validateapplication/json
# validate: a D406 file → a verdict against the official v2.4.9 XSD + our own checks
curl "https://oneapi.ro/api/anaf/v1/saft/validate" \
  -H "Authorization: Bearer $ONEAPI_TOKEN" \
  -F "fisier=@d406_2026_07.xml"

# → 200 OK
{
  "valid":       true,
  "standard":    "D406",
  "xsd_checked": "v2.4.9",
  "errors":      [],
  "warnings":    []
}
When validation fails

What was checked, the rule and the place

A validation response does not just say “invalid”. It tells you what was checked — the v2.4.9 XSD and our own checks — whether it is valid, plus the errors and warnings with the rule involved. Enough to fix it first time instead of guessing.

HTTP/1.1 422 Unprocessable Content
{ "valid": false,
  "standard":    "D406",
  "xsd_checked": "v2.4.9",
  "errors": [ {
    "regula": "SAFT-BAL-01",
    "mesaj":  "Jurnal: debit ≠ credit (Δ 0.02).",
    "camp":   "GeneralLedgerEntries"
} ], "warnings": [] }
07 Questions

Before you file the first D406.

The rest, in the frequently asked questions and in the documentation.

No. The SAF-T file is produced by your ERP or accounting software — that is where the master data, the journal and the source documents come from. We do not build a D406 from scratch (full generation is deferred). What we cover is the checking and reading layer: validate, parse, render. Filing in SPV stays with you.

The first validation takes as long as reading this page. One token, one SAF-T file, the verdict and the summary back. Zero retention, from the first call.
Generate a token All modules