oneapi
Sign in
Anaf v1 / e-Factura

Build invoice

You send the invoice as JSON and get the CIUS-RO XML (UBL 2.1) back, run through the XSD and the Schematron rules before it is handed to you. With validate=anaf you can also ask for the ANAF validator's verdict.

POST
https://oneapi.ro/api/anaf/v1/efactura/build

Request body

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

Two-line invoice Request body
{
    "number": "FCT-2026-0142",
    "issue_date": "2026-09-10",
    "due_date": "2026-10-10",
    "currency": "RON",
    "supplier": {
        "name": "Exemplu Furnizor SRL",
        "vat_id": "RO990000005",
        "address": {
            "country": "RO",
            "city": "Cluj-Napoca",
            "street": "Str. Memorandumului 28",
            "county": "RO-CJ"
        }
    },
    "customer": {
        "name": "Exemplu Client SRL",
        "vat_id": "RO990000072",
        "address": {
            "country": "RO",
            "city": "SECTOR1",
            "street": "Calea Victoriei 1",
            "county": "RO-B"
        }
    },
    "lines": [
        {
            "name": "Servicii de consultanţă",
            "quantity": 2,
            "unit": "H87",
            "unit_price": 100,
            "vat": {
                "rate": 21
            }
        },
        {
            "name": "Licenţă software anuală",
            "quantity": 1,
            "unit": "H87",
            "unit_price": 500,
            "vat": {
                "rate": 21
            }
        }
    ]
}
Credit note (reversal) Request body
{
    "type": "credit_note",
    "number": "STN-2026-0007",
    "issue_date": "2026-09-20",
    "currency": "RON",
    "supplier": {
        "name": "Exemplu Furnizor SRL",
        "vat_id": "RO990000005",
        "address": {
            "country": "RO",
            "city": "Cluj-Napoca",
            "street": "Str. Memorandumului 28",
            "county": "RO-CJ"
        }
    },
    "customer": {
        "name": "Exemplu Client SRL",
        "vat_id": "RO990000072",
        "address": {
            "country": "RO",
            "city": "SECTOR1",
            "street": "Calea Victoriei 1",
            "county": "RO-B"
        }
    },
    "lines": [
        {
            "name": "Stornare servicii de consultanţă",
            "quantity": 1,
            "unit": "H87",
            "unit_price": 200,
            "vat": {
                "rate": 21
            }
        }
    ],
    "preceding_invoices": [
        {
            "number": "FCT-2026-0142",
            "issue_date": "2026-09-10"
        }
    ]
}
Intra-community supply, in euro Request body
{
    "number": "FCT-2026-0150",
    "issue_date": "2026-09-25",
    "due_date": "2026-10-25",
    "currency": "EUR",
    "exchange_rate": 5.0821,
    "supplier": {
        "name": "Exemplu Furnizor SRL",
        "vat_id": "RO990000005",
        "address": {
            "country": "RO",
            "city": "Cluj-Napoca",
            "street": "Str. Memorandumului 28",
            "county": "RO-CJ"
        }
    },
    "customer": {
        "name": "Exemplu Client GmbH",
        "vat_id": "DE999000009",
        "address": {
            "country": "DE",
            "city": "Muenchen",
            "street": "Leopoldstrasse 1",
            "county": "DE-BY"
        }
    },
    "delivery": {
        "date": "2026-09-24",
        "address": {
            "country": "DE",
            "city": "Muenchen",
            "street": "Leopoldstrasse 1",
            "county": "DE-BY"
        }
    },
    "lines": [
        {
            "name": "Licenţă software anuală",
            "quantity": 1,
            "unit": "H87",
            "unit_price": 1200,
            "vat": {
                "rate": 0,
                "category": "K"
            }
        }
    ]
}

Query parameters

NameTypeDescriptionAccepted values
validateoptional string Validation layer: local (default, official Schematron run locally), anaf (local + ANAF-validator cross-check), none (generate only, no validation). e.g. locale.g. anafe.g. none
strictoptional boolean true (default) returns 422 with no XML if validation fails; false returns the XML anyway, with valid: false and the errors. e.g. false
formatoptional text Shape of the XML in the response: xml (default, text) or base64. e.g. base64

