DEV Community

Alexander Nitrovich
Alexander Nitrovich

Posted on • Originally published at blog.eurovalidate.com

Validate EU VAT in Node.js (5 Lines of Code)

Validate EU VAT in Node.js (5 Lines of Code)

You can validate any EU VAT number in Node.js by calling the EuroValidate REST API. Install the SDK, pass a VAT number, and get back a typed result with the company name, address, and a confidence score -- all in under 5 milliseconds for cached lookups. No SOAP parsing, no XML, no VIES downtime headaches. Here is the minimal working example.

Quick start

Install the SDK:

npm install @eurovalidate/sdk
Enter fullscreen mode Exit fullscreen mode

Validate a VAT number in 5 lines:

import { EuroValidate } from "@eurovalidate/sdk";

const client = new EuroValidate("ev_live_your_key_here");

const result = await client.validateVat("NL820646660B01");
console.log(result.valid, result.companyName);
// true "COOLBLUE B.V."
Enter fullscreen mode Exit fullscreen mode

That is it. The SDK handles retries on rate limits (429 with Retry-After), timeouts, and error mapping automatically.

Using curl instead

If you prefer to test from the terminal before writing any code:

curl -H "X-API-Key: ev_live_your_key_here" \
  https://api.eurovalidate.com/v1/vat/NL820646660B01
Enter fullscreen mode Exit fullscreen mode

What the API returns

Valid VAT number

Request: GET /v1/vat/NL820646660B01

{
  "vat_number": "NL820646660B01",
  "country_code": "NL",
  "status": "valid",
  "company_name": "COOLBLUE B.V.",
  "company_address": "Weena 664 3012CN ROTTERDAM",
  "request_id": "req_abc123",
  "meta": {
    "confidence": "high",
    "source": "vies_live",
    "cached": false,
    "response_time_ms": 247,
    "last_verified": "2026-04-05T10:15:30Z",
    "upstream_status": "ok"
  }
}
Enter fullscreen mode Exit fullscreen mode

Invalid VAT number

Request: GET /v1/vat/NL000000000B00

{
  "vat_number": "NL000000000B00",
  "country_code": "NL",
  "status": "invalid",
  "company_name": null,
  "company_address": null,
  "request_id": "req_def456",
  "meta": {
    "confidence": "high",
    "source": "vies_live",
    "cached": false,
    "response_time_ms": 189,
    "last_verified": "2026-04-05T10:15:35Z",
    "upstream_status": "ok"
  }
}
Enter fullscreen mode Exit fullscreen mode

The status field is one of: valid, invalid, error, or unavailable. The confidence field tells you how fresh the data is: high means a live upstream check, medium means served from cache, low means the upstream was down and you are getting stale data.

TypeScript support

The SDK ships with full type definitions. Every response is a typed interface:

import { EuroValidate, VatResult } from "@eurovalidate/sdk";

const client = new EuroValidate("ev_live_your_key_here");

const result: VatResult = await client.validateVat("FR40303265045");

if (result.valid) {
  console.log(`Company: ${result.companyName}`);
  console.log(`Address: ${result.companyAddress}`);
  console.log(`Confidence: ${result.meta?.confidence}`);
} else {
  console.log(`VAT number ${result.vatNumber} is not valid`);
}
Enter fullscreen mode Exit fullscreen mode

The VatResult interface gives you autocomplete for valid, vatNumber, countryCode, companyName, companyAddress, status, meta, and requestId.

Error handling

The SDK throws typed errors you can catch:

import { EuroValidate, RateLimitError, AuthError } from "@eurovalidate/sdk";

const client = new EuroValidate("ev_live_your_key_here");

try {
  const result = await client.validateVat("NL820646660B01");
  console.log(result.valid);
} catch (err) {
  if (err instanceof RateLimitError) {
    // Automatic retry handles most 429s, but if retries are exhausted:
    console.log("Rate limited. Try again later.");
  } else if (err instanceof AuthError) {
    console.log("Invalid API key.");
  } else {
    throw err;
  }
}
Enter fullscreen mode Exit fullscreen mode

Latency

Typical response times you can expect:

Scenario Latency
Cached result (Redis hit) 1--5 ms
Live VIES lookup 150--300 ms
VIES unavailable, stale cache returned 2--8 ms

Once a VAT number is validated, the result is cached for 24 hours. Subsequent lookups for the same number hit the Redis cache and return in single-digit milliseconds. For high-traffic applications, this means the majority of your requests resolve almost instantly.

Common pitfalls

Germany and Spain never return company names

The German (DE) and Spanish (ES) tax authorities do not return trader name or address through VIES. This is a data protection policy at the country level, not a bug. When you validate a German VAT number, company_name and company_address will be null even if the number is valid.

EuroValidate works around this by cross-referencing GLEIF data (the Global LEI system) when available, but coverage depends on whether the company holds an LEI.

Greece uses EL, not GR

VIES uses the prefix EL for Greece, but ISO 3166 uses GR. The API accepts both -- you can pass EL820646660 or GR820646660 and the mapping is handled automatically. The country_code field in the response always returns the ISO code (GR).

Northern Ireland dual status

Northern Ireland businesses may have both a UK VAT number (GB prefix) and an EU EORI number (XI prefix) for customs. If you are handling cross-border e-commerce involving Northern Ireland, validate both the VAT and EORI separately.

VIES downtime

The VIES service operated by the European Commission has a historical uptime around 70%. Individual country backends go down independently -- Germany alone accounts for the majority of VIES errors. EuroValidate uses per-country circuit breakers so that one country going offline does not affect lookups for other countries. When a country backend is unavailable, the API returns the last cached result with confidence: "low" and upstream_status indicating the issue.

Unified validation

If you need to validate a VAT number and an IBAN in a single request, use the unified endpoint:

const client = new EuroValidate("ev_live_your_key_here");

const response = await fetch("https://api.eurovalidate.com/v1/validate", {
  method: "POST",
  headers: {
    "X-API-Key": "ev_live_your_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    vat_number: "NL820646660B01",
    iban: "DE89370400440532013000"
  })
});

const data = await response.json();
console.log(data.vat.status);  // "valid"
console.log(data.iban.valid);  // true
Enter fullscreen mode Exit fullscreen mode

This counts as one API call against your quota.

Pricing

The free tier includes 100 requests per hour -- enough to build and test your integration. Paid plans start at EUR 19/month for 5,000 requests.

Plan Price Requests/month
Free EUR 0 100/hr
Starter EUR 19/mo 5,000
Growth EUR 49/mo 25,000
Scale EUR 149/mo 100,000

Next steps

  1. Get your free API key -- takes 30 seconds, no credit card required.
  2. Read the full API docs -- interactive Swagger UI where you can test every endpoint.
  3. Explore the IBAN endpoint -- validate IBANs and get bank name + BIC in the same call.
  4. Batch validation -- validate up to 1,000 VAT numbers in a single async request.

EuroValidate is a unified REST API that replaces 5 fragmented EU government services (VIES, EORI, IBAN, GLEIF, national registries) with a single JSON endpoint. Built for developers who need reliable EU business data validation without dealing with SOAP/XML, per-country downtime, or inconsistent response formats.

Top comments (0)