oneapi
Sign in
Financiar v1 / Validare

Intra-Community VAT validation (VIES)

Checks with VIES whether a VAT number is valid for intra-Community operations and, optionally, issues the consultation number that serves as proof of the check.

It is not the same as /validare/tva. There the ANAF register is read: whether the Romanian company is VAT-registered and whether it is tax-inactive. Here the European database is queried: whether that number is valid for exchanges between member states. A tax id can be VAT-registered in Romania and not appear in VIES.

The consultation number (solicitant). If you send your own VAT number in solicitant, VIES returns a numar_consultare — the proof that you checked that partner on that date, the only thing you can show at a tax inspection to justify the VAT exemption on an intra-Community supply. Requests carrying solicitant are NEVER served from cache: a number issued for somebody else, or two hours ago, is not your proof.

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

Request body

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

NameTypeDescriptionAccepted values
codrequired string Required. The number to check, with the country prefix (RO14399840) or without it if you pass tara separately. Spaces, dots and hyphens are ignored. max 20 car.
taraoptional string | null Optional. The two letters of the member state, when the code is sent without a prefix. max 2 car.
solicitantoptional string | null Optional, but required for proof: YOUR VAT number, with prefix. Its presence requests an official consultation, with a registration number, and bypasses the cache. max 20 car.
VIES check Request body
{
    "cod": "RO14399840"
}
Code without prefix, country given separately Request body
{
    "cod": "14399840",
    "tara": "RO"
}
Another Romanian code Request body
{
    "cod": "RO6719278"
}

Query parameters

This route accepts no query parameters.

How it behaves

  • Checks with VIES whether a VAT number is valid for intra-Community transactions and, optionally, obtains the consultation number that serves as proof of the check.
  • This is not the same as /validare/tva, and the confusion costs money. There, the ANAF register is read: whether a Romanian company is VAT-registered and whether it is inactive for tax purposes. Here, the European database is queried: whether that number is valid in exchanges between member states. A Romanian tax code can be VAT-registered domestically and NOT appear in VIES — and then the supply cannot be invoiced as exempt.
  • The consultation number is the heart of this route. Send your own VAT number in solicitant and VIES issues a numar_consultare: proof that YOU checked THAT partner on THAT date. It is the only thing you can show at a tax audit to justify VAT exemption on an intra-Community supply (art. 294 of the Romanian Tax Code). Without solicitant you get the verdict, but not the proof.
  • Requests with solicitant are never served from cache. A consultation number issued for someone else, or two hours ago, is not your proof — so every such request is a real call to the Commission. Plain checks are cached.
  • The result (valid or invalid) is cached for 10 minutes, like every external check on the platform. Short on purpose: a VAT number can be cancelled, and a stale "valid" would underpin an exempt invoice issued to a partner who is no longer registered — the cost falls on the supplier.
  • Three states, not two. serviciu_indisponibil and serviciu_aglomerat return valid: null, not false. VIES has no database of its own: it queries the member state's database in real time, and those have announced periods of unavailability. Reading "unavailable" as "invalid" makes a client refuse a legitimate partner.
  • A VIES outage is not a route error. The response stays HTTP 200, with the state above and motiv says why: stat_membru_indisponibil (MS_UNAVAILABLE), aglomerat (busy), timeout, conexiune (connection failed), http_, raspuns_neinteligibil (a 200 without a verdict — usually the maintenance page), circuit_deschis (after repeated failures we stop calling for a while; meta.reia_dupa_s says how long). VIES sends some outages with HTTP 200 and isValid: false; those are not read as a verdict and are not cached.
  • Name and address appear only if the member state publishes them — some do not at all. A valid number without a name is normal, not an incomplete answer.
  • The method is POST because solicitant is YOUR VAT number: it identifies the taxable person asking, and in a query string it would end up in access logs and in browser history.
  • Greece is written EL in VIES; GR is also accepted and normalised automatically.

What it is for

  • Checking an EU partner before issuing a VAT-exempt invoice.
  • Obtaining and archiving the consultation number as proof for a tax audit.
  • Periodically re-checking recurring partners: a number valid today may be cancelled tomorrow.

Response structure

FieldTypeDescription
data.cod string Code from the source code list — the key you filter on.
data.tara string The country the value refers to.
data.numar string Number of items counted.
data.valid boolean true/false from VIES, or null when we do not know (service unavailable or busy, unknown country).
data.stare string valid, invalid, structura_invalida, tara_necunoscuta, serviciu_indisponibil, serviciu_aglomerat.
data.denumire string The name, if the member state publishes it. null otherwise.
data.adresa string The address, in the form published by the source.
data.verificat_la string The date of the check as VIES reports it. Archive it together with the consultation number.
data.numar_consultare null The number issued by VIES when you sent solicitant — the proof of the check. null on a plain check.
data.motiv null Why there was no verdict, only on serviciu_indisponibil/serviciu_aglomerat: stat_membru_indisponibil, aglomerat, timeout, conexiune, http_, raspuns_neinteligibil, circuit_deschis. null otherwise.
data.provenienta string cache, local, extern or circuit (no call: the circuit breaker is open). Requests with solicitant are never cache.
meta.sursa string The official source the data comes from, with its licence where one is required.
meta.temei string The legal basis for the values or for the way they are computed.
meta.provenienta string
meta.nota_consultare string A note on how to read the response: a caveat, a convention or a limit of the source.
meta.nota_vamal string A note on how to read the response: a caveat, a convention or a limit of the source.

Response examples

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."
    }
}

Error codes

CodeSlugWhen it occurs
401neautentificatToken missing, invalid, expired or revoked.
403feature_indisponibilThe current plan does not include the feature the route depends on.
422validarecod missing or of an impossible length. A code that is present but malformed returns 200 with stare: "structura_invalida".
429limita_taYou exceeded your rate for external checks; capacitate_serviciu — the service is at capacity, not a limit on your account. Both with Retry-After.

All errors share the same shape. eroare.cod is stable and is the value you should branch on in code — not the text in mesaj, which may change.

{
    "eroare": {
        "cod": "validare",
        "mesaj": "cod missing or of an impossible length. A code that is present but malformed returns 200 with stare: \"structura_invalida\"."
    }
}