How it behaves

  • Takes a business JSON — seller, buyer, lines, rates — and returns the invoice as CIUS-RO (UBL 2.1) XML, ready to file with ANAF. It is the inverse of /anaf/v1/efactura/parse: there you read an invoice you received, here you build your own.
  • The VAT category is derived automatically from context — the rate, the customer country, the presence and type of the VAT number — never declared by hand. The engine covers the full fiscal spectrum: standard rate, multi-rate invoices, reverse charge (AE), intra-community supply (K), export (G), services to the EU (O), non-VAT payer, B2C with the fiscal code filled with 13 zeros, credit note, corrective invoice, advance payment, foreign currency, cash-basis VAT and self-billing.
  • validate selects the validation layer. At local (the default) the official Schematron (EN 16931 + CIUS-RO + RO-eFactura) runs locally through Saxon — the same rule set ANAF applies, without the payload leaving the process. At anaf an ANAF-validator cross-check is added; at none only the XML is generated, with no validation.
  • strict decides what happens when validation fails. At true (the default) the response is 422 and you get no XML — the invoice cannot be filed, so there is no point returning it. At false you get the XML anyway, with valid: false and the list of errors, so you can inspect and fix it.
  • Zero retention. The payload is not written to disk, not logged, and never enters cache keys. The route is POST and non-cacheable precisely because an invoice carries commercial and personal data that has no place in access logs or telemetry.
  • Structural errors (missing field, impossible rate, totals that do not add up) come back as 422 in the common {eroare:{cod,mesaj,camp}} shape, where camp points to exactly where the problem is in the JSON you sent.
  • The body fields are in English, the one exception across the platform (every other route uses Romanian names). The reason: the input mirrors the EN 16931 / UBL semantic model (supplier, issue_date, unit_price, vat_id), so a JSON field reads straight into the specification with no dictionary in between. Error messages stay in Romanian.
  • An unknown body field is rejected, not ignored. unit_code instead of unit, seller instead of supplier — you get 422 camp_necunoscut with the list accepted at that level. Otherwise you would have got a valid invoice built on defaults, never learning your value was not read.

What it is for

  • Generating CIUS-RO XML from an internal invoice model, before filing it in SPV.
  • Producing a credit note or a corrective invoice from data you already hold.
  • Checking, at validate=local, that an invoice passes the official Schematron without sending it to ANAF yet.

Response structure

FieldTypeDescription
data.valid boolean The validation result; null when validate=none.
data.standard string Detected standard: FACT1 (invoice) or FCN (credit note).
data.xml string The generated CIUS-RO XML; text or base64 depending on format.
data.meta.customization_id string The CIUS-RO identifier of the specification applied.
data.meta.document_type_code string The document type code (e.g. 380 invoice, 381 credit note).
data.meta.totals object The computed totals: base, VAT, amount due.
data.meta.totals.lines_net integer
data.meta.totals.allowance_total integer
data.meta.totals.charge_total integer
data.meta.totals.taxable_base integer
data.meta.totals.vat integer
data.meta.totals.gross integer
data.meta.totals.prepaid integer
data.meta.totals.rounding integer
data.meta.totals.payable integer
data.meta.vat_breakdown[] array The breakdown by VAT category, with each one's base and rate.
data.meta.vat_breakdown[].category string
data.meta.vat_breakdown[].rate integer
data.meta.vat_breakdown[].base integer
data.meta.vat_breakdown[].amount integer
data.errors array Validation errors, when strict=false (with strict=true they come in the error envelope).
data.warnings array Non-blocking warnings, in the {cod,mesaj,camp} shape.
meta.generat_la string When the response was built (ISO 8601).

Response examples

