ANAF compliance · e-Invoice

You issue compliant invoices, in one call.

Turn a business JSON into valid CIUS-RO XML, validate it with the official Schematron and render it as a PDF — all through one API, without storing anything.

This is not a dataset, it is a tool. You send the invoice as an object and get back the XML, the validation verdict and, on request, the PDF. Processing happens in memory; the content never touches a disk of ours.

An object in, a compliant invoice outPOST · in memory · zero retention
POST /efactura/v1/build
{
  "furnizor": { "cui": "RO12345678", // your business object
  "client":   { "cui": "RO87654321" },
  "linii":    [ { "cantitate": 3, "pret": 100 } ]
}

// → { valid: true, xml: "<Invoice…", meta: { totals } }
What you get One POST endpoint, one invoice JSON, one response. No ANAF account held by us, no invoice written to disk — only the transformation and the verdict.
Standard
CIUS-RO / UBL 2.1
Rules
EN16931 + RO-eFactura
Operations
build · validate · parse · render
Code lists
UN/ECE, VAT rates
Retention
none
01 The problem

e-Invoice compliance is hard. And it is not your product.

Between your business object and an XML that ANAF accepts sits a layer of rules that keeps changing and that someone has to keep current.

A

CIUS-RO / UBL

An invoice is not a JSON, it is a UBL 2.1 XML with dozens of ordered elements, namespaces and strict cardinalities. One comma too many, one missing field, and the file is rejected.

B

Code lists

UN/ECE unit-of-measure codes, VAT categories and rates, tax types, country codes. Official lists with permitted values that you have to map and keep updated.

C

Dozens of tax cases

Reverse charge, exemptions with right of deduction, intra-community supply, export, cash-accounting VAT, advances, credit notes. Each has its own rules about which fields appear and which codes are allowed.

D

Schematron

Real validation is not against an XSD schema but against the EN16931 and RO-eFactura business rules, written in Schematron. Hundreds of assertions that have to be run correctly.

E

BR-RO

On top of the European rules, ANAF adds its own national constraints — tax code, address, specific codes. You pass the EN rules and fail the RO ones, or the other way round.

F

Rules that change

The specification gets revised, the code lists grow, the assertions get adjusted. What was valid last year can be rejected 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 order of elements in a UBL or the UN/ECE code for “piece”. They pay you for your product. The compliance layer is pure cost — written once and maintained indefinitely — and it is exactly what we move onto our side.
02 What it does

Four operations and a code list.

Each is an independent POST call. You use the one you need; nothing forces you through all of them.

POST /build

Build

You send the invoice as business JSON and get valid CIUS-RO XML back. Element order, namespaces, totals and codes are set correctly by us, from your object.

POST /validate

Validate

You run an existing XML through the official Schematron locally, plus a numeric check of our own on the totals. You get a verdict, the list of failed rules and the exact difference.

POST /parse

Parse

A CIUS-RO XML you received becomes clean JSON, with the fields unpacked — supplier, customer, lines, taxes, totals — so you can read it without touching UBL.

POST /render

Render

From the invoice or the XML comes a human-readable PDF, generated locally (dompdf). The view you hand your customer, without an external rendering service.

GET /codes

Code lists

The official lists the invoice accepts — units of measure, VAT categories and rates, document types, country codes — served as a reference, so you can validate from the form.

03 Zero retention

Your invoices go nowhere. Not to us, not to ANAF.

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

01

Processed in memory

The payload is never written to disk. It arrives in the request, is transformed in memory and is gone when the response leaves. There is no file of your invoice at our end.

02

Local validation

The official Schematron runs on our side, on the server holding your response. We do not send the invoice 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. Your customer’s name, the amounts, the invoice lines go into no log, neither ours nor an observability service’s.

04

Not even the XML

An optional header tells us not to return the XML either, only the verdict and the totals. For integrations where you want the validation but would rather the document did not travel back whole.

Why it matters to youAn invoice holds sensitive commercial data: who your customers are, what you sell them, at what price. 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 transforms and does not remember.
04 Official validation

We do not just say “invalid”. We say exactly what and by how much.

We run the official rules in full, locally — and add the numeric diagnosis the ANAF validator does not give you.

Official Schematron

We run the complete rule set EN16931 + CIUS-RO + RO-eFactura, the same assertions ANAF uses, executed locally. If an invoice passes with us, it passes because it follows the rules, not because we were lenient.

Our own numeric check

On top of Schematron we add a totals check of our own: base, VAT, line total, document total. When something does not add up we tell you the field and the exact difference — 0.01 lei from rounding, not “something is wrong somewhere”.

Diagnosis, not just a verdict

The ANAF validator gives you “rejected” and a code. We give you the failed rule in words, the field involved and, for totals, the expected value against the one received. The difference between knowing there is a problem and knowing where it is.

Optional ANAF cross-check

If you want confirmation from the source, you can request a cross-check against the ANAF validator for a specific invoice. It stays optional and explicit: by default, nothing leaves us for ANAF.

05 Cases covered

From plain B2B to a credit note in foreign currency.

The real tax cases, not just the textbook example. Each with the correct codes and fields, already built.

Standard B2B Multiple VAT rates Reverse charge (AE) Intra-community supply (K) Export (G) EU services (O) Non-VAT-registered supplier B2C individual Credit note Corrective invoice Advance and settlement Foreign currency Cash-accounting VAT Self-billing

We cover the CIUS-RO standard in full: FACT1 for invoices and FCN for credit notes. If you hit a case we do not handle correctly, write to us — real cases take priority in what we build.

06 Integration

An invoice object in. Valid XML out.

You send the invoice as business JSON and get the verdict, the XML and the calculated totals. No mandatory SDK — the HTTP client you already have.

POST/api/anaf/v1/efactura/buildapplication/json
# build: a minimal invoice object → valid CIUS-RO XML
curl "https://oneapi.ro/api/anaf/v1/efactura/build" \
  -H "Authorization: Bearer $ONEAPI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tip": "FACT1",
    "moneda": "RON",
    "furnizor": { "cui": "RO12345678", "nume": "Furnizor SRL" },
    "client":   { "cui": "RO87654321", "nume": "Client SRL" },
    "linii": [
      { "descriere": "Consultanță", "cantitate": 3, "pret": 100, "cota_tva": 19 }
    ]
  }'

# → 200 OK
{
  "valid": true,
  "xml":   "<Invoice xmlns=…>…</Invoice>",
  "meta":  { "totals": { "baza": 300.00, "tva": 57.00, "total": 357.00 } }
}
When validation fails

The failed rule, the field and the difference

An error response does not just say “invalid”. It gives you the rule code, its text, the field involved and — for totals — the expected value against the one received. Enough to fix it first time instead of guessing.

HTTP/1.1 422 Unprocessable Content
{ "valid": false,
  "erori": [ {
    "regula":    "BR-CO-15",
    "mesaj":     "Total nu corespunde bazei + TVA.",
    "camp":      "totals.total",
    "asteptat": 357.00, "primit": 357.01
} ] }
07 Questions

Before you send the first invoice.

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

Because the hard part is not sending it to ANAF, it is building a valid CIUS-RO XML and validating it before you send. We cover exactly that compliance layer — build, validate, parse, render — which you would otherwise write and maintain yourself. The actual filing in SPV stays with you, using your own credentials.

The first compliant invoice takes as long as reading this page. One token, one invoice JSON, valid XML back. Zero retention, from the first call.
Generate a token All modules