oneapi
Autentificare
Financiar v1 / Validare

Validare cod TVA intracomunitar (VIES)

Verifică la VIES dacă un cod de TVA e valabil pentru operaţiuni intracomunitare şi, opţional,
emite numărul de consultare care serveşte ca dovadă a verificării.

Nu e acelaşi lucru cu /validare/tva. Acolo se citeşte registrul ANAF: dacă firma românească e
plătitoare de TVA şi dacă e inactivă fiscal. Aici se întreabă baza europeană: dacă acel cod e valabil
pentru schimburi între state membre. Un CUI poate fi plătitor de TVA în România şi să nu apară în VIES.

Numărul de consultare (solicitant). Dacă trimiţi propriul cod de TVA în solicitant, VIES
întoarce un numar_consultare — dovada că tu ai verificat acel partener la acea dată, singurul lucru
pe care îl poţi arăta la un control fiscal ca să justifici scutirea de TVA la o livrare
intracomunitară. Cererile cu solicitant NU se servesc niciodată din cache: un număr emis pentru
altcineva, sau acum două ore, nu e dovada ta.

POST
https://oneapi.ro/api/financiar/v1/validare/tva/intracomunitar

Corpul cererii

Se trimite ca JSON, în corpul cererii (Content-Type: application/json) — nu în şirul de interogare.

NumeTipDescriereValori acceptate
codobligatoriu string Obligatoriu. Codul de verificat, cu prefixul de ţară (RO14399840) sau fără, dacă dai tara separat. Spaţiile, punctele şi cratimele se ignoră. max 20 car.
taraopțional string | null Opţional. Cele două litere ale statului membru, când codul e trimis fără prefix. max 2 car.
solicitantopțional string | null Opţional, dar necesar pentru dovadă: codul TĂU de TVA, cu prefix. Prezenţa lui cere o consultare oficială, cu număr de înregistrare, şi ocoleşte cache-ul. max 20 car.
Verificare în VIES Corpul cererii
{
    "cod": "RO14399840"
}
Codul fără prefix, ţara separat Corpul cererii
{
    "cod": "14399840",
    "tara": "RO"
}
Alt cod românesc Corpul cererii
{
    "cod": "RO6719278"
}

Parametri de interogare

Ruta nu acceptă parametri de interogare.

Cum se comportă

  • Verifică la VIES dacă un cod de TVA e valabil pentru operaţiuni intracomunitare şi, opţional, obţine numărul de consultare care serveşte ca dovadă a verificării.
  • Nu e acelaşi lucru cu /validare/tva, şi confuzia costă bani. Acolo se citeşte registrul ANAF: dacă firma românească e plătitoare de TVA şi dacă e inactivă fiscal. Aici se întreabă baza europeană: dacă acel cod e valabil în schimburile între state membre. Un CUI poate fi plătitor de TVA în România şi să NU apară în VIES — iar atunci livrarea nu se poate factura cu scutire.
  • Numărul de consultare e miezul rutei. Trimite propriul cod de TVA în solicitant şi VIES emite un numar_consultare: dovada că TU ai verificat ACEL partener la ACEA dată. E singurul lucru pe care îl poţi arăta la un control fiscal ca să justifici scutirea de TVA la o livrare intracomunitară (art. 294 din Codul fiscal). Fără solicitant primeşti verdictul, dar nu dovada.
  • Cererile cu solicitant nu se servesc niciodată din cache. Un număr de consultare emis pentru altcineva, sau acum două ore, nu e dovada ta — deci fiecare astfel de cerere e un apel real la Comisie. Verificările simple se cache-uiesc.
  • Rezultatul (valid sau invalid) se ţine în cache 10 minute, cât toate verificările externe ale platformei. Scurt deliberat: un cod de TVA se poate anula, iar un „valid" vechi ar sta la baza unei facturi cu scutire emise către un partener care nu mai e înregistrat — costul cade pe furnizor.
  • Trei stări, nu două. serviciu_indisponibil şi serviciu_aglomerat întorc valid: null, nu false. VIES nu are o bază proprie: întreabă în timp real baza statului membru, iar acestea au perioade de indisponibilitate anunţate. „Indisponibil" citit ca „invalid" face un client să refuze un partener legitim.
  • O pană a VIES nu e o eroare a rutei. Răspunsul rămâne HTTP 200, cu starea de mai sus şi motiv spune de ce: stat_membru_indisponibil (MS_UNAVAILABLE), aglomerat, timeout, conexiune, http_<cod>, raspuns_neinteligibil (un 200 fără verdict — de obicei pagina de mentenanţă), circuit_deschis (după eşecuri repetate nu mai sunăm un timp; meta.reia_dupa_s spune cât). VIES trimite unele pene cu HTTP 200 şi isValid: false; acelea nu sunt citite ca verdict şi nu intră în cache.
  • Denumirea şi adresa apar numai dacă statul membru le publică — unele nu o fac deloc. Un cod valabil fără denumire e normal, nu un răspuns incomplet.
  • Metoda e POST pentru că solicitant e codul TĂU de TVA: identifică plătitorul care întreabă, iar într-un query-string ar ajunge în logurile de acces şi în istoricul browserului.
  • Grecia se scrie EL în VIES; se acceptă şi GR, se normalizează automat.

