e-Invoice ↔ SAF-T reconciliation
Compares the invoices you issued against what appears in the SAF-T file and shows the mismatches both ways: invoices missing from the D406 and D406 entries with no invoice.
Request body
Sent as JSON in the request body (Content-Type: application/json) — not in the query string.
{id, xml}. With id, the rows in lipsa_in_saft, diferente_valoare and numere_duplicate carry your identifier. An item that is neither XML nor {id, xml} returns 422 with its position.
{
"saft": "@saft-d406.xml",
"facturi": [
"@efactura.xml"
]
}
In this example, @saft-d406.xml, @efactura.xml stand in for whole documents: send the file content — XML as text or base64, a PDF as base64 — not its name.
{
"saft": "@saft-d406.xml",
"facturi": [
"@efactura.xml",
"@efactura-stornare.xml"
]
}
In this example, @saft-d406.xml, @efactura.xml, @efactura-stornare.xml stand in for whole documents: send the file content — XML as text or base64, a PDF as base64 — not its name.
{
"saft": "@saft-d406.xml",
"facturi": [
"@efactura-stornare.xml"
]
}
In this example, @saft-d406.xml, @efactura-stornare.xml stand in for whole documents: send the file content — XML as text or base64, a PDF as base64 — not its name.
Query parameters
How it behaves
- Compares the issued invoices (e-Invoice XMLs) against the sales invoices reported in the SAF-T file (D406,
SourceDocuments/SalesInvoices), by invoice number. Catches what does not line up between the two reports: invoices present on one side but not the other, and totals (VAT-inclusive) that differ. - JSON body:
{saft: "<xml>", facturi: ["<xml>", ...]}(raw XML or base64). Matched by number, and amounts are compared in whole bani (no floating-point pitfalls). On the e-Invoice side we readTaxInclusiveAmount(BT-112), which carries the same meaning as SAF-T'sGrossTotal— notPayableAmount, which subtracts prepayments and would produce false mismatches. - If the same number appears twice on the same side (typically an invoice and a credit note sharing a number), the row is reported under
numere_duplicateinstead of being silently overwritten. - Zero retention and no SPV — everything is in-memory; nothing is submitted.
What it is for
- Check that the SAF-T for the month contains exactly the invoices issued via e-Invoice, with the same amounts, before filing.
- Quickly find the missing invoice or the wrong amount among hundreds of documents.
Response structure
true if there is at least one mismatch.
facturi_efactura, facturi_saft, lipsa_in_saft, lipsa_in_efactura, diferente_valoare, numere_duplicate.
[{id?,numar,tip,total}]; id appears only if you sent one.
[{numar,total}].
[{id?,numar,efactura,saft,diferenta}].
[{id?,numar,sursa,tip}].
Response examples
body: {"saft": "@saft-d406.xml", "facturi": ["@efactura.xml"]}
{
"data": {
"are_diferente": true,
"sumar": {
"facturi_efactura": 1,
"facturi_saft": 2,
"lipsa_in_saft": 0,
"lipsa_in_efactura": 1,
"diferente_valoare": 0,
"numere_duplicate": 0
},
"lipsa_in_saft": [],
"lipsa_in_efactura": [
{
"numar": "FCT-2026-0143",
"total": 1210
}
],
"diferente_valoare": [],
"numere_duplicate": []
},
"meta": {
"generat_la": "2026-10-06T23: 59: 41+03: 00",
"request_id": "01a11303-d87c-724c-9897-cd8c69f79a4e"
}
}
body: {"saft": "@saft-d406.xml", "facturi": ["@efactura.xml", "@efactura-stornare.xml"]}
{
"data": {
"are_diferente": true,
"sumar": {
"facturi_efactura": 2,
"facturi_saft": 2,
"lipsa_in_saft": 1,
"lipsa_in_efactura": 1,
"diferente_valoare": 0,
"numere_duplicate": 0
},
"lipsa_in_saft": [
{
"numar": "STN-2026-0007",
"tip": "CreditNote",
"total": 242
}
],
"lipsa_in_efactura": [
{
"numar": "FCT-2026-0143",
"total": 1210
}
],
"diferente_valoare": [],
"numere_duplicate": []
},
"meta": {
"generat_la": "2026-10-06T23: 59: 41+03: 00",
"request_id": "01a11303-d882-736e-919d-8f6e74d3cc14"
}
}
body: {"saft": "@saft-d406.xml", "facturi": ["@efactura-stornare.xml"]}
{
"data": {
"are_diferente": true,
"sumar": {
"facturi_efactura": 1,
"facturi_saft": 2,
"lipsa_in_saft": 1,
"lipsa_in_efactura": 2,
"diferente_valoare": 0,
"numere_duplicate": 0
},
"lipsa_in_saft": [
{
"numar": "STN-2026-0007",
"tip": "CreditNote",
"total": 242
}
],
"lipsa_in_efactura": [
{
"numar": "FCT-2026-0142",
"total": 847
}
],
"diferente_valoare": [],
"numere_duplicate": []
},
"meta": {
"generat_la": "2026-10-06T23: 59: 41+03: 00",
"request_id": "01a11303-d889-7047-b8de-15b09f9de9bd"
}
}
Error codes
| Code | Slug | When it occurs |
|---|---|---|
| 401 | neautentificat | Token missing, invalid, expired or revoked. |
| 403 | feature_indisponibil | The current plan does not include the feature the route depends on. |
| 422 | xml_invalid | Missing saft or facturi, or a document is not valid XML; over 5000 invoices. |
| 429 | cota_depasita | The plan's monthly quota has been exceeded (see Retry-After). |
Errors in the Anaf module use the same envelope as the rest of the platform, with two extra fields: {eroare: {cod, mesaj, camp, request_id}}. eroare.cod is stable and is what you branch on; on validation (422) the code is case-specific: xml_invalid, xml_nu_e_factura, unitate_necunoscuta, luna_invalida and so on. camp points at the offending field when one can be identified.
{
"eroare": {
"cod": "xml_invalid",
"mesaj": "Missing saft or facturi, or a document is not valid XML; over 5000 invoices.",
"camp": null,
"request_id": "0199c1f0-6e1a-7c3d-9b2f-4a8e5d1c7b04"
}
}