Skip to content

D390 — EU recapitulative statement (VIES)

The declarație recapitulativă privind livrările/achizițiile/prestările intracomunitare is the monthly informative that feeds the EU-wide VIES system: it summarizes, per partner and per operation type, the intra-EU goods/services you supplied and acquired so member states can cross-match each other's declarations. This file is a completion guide: what the declaration reports, who files it and when, and how each field maps onto the XSD attribute anafpy authors — followed by the technical XSD/DUK layer. ANAF's validator jar (D390Validator.jar) and the OPANAF 705/2020 instructions are the authority; this guide is a distilled bridge, not a re-implementation of the rules. Everything below the "Common scenarios" instances was proven hands-on on 2026-07-17 against J4.1.2 (XSD v3).

D390 carries no tax and settles no payment — it is a reconciliation feed. Every intra-EU transaction is reverse-charged (the tax is accounted for in the acquirer's member state), so the recapitulative statement exists purely so that national administrations can match a Romanian supplier's declared supply against the counterpart's declared acquisition. It reports six operation types (see the code table below): supplies and acquisitions of goods, triangular supplies, services rendered and received, and farmer-regime supplies.

  • Current model: approved by OPANAF 705/2020 (M.Of. 234/18.03.2020), used for reporting periods from 02/2020 onward. It introduced the v3 schema (namespace mfp:anaf:dgti:d390:declaratie:v3), which added the call-off-stock annex (cos) and the R operation type (farmer regime). Legal basis: art. 325 of the Fiscal Code (Legea 227/2015); obligated persons per art. 316 / 317.
  • Periodicity: monthly only — D390 has no quarterly election (unlike D300). The reporting period is carried by luna + an.
  • e-TVA note: OUG 70/2024 (pre-filled RO e-TVA) amended art. 325 so that the deadline is set by ANAF order rather than fixed in the Code; the order kept it at the 25th (see Who files & when).

Who files & when

  • Who: taxable persons registered for VAT under art. 316 or art. 317 of the Fiscal Code who, in a given month, carried out at least one intra-EU operation of the reportable types. Art. 317 (special registration, e.g. for intra-EU acquisitions above the threshold or for services) covers persons who are not registered under the full art. 316 regime but still owe a D390 for their intra-EU services/acquisitions.
  • Deadline: the 25th (inclusive) of the month following the reporting month. If the 25th is a non-working day, it rolls to the next working day. Confirmed two ways: the OPANAF 705/2020 instructions ("până la data de 25 inclusiv a lunii următoare unei luni calendaristice") and the CECCAR Business Magazine deadline note (the 25th was kept after the e-TVA / OUG 70/2024 art.325 change — a proposal to move it earlier did not take effect).
  • Only file when there ARE intra-EU operationsa nil D390 is NOT filed. This is the sharpest departure from D300 (which requires a decont for every period, nil included). The recapitulative summarizes operations that occurred; a month with no intra-EU supplies, acquisitions, triangular operations or services produces no D390 at all. Do not file an empty statement to "keep the streak" — there is no zero-line valid instance (the schema requires at least one operatie; see the gotchas).
  • Corrections — d_rec (declarație rectificativă): d_rec="0" is the initial statement, d_rec="1" a rectificative. A rectificative is a full replacement, not a delta: per the instructions, "se completează toate rubricile formularului cu datele valabile la momentul declarării" — re-file the entire corrected month with all lines (the unchanged ones too), each carrying the value valid at declaration time. A rectificative can also touch transactions from any prior reporting period. There is no separate "annulment" document — you overwrite the period by re-declaring it.

Filling guide

The document is a small tree, not a flat attribute bag like D300. The root <declaratie390> carries the header/identification attributes; its children, in this exact XSD order, are one <rezumat> (the totals block), zero or more <cos> (the call-off-stock annex), and one or more <operatie> (the per-partner-per-type summary lines). Every euro of intra-EU activity is folded into an operatie line; rezumat is the arithmetic roll-up of those lines and must reconcile with them (the jar recomputes and checks every total).

One line per (country, partner code, name, type). You do not list invoices — you list partners. All of a month's supplies of goods to one German customer collapse into a single operatie tip="L" line with the summed baza. The 4-tuple (tara + codO + denO + tip) must be unique across lines (duplicate = error); aggregate before authoring.

Header / identification block (root attributes)

Attribute Form field Notes
luna Perioada de raportare – Luna reporting month 1–12
an Perioada de raportare – An reporting year (≥ 2020 for v3; XSD range 2017–2100)
d_rec Declarație rectificativă 0 = inițială, 1 = rectificativă (full re-file)
nume_declar / prenume_declar / functie_declar Nume / Prenume / Funcție declarant required text
cui Cod de înregistrare în scopuri de TVA CUI check-digit enforced by the jar (N(10))
den Denumire / Nume și Prenume required
adresa Adresă domiciliu fiscal required
telefon / fax / mail contact optional
totalPlata_A Suma de control control sum — not a payment; formula below

totalPlata_A = nrOPI + bazaL + bazaT + bazaA + bazaP + bazaS + bazaR (rule R13 — the operator count plus the six per-type base totals). For the minimal one-supply instance below that is 1 + 1000 = 1001. Compose it from the rezumat values; the jar recomputes and rejects a wrong sum.

rezumat — the totals block (all attributes required)

Attribute Form field Formula (jar-enforced)
nr_pag Număr total pagini anexă annex page count, N(1) (0–9)
nrOPI Numărul total al operatorilor intracomunitari = COUNT(operatie)
bazaL L – Livrări intracomunitare de bunuri = Σ baza where tip="L"
bazaT T – Livrări în cadrul unei operațiuni triunghiulare = Σ baza where tip="T"
bazaA A – Achiziții intracomunitare de bunuri = Σ baza where tip="A"
bazaP P – Prestări intracomunitare de servicii = Σ baza where tip="P"
bazaS S – Achiziții intracomunitare de servicii = Σ baza where tip="S"
bazaR R – Livrări IC de bunuri (regim special agricultori) = Σ baza where tip="R"
total_baza Total bază de impozitare din anexă = Σ baza (all lines)

Every baza* total the type produced no lines is "0" (the attribute is required, so it is present as zero, never omitted).

operatie — the summary lines (one or more)

Attribute Form field Notes
tip Tip operațiune enum L/T/A/P/S/R (see code table)
tara Țara operator intracomunitar EU 2-letter code — includes XI, no GB
codO Cod operator intracomunitar (fără prefixul de țară) partner VAT number without country prefix; per-country checksum; required for L/T/P/R, may be absent for A/S
denO Denumire operator intracomunitar required
baza Bază impozabilă required, integer RON

Operation-type codes (tip enum)

Code Meaning (ANAF label) Side
L Livrări intracomunitare de bunuri (intra-EU supplies of goods) output
T Livrări în cadrul unei operațiuni triunghiulare (triangular supplies) output
A Achiziții intracomunitare de bunuri (intra-EU acquisitions of goods) input
P Prestări intracomunitare de servicii (intra-EU services rendered) output
S Achiziții intracomunitare de servicii (intra-EU services received) input
R Livrări IC de bunuri în cadrul regimului special pentru agricultori output

The direction matters: P is a service you supply to an EU customer (place of supply in their state), S a service you receive from an EU supplier; L/A are the goods analogues. Get the letter wrong and the counterpart's member state cannot match the line.

cos — call-off-stock annex (zero or more, optional)

Only for the stocuri la dispoziția clientului regime (goods moved to an EU warehouse before the customer takes title). Most SMEs never file a cos line.

Attribute Form field Notes
tip Secțiunea (A/B) A = dispatches under the regime; B = changes to a prior registration
tara_m1 / cod_m1 Țara / Cod persoană impozabilă required (the customer's state + VAT code)
motiv Motivul modificării 1 = retur bunuri, 2 = înlocuire client; required if tip="B", must be null for tip="A"
tara_m2 / cod_m2 al doilea operator required if motiv="2" (the substitute customer); null otherwise

Common scenarios

Both instances below validated clean (ok) against D390Validator.jar J4.1.2 on 2026-07-17; the minimal one also rendered to a PDF via -p. The synthetic cui="1234565" is check-digit valid; DE136695976 is the classic TAXUD test VAT number that passes the German algorithm, and FR40303265045 is a key-valid French number.

1 — Minimal (one intra-EU supply of goods): 1 000 RON of goods supplied to one German customer, June 2026. nrOPI="1", bazaL="1000", total_baza="1000", totalPlata_A="1001" (= 1 + 1000).

<?xml version="1.0" encoding="UTF-8"?>
<declaratie390 xmlns="mfp:anaf:dgti:d390:declaratie:v3"
  luna="6" an="2026" d_rec="0"
  nume_declar="Popescu" prenume_declar="Ion" functie_declar="Administrator"
  cui="1234565" den="EXEMPLU TEST SRL" adresa="Mun. Bucuresti, Str. Exemplu nr. 1"
  totalPlata_A="1001">
  <rezumat nr_pag="1" nrOPI="1" bazaL="1000" bazaT="0" bazaA="0" bazaP="0"
    bazaS="0" bazaR="0" total_baza="1000"/>
  <operatie tip="L" tara="DE" codO="136695976" denO="Partner GmbH" baza="1000"/>
</declaratie390>

2 — Several partners and types: a 1 000 RON supply of goods to a German customer (L), a 2 000 RON acquisition of goods from a French supplier (A), and a 500 RON service rendered to the German customer (P). Three operatie lines → nrOPI="3"nrOPI counts lines, not distinct partners (the DE partner appears on both an L and a P line); per-type totals bazaL=1000, bazaA=2000, bazaP=500; total_baza="3500"; totalPlata_A="3503" (= 3 + 3500).

<?xml version="1.0" encoding="UTF-8"?>
<declaratie390 xmlns="mfp:anaf:dgti:d390:declaratie:v3"
  luna="6" an="2026" d_rec="0"
  nume_declar="Popescu" prenume_declar="Ion" functie_declar="Administrator"
  cui="1234565" den="EXEMPLU TEST SRL" adresa="Mun. Bucuresti, Str. Exemplu nr. 1"
  totalPlata_A="3503">
  <rezumat nr_pag="1" nrOPI="3" bazaL="1000" bazaT="0" bazaA="2000" bazaP="500"
    bazaS="0" bazaR="0" total_baza="3500"/>
  <operatie tip="L" tara="DE" codO="136695976" denO="Partner GmbH" baza="1000"/>
  <operatie tip="A" tara="FR" codO="40303265045" denO="Fournisseur SARL" baza="2000"/>
  <operatie tip="P" tara="DE" codO="136695976" denO="Partner GmbH" baza="500"/>
</declaratie390>

3 — Correction (rectificativă): same shape as the initial statement but d_rec="1", re-declaring the whole corrected month with all partners and their now-correct baza (not only the changed line). If a partner drops out entirely, omit its line and adjust the rezumat totals; the rectificative stands in place of the original.

Nil month: there is no instance — a month with no intra-EU operations is not filed (see Who files & when).

Special attention & gotchas

The pitfalls below trace either to direct XSD/validator/annex verification (the totalPlata_A formula, the codO-required-vs-optional split, the per-country checksum, the cos minOccurs discrepancy, and the rezumat reconciliation were each observed against D390Validator.jar J4.1.2 / the structure annex) or to an authoritative source (OPANAF 705/2020 for the obligated persons, deadline, nil-not-filed and rectificative semantics; CECCAR for the deadline confirmation). No uncorroborated practitioner claim is carried.

  • A nil D390 is not filed. Unlike D300, there is no such thing as an empty D390 — the schema requires at least one operatie, and the obligation only arises in months with reportable intra-EU operations. Filing "nothing" means filing nothing at all.
  • codO is mandatory for L/T/P/R but may be absent for A/S (structure annex rule 24). For your own supplies of goods, triangular supplies, services rendered and farmer-regime supplies the partner's VAT code is required; for acquisitions of goods and services received the code may be missing (e.g. a supplier who did not give a valid code). Omitting codO on an L/T/P/R line is a hard error.
  • codO is checksum-validated with the per-country VIES/TAXUD algorithm (rule R24.1: "trebuie să respecte algoritmul specific ''"). The number is carried without the country prefix — the country goes in tara. Synthetic data needs genuinely key-valid foreign VAT numbers (DE136695976, FR40303265045 pass). Verify every partner code in VIES before filing — an invalid or de-registered partner code is the single most common rejection/query cause.
  • totalPlata_A is a control sum, not a payment: = nrOPI + bazaL + bazaT + bazaA + bazaP + bazaS + bazaR (rule R13). D390 never moves money. (This formula is documented in the structure annex — it supersedes the earlier "let the validator dictate it" note in the v3 section below.)
  • rezumat must reconcile with the operatie lines exactly. nrOPI = COUNT(operatie), each baza<X> = Σ baza over tip="X", total_baza = Σ all baza (rules R14–R21). A single miscounted operator or mistyped total fails.
  • (tara + codO + denO + tip) must be unique. Duplicate lines are rejected (rule R24, "aparții multiple"); aggregate a partner's month into one line per type. Exception observed in the annex: for tip="A" the same codO may carry multiple denO values; for any other type one code maps to one name.
  • XI (Northern Ireland) replaces GB; Great Britain is out of VIES. Post-Brexit, goods to/from Northern Ireland use tara="XI" (validated with the old GB algorithm); the country list has no GB. Transactions with Great Britain proper are exports/imports (third country), not D390 lines — putting a GB partner on a D390 is a category error.
  • The cos element is XSD-required but validator-optional (XSD vs jar). The schema's <xs:sequence> declares cos with the default minOccurs="1", which would demand at least one call-off-stock row; the structure annex documents it as "0-n apariții" and the validator accepts zero cos elements (both instances above validate clean without one). The validator/annex win — for an ordinary filer cos is absent. Only emit cos for the call-off-stock regime.
  • Rectificative is a full re-file, not a patch. With d_rec="1" you resubmit the entire corrected month; the new statement replaces the prior one. Sending only the changed line loses every other partner.
  • Cross-form: D390 must reconcile with the D300 decont's intra-EU rows. ANAF cross-checks the recapitulative against the VAT return of the same period and the partner codes against VIES; mismatches generate query letters. The correspondences: L ↔ D300 Rd.1 (intra-EU supplies of goods, exempt), A ↔ D300 Rd.5/Rd.20 (intra-EU acquisitions, reverse-charged on both legs), P (services rendered, place of supply abroad) ↔ D300 Rd.3/3.1, S (services received) ↔ D300 Rd.7.1/Rd.22.1. Reconcile the per-partner totals with the sales/purchase journals before filing so the D390 sum ties to the decont's intra-EU lines.
  • cui check digit is enforced beyond the XSD pattern ([1-9]\d{1,9}) — the jar rejects a wrong checksum (1234565 is valid synthetic data).

v3 (current; XSD d390_12022021.xsd, jar J4.1.2)

  • Namespace mfp:anaf:dgti:d390:declaratie:v3, root declaratie390. Older schemas on the page: v2 = d390_20170131.xsd, v1 = d390_20130729.xsd. Caution: a stale validator jar (see the trap below) rejects v3 and demands v1 — if DUK ever answers "Valoarea corecta este xmlns='…v1'" for a current period, the installed jar is outdated, the XML is not wrong.
  • Shape: header attributes on the root (luna, an, d_rec 0/1 rectifying flag, declarant name/function, cui, den, adresa, totalPlata_A), then children: one rezumat + repeated operatie rows (and cos rows for call-off-stock).
  • rezumat (all required): nr_pag, nrOPI (operator count), per-type bases bazaL/bazaT/bazaA/bazaP/bazaS/bazaR, total_baza. They must agree with the operatie lines.
  • operatie: tip (enum L/T/A/P/S/R — supplies, triangular, acquisitions, services rendered, services received, R added in v3), tara (EU list — includes XI Northern Ireland, no GB), codO (partner VAT number without country prefix), denO, baza.
  • codO is checksum-validated with the per-country algorithm (rule R24.1: "trebuie sa respecte algoritmul specific 'DE'"). Synthetic data needs genuinely valid foreign VAT numbers — the classic German test number 136695976 (DE136695976) passes.
  • cui check digit enforced (as on every form; 1234565 works).
  • totalPlata_A is a control sum (rule R13), not an amount. The formula is nrOPI + bazaL + bazaT + bazaA + bazaP + bazaS + bazaR (documented in the structure annex — Special attention & gotchas).
  • Minimal valid instance (one 1000 RON intra-EU supply to a German partner, June 2026):
<?xml version="1.0" encoding="UTF-8"?>
<declaratie390 xmlns="mfp:anaf:dgti:d390:declaratie:v3"
  luna="6" an="2026" d_rec="0"
  nume_declar="Popescu" prenume_declar="Ion" functie_declar="Administrator"
  cui="1234565" den="EXEMPLU TEST SRL" adresa="Mun. Bucuresti, Str. Exemplu nr. 1"
  totalPlata_A="1001">
  <rezumat nr_pag="1" nrOPI="1" bazaL="1000" bazaT="0" bazaA="0" bazaP="0"
    bazaS="0" bazaR="0" total_baza="1000"/>
  <operatie tip="L" tara="DE" codO="136695976" denO="Partner GmbH" baza="1000"/>
</declaratie390>

The stale-jar trap (how this page was almost wrong)

http://static.anaf.ro/static/10/Anaf/update5/D390/D390Validator.jar — the unversioned directory one would guess from the feed's layout — serves the original 2012 release (J1.0.0), which only knows namespace v1 and predates bazaR/tip="R". The feed's real JURL points into a versioned directory (update5/D390_11/ at J4.1.2). Always install jars from the feed's JURL/PURL verbatim; never construct the URL by pattern. (The same applies to every form — D394's unversioned directory likewise serves a 2012 jar.)