La ce folosește

  • Verificarea unui partener din UE înainte de a emite o factură cu scutire de TVA.
  • Obţinerea şi arhivarea numărului de consultare, ca dovadă pentru controlul fiscal.
  • Reverificarea periodică a partenerilor recurenţi: un cod valabil azi poate fi anulat mâine.

Structura răspunsului

CâmpTipDescriere
data.cod string Codul din nomenclatorul sursei — cheia pe care se filtrează.
data.tara string Ţara la care se referă valoarea.
data.numar string Numărul de elemente numărate.
data.valid boolean true/false de la VIES, sau null când nu ştim (serviciu indisponibil ori aglomerat, ţară necunoscută).
data.stare string valid, invalid, structura_invalida, tara_necunoscuta, serviciu_indisponibil, serviciu_aglomerat.
data.denumire string Denumirea, dacă statul membru o publică. Altfel null.
data.adresa string Adresa, în forma publicată de sursă.
data.verificat_la string Data verificării, aşa cum o raportează VIES. Se arhivează împreună cu numărul de consultare.
data.numar_consultare null Numărul emis de VIES când ai trimis solicitant — dovada verificării. null la verificarea simplă.
data.motiv null De ce n-a existat verdict, doar la serviciu_indisponibil/serviciu_aglomerat: stat_membru_indisponibil, aglomerat, timeout, conexiune, http_<cod>, raspuns_neinteligibil, circuit_deschis. Altfel null.
data.provenienta string cache, local, extern sau circuit (fără apel: întrerupătorul e deschis). Cererile cu solicitant nu sunt niciodată cache.
meta.sursa string Sursa oficială din care vin datele, cu licenţa ei acolo unde e cerută.
meta.temei string Temeiul legal al valorilor sau al modului de calcul.
meta.provenienta string
meta.nota_consultare string Precizare despre cum se citeşte răspunsul: o capcană, o convenţie sau o limită a sursei.
meta.nota_vamal string Precizare despre cum se citeşte răspunsul: o capcană, o convenţie sau o limită a sursei.

Exemple de răspuns

body: {"cod": "RO14399840"}

POSThttps://oneapi.ro/api/financiar/v1/validare/tva/intracomunitar
{
    "data": {
        "cod": "RO14399840",
        "tara": "RO",
        "numar": "14399840",
        "valid": true,
        "stare": "valid",
        "denumire": "DANTE INTERNATIONAL SA",
        "adresa": "MUNICIPIUL  BUCUREŞTI, SECTOR 2 00000 STR. GARA HERĂSTRĂU Nr. 6 Et. 1,2,3,5,8",
        "verificat_la": "2026-10-06T22: 58: 02.749Z",
        "numar_consultare": null,
        "motiv": null,
        "provenienta": "extern"
    },
    "meta": {
        "sursa": "Comisia Europeană — VIES (VAT Information Exchange System).",
        "temei": "Regulamentul (UE) 904/2010; scutirea de TVA la livrări intracomunitare — art. 294 din Codul fiscal.",
        "provenienta": "Apel la VIES.",
        "nota_consultare": "Nu s-a emis număr de consultare. Trimite propriul cod de TVA în `solicitant` dacă ai nevoie de dovada verificării.",
        "nota_vamal": "Pentru operaţiuni cu ţări terţe, identificatorul e EORI, verificat prin `/validare/eori` — nu codul de TVA."
    }
}

Coduri de eroare

CodSlugCând apare
401neautentificatToken lipsă, invalid, expirat sau revocat.
403feature_indisponibilPlanul curent nu include funcţia de care ţine ruta.
422validareLipseşte cod sau are o lungime imposibilă. Un cod prezent dar malformat întoarce 200 cu stare: "structura_invalida".
429limita_taAi depăşit ritmul tău de verificări externe; capacitate_serviciu — serviciul e la capacitate, nu e o limită a contului. Ambele cu Retry-After.

Toate erorile au aceeași formă. eroare.cod e stabil și e cel după care trebuie să ramifici în cod — nu după textul din mesaj, care se poate schimba.

{
    "eroare": {
        "cod": "validare",
        "mesaj": "Lipseşte cod sau are o lungime imposibilă. Un cod prezent dar malformat întoarce 200 cu stare: \"structura_invalida\"."
    }
}