body: {"number": "FCT-2026-0142", "issue_date": "2026-09-10", "due_date": "2026-10-10", "currency": "RON", "supplier": {"name": "Exemplu Furnizor SRL", "vat_id": "RO990000005", "address": {"country": "RO", "city": "Cluj-Napoca", "street": "Str. Memorandumului 28", "county": "RO-CJ"}}, "customer": {"name": "Exemplu Client SRL", "vat_id": "RO990000072", "address": {"country": "RO", "city": "SECTOR1", "street": "Calea Victoriei 1", "county": "RO-B"}}, "lines": [{"name": "Servicii de consultanţă", "quantity": 2, "unit": "H87", "unit_price": 100, "vat": {"rate": 21}}, {"name": "Licenţă software anuală", "quantity": 1, "unit": "H87", "unit_price": 500, "vat": {"rate": 21}}]}

POSThttps://oneapi.ro/api/anaf/v1/efactura/build
{
    "data": {
        "valid": true,
        "standard": "FACT1",
        "xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\" xmlns:cac=\"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\" xmlns:cbc=\"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\">\n  <cbc:CustomizationID>urn:cen.eu:en16931: 2017#compliant#urn:efactura.mfinante.ro:CIUS-RO: 1.0.1</cbc:CustomizationID>\n  <cbc:ID>FCT-2026-0142</cbc:ID>\n  <cbc:IssueDate>2026-09-10</cbc:IssueDate>\n  <cbc:DueDate>2026-10-10</cbc:DueDate>\n  <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>\n  <cbc:DocumentCurrencyCode>RON</cbc:DocumentCurrencyCode>\n  <cac:AccountingSupplierParty>\n    <cac:Party>\n      <cac:PostalAddress>\n        <cbc:StreetName>Str. Memorandumului 28</cbc:StreetName>\n        <cbc:CityName>Cluj-Napoca</cbc:CityName>\n        <cbc:CountrySubentity>RO-CJ</cbc:CountrySubentity>\n        <cac:Country>\n          <cbc:IdentificationCode>RO</cbc:IdentificationCode>\n        </cac:Country>\n      </cac:PostalAddress>\n      <cac:PartyTaxScheme>\n        <cbc:CompanyID>RO990000005</cbc:CompanyID>\n        <cac:TaxScheme>\n          <cbc:ID>VAT</cbc:ID>\n        </cac:TaxScheme>\n      </cac:PartyTaxScheme>\n      <cac:PartyLegalEntity>\n        <cbc:RegistrationName>Exemplu Furnizor SRL</cbc:RegistrationName>\n      </cac:PartyLegalEntity>\n    </cac:Party>\n  </cac:AccountingSupplierParty>\n  <cac:AccountingCustomerParty>\n    <cac:Party>\n      <cac:PostalAddress>\n        <cbc:StreetName>Calea Victoriei 1</cbc:StreetName>\n        <cbc:CityName>SECTOR1</cbc:CityName>\n        <cbc:CountrySubentity>RO-B</cbc:CountrySubentity>\n        <cac:Country>\n          <cbc:IdentificationCode>RO</cbc:IdentificationCode>\n        </cac:Country>\n      </cac:PostalAddress>\n      <cac:PartyTaxScheme>\n        <cbc:CompanyID>RO990000072</cbc:CompanyID>\n        <cac:TaxScheme>\n          <cbc:ID>VAT</cbc:ID>\n        </cac:TaxScheme>\n      </cac:PartyTaxScheme>\n      <cac:PartyLegalEntity>\n        <cbc:RegistrationName>Exemplu Client SRL</cbc:RegistrationName>\n      </cac:PartyLegalEntity>\n    </cac:Party>\n  </cac:AccountingCustomerParty>\n  <cac:TaxTotal>\n    <cbc:TaxAmount currencyID=\"RON\">147.00</cbc:TaxAmount>\n    <cac:TaxSubtotal>\n      <cbc:TaxableAmount currencyID=\"RON\">700.00</cbc:TaxableAmount>\n      <cbc:TaxAmount currencyID=\"RON\">147.00</cbc:TaxAmount>\n      <cac:TaxCategory>\n        <cbc:ID>S</cbc:ID>\n        <cbc:Percent>21</cbc:Percent>\n        <cac:TaxScheme>\n          <cbc:ID>VAT</cbc:ID>\n        </cac:TaxScheme>\n      </cac:TaxCategory>\n    </cac:TaxSubtotal>\n  </cac:TaxTotal>\n  <cac:LegalMonetaryTotal>\n    <cbc:LineExtensionAmount currencyID=\"RON\">700.00</cbc:LineExtensionAmount>\n    <cbc:TaxExclusiveAmount currencyID=\"RON\">700.00</cbc:TaxExclusiveAmount>\n    <cbc:TaxInclusiveAmount currencyID=\"RON\">847.00</cbc:TaxInclusiveAmount>\n    <cbc:PayableAmount currencyID=\"RON\">847.00</cbc:PayableAmount>\n  </cac:LegalMonetaryTotal>\n  <cac:InvoiceLine>\n    <cbc:ID>1</cbc:ID>\n    <cbc:InvoicedQuantity unitCode=\"H87\">2</cbc:InvoicedQuantity>\n    <cbc:LineExtensionAmount currencyID=\"RON\">200.00</cbc:LineExtensionAmount>\n    <cac:Item>\n      <cbc:Name>Servicii de consultanţă</cbc:Name>\n      <cac:ClassifiedTaxCategory>\n        <cbc:ID>S</cbc:ID>\n        <cbc:Percent>21</cbc:Percent>\n        <cac:TaxScheme>\n          <cbc:ID>VAT</cbc:ID>\n        </cac:TaxScheme>\n      </cac:ClassifiedTaxCategory>\n    </cac:Item>\n    <cac:Price>\n      <cbc:PriceAmount currencyID=\"RON\">100.00</cbc:PriceAmount>\n    </cac:Price>\n  </cac:InvoiceLine>\n  <cac:InvoiceLine>\n    <cbc:ID>2</cbc:ID>\n    <cbc:InvoicedQuantity unitCode=\"H87\">1</cbc:InvoicedQuantity>\n    <cbc:LineExtensionAmount currencyID=\"RON\">500.00</cbc:LineExtensionAmount>\n    <cac:Item>\n      <cbc:Name>Licenţă software anuală</cbc:Name>\n      <cac:ClassifiedTaxCategory>\n        <cbc:ID>S</cbc:ID>\n        <cbc:Percent>21</cbc:Percent>\n        <cac:TaxScheme>\n          <cbc:ID>VAT</cbc:ID>\n        </cac:TaxScheme>\n      </cac:ClassifiedTaxCategory>\n    </cac:Item>\n    <cac:Price>\n      <cbc:PriceAmount currencyID=\"RON\">500.00</cbc:PriceAmount>\n    </cac:Price>\n  </cac:InvoiceLine>\n</Invoice>\n",
        "meta": {
            "customization_id": "urn:cen.eu:en16931: 2017#compliant#urn:efactura.mfinante.ro:CIUS-RO: 1.0.1",
            "document_type_code": "380",
            "totals": {
                "lines_net": 700,
                "allowance_total": 0,
                "charge_total": 0,
                "taxable_base": 700,
                "vat": 147,
                "gross": 847,
                "prepaid": 0,
                "rounding": 0,
                "payable": 847
            },
            "vat_breakdown": [
                {
                    "category": "S",
                    "rate": 21,
                    "base": 700,
                    "amount": 147
                }
            ]
        },
        "errors": [],
        "warnings": []
    },
    "meta": {
        "generat_la": "2026-10-06T23: 59: 42+03: 00"
    }
}

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_invalidInvalid business JSON (missing/wrong field) or — at strict=true — an invoice that fails validation. The body carries error plus errors[]/warnings[].
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": "Invalid business JSON (missing/wrong field) or — at strict=true — an invoice that fails validation. The body carries error plus errors[]/warnings[].",
        "camp": "validate",
        "request_id": "0199c1f0-6e1a-7c3d-9b2f-4a8e5d1c7b04"
    }
}