oneapi
Sign in
Anaf v1 / Utilitare cross-zonă

Differences between two documents

Two documents of the same type, field by field: what was added, what was removed and what changed. For seeing exactly what a correction brings over the original document.

POST
https://oneapi.ro/api/anaf/v1/diff

Request body

Sent as JSON in the request body (Content-Type: application/json) — not in the query string.

NameTypeDescriptionAccepted values
arequired string The first document (the reference version), raw XML or base64.
brequired string The second document, of the same type as a, raw XML or base64.
An invoice and its correction Request body
{
    "a": "@efactura.xml",
    "b": "@efactura-corectata.xml"
}

In this example, @efactura.xml, @efactura-corectata.xml stand in for whole documents: send the file content — XML as text or base64, a PDF as base64 — not its name.

An invoice against its reversal Request body
{
    "a": "@efactura.xml",
    "b": "@efactura-stornare.xml"
}

In this example, @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.

Two transport notifications Request body
{
    "a": "@etransport.xml",
    "b": "@etransport-lic.xml"
}

In this example, @etransport.xml, @etransport-lic.xml stand in for whole documents: send the file content — XML as text or base64, a PDF as base64 — not its name.

A D100 before and after correction Request body
{
    "a": "@d100.xml",
    "b": "@d100-rectificat.xml"
}

In this example, @d100.xml, @d100-rectificat.xml stand in for whole documents: send the file content — XML as text or base64, a PDF as base64 — not its name.

Query parameters

This route accepts no query parameters.

How it behaves

  • Compares TWO ANAF documents of the same type and returns what changed, field by field — typically the "old version" against the "new version". Works across every product on the platform (e-Invoice, e-Transport, SAF-T, D declarations): the type is detected on its own from the root/namespace.
  • JSON body: {a: "<xml>", b: "<xml>"} (raw XML or base64). The comparison runs on the business JSON (the parser's output), not on raw XML, so every difference comes with a path made of named fields (linii.0.pret) rather than an XML node.
  • Lists are compared positionally, by index: a line inserted in the middle shows up as a chain of modifications plus one addition at the end. We do not guess the identity of list items.
  • Nothing is interpreted fiscally — it reports strictly what differs. Past 500 differences the response is truncated (trunchiat: true).
  • Zero retention and no SPV — everything is in-memory.

What it is for

  • See exactly what changed between the original invoice and the corrected one, before you send the credit note or the new version.
  • Check, before filing, what differs between the declaration you filed last month and the one you are preparing now.
  • Internal audit: prove which fields changed between two versions of the same document.

Response structure

FieldTypeDescription
data.tip string The detected document type (identical for both, otherwise an error).
data.produs string The product the type belongs to (efactura, etransport, saft, declaratii).
data.identice boolean true if there is no difference at all.
data.sumar object Counts: modificate, adaugate, sterse, total.
data.sumar.modificate integer
data.sumar.adaugate integer
data.sumar.sterse integer
data.sumar.total integer
data.modificate[] array Fields present in both, with different values [{cale,inainte,dupa}].
data.modificate[].cale string Path through the hierarchy, from the root down to the current item.
data.modificate[].inainte integer
data.modificate[].dupa integer
data.adaugate array Fields present only in b [{cale,valoare}].
data.sterse array Fields present only in a [{cale,valoare}].
data.trunchiat boolean true if more than 500 differences were found and the lists were cut.
meta.generat_la string When the response was built (ISO 8601).
meta.request_id string The identifier of this request. Quote it when reporting a problem — it is what the answer is found by.

Response examples

body: {"a": "@efactura.xml", "b": "@efactura-corectata.xml"}

POSThttps://oneapi.ro/api/anaf/v1/diff
{
    "data": {
        "tip": "e-Factura",
        "produs": "efactura",
        "identice": false,
        "sumar": {
            "modificate": 1,
            "adaugate": 0,
            "sterse": 0,
            "total": 1
        },
        "modificate": [
            {
                "cale": "lines.0.quantity",
                "inainte": 2,
                "dupa": 3
            }
        ],
        "adaugate": [],
        "sterse": [],
        "trunchiat": false
    },
    "meta": {
        "generat_la": "2026-10-06T23: 59: 41+03: 00",
        "request_id": "01a11303-d891-7144-ae4c-bffcf733ff72"
    }
}

Error codes

CodeSlugWhen it occurs
401neautentificatToken missing, invalid, expired or revoked.
403feature_indisponibilThe current plan does not include the feature the route depends on.
422xml_invalidMissing a or b; a document is not valid XML or is unrecognized; the two documents are of different types.
429cota_depasitaThe 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 a or b; a document is not valid XML or is unrecognized; the two documents are of different types.",
        "camp": null,
        "request_id": "0199c1f0-6e1a-7c3d-9b2f-4a8e5d1c7b04"
    }
}