DEV Community

Alexander Nitrovich
Alexander Nitrovich

Posted on • Originally published at blog.eurovalidate.com

VAT Validation REST API Example

Validate EU VAT Numbers with a REST API

To validate an EU VAT number via REST API, send a GET request to https://api.eurovalidate.com/v1/vat/{vat_number} with your API key in the X-API-Key header. The response includes the validation status, company name, address, and a confidence score indicating data freshness. No SOAP, no XML parsing, no WSDL downloads. One HTTP call, JSON response, under 300ms.

curl Example

The fastest way to test. Replace YOUR_API_KEY with a free key from eurovalidate.com.

Valid VAT number

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

Response:

{
  "vat_number": "NL820646660B01",
  "country_code": "NL",
  "status": "valid",
  "company_name": "ABN AMRO BANK N.V.",
  "company_address": "GUSTAV MAHLERLAAN 00010\n1082PP AMSTERDAM",
  "request_id": "req_abc123",
  "meta": {
    "confidence": "high",
    "source": "vies_live",
    "cached": false,
    "response_time_ms": 247,
    "last_verified": "2026-04-08T09:00:00Z",
    "upstream_status": "ok"
  }
}
Enter fullscreen mode Exit fullscreen mode

Invalid VAT number

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

Response:

{
  "vat_number": "DE000000000",
  "country_code": "DE",
  "status": "invalid",
  "company_name": null,
  "company_address": null,
  "request_id": "req_def456",
  "meta": {
    "confidence": "high",
    "source": "vies_live",
    "cached": false,
    "response_time_ms": 189,
    "upstream_status": "ok"
  }
}
Enter fullscreen mode Exit fullscreen mode

Node.js Example

Install the SDK:

npm install @eurovalidate/sdk
Enter fullscreen mode Exit fullscreen mode
import { EuroValidate } from '@eurovalidate/sdk';

const ev = new EuroValidate('YOUR_API_KEY');

const result = await ev.validateVat('FR40303265045');

if (result.status === 'valid') {
  console.log(`Company: ${result.company_name}`);
  console.log(`Cached: ${result.meta.cached}`);
  console.log(`Confidence: ${result.meta.confidence}`);
} else {
  console.log(`VAT ${result.vat_number} is ${result.status}`);
}
Enter fullscreen mode Exit fullscreen mode

Python Example

Install the SDK:

pip install eurovalidate
Enter fullscreen mode Exit fullscreen mode
from eurovalidate import Client

client = Client(api_key="YOUR_API_KEY")
result = client.validate_vat("IT00159560366")

if result.status == "valid":
    print(f"Company: {result.company_name}")  # FERRARI S.P.A.
    print(f"Response time: {result.meta.response_time_ms}ms")
else:
    print(f"VAT {result.vat_number} is {result.status}")
Enter fullscreen mode Exit fullscreen mode

Unified Validation (VAT + IBAN + EORI in one call)

For checkout flows where you need multiple checks at once:

curl -X POST https://api.eurovalidate.com/v1/validate \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vat_number": "NL820646660B01",
    "iban": "DE89370400440532013000",
    "eori_number": "NL810002383"
  }'
Enter fullscreen mode Exit fullscreen mode

This returns all three results in a single response, saving you three round trips.

Response Fields Explained

Field Type Description
vat_number string The VAT number as submitted (normalized)
country_code string ISO 3166-1 alpha-2 (or EL for Greece)
status string valid, invalid, error, or unavailable
company_name string or null Registered company name from VIES
company_address string or null Registered address
meta.confidence string high, medium, low, or unknown
meta.source string vies_live or vies_cached
meta.cached boolean Whether the response came from cache
meta.response_time_ms integer Time to produce the response

Latency

Scenario Typical Time
Cached response (Redis hit) 1-5 ms
Live VIES call 150-300 ms
VIES slow country (DE) 500-1000 ms
IBAN (offline MOD-97) 65 ms

Cached responses are served for 24 hours after the first live check. Second and subsequent requests for the same VAT number hit the cache.

Common Pitfalls

Germany and Spain never return company names. These countries redact trader data under national data protection law. Your code should handle company_name: null for DE and ES VAT numbers.

Greece uses EL, not GR. VIES uses EL as the country prefix for Greece, but ISO 3166 uses GR. The API accepts both: EL094019245 and GR094019245 resolve to the same company.

Format validation happens locally. If you send DE12345 (too short for Germany, which requires 9 digits), the API returns HTTP 400 immediately without calling VIES. This saves your quota.

Rate limits are per API key. Free tier: 100 requests/hour. Headers X-RateLimit-Remaining and X-RateLimit-Reset tell you where you stand.

Error Handling

The API uses RFC 7807 Problem Details for errors:

{
  "type": "https://eurovalidate.dev/errors/http",
  "title": "VAT number for DE must be 9 characters (got 5)",
  "status": 400,
  "detail": "VAT number for DE must be 9 characters (got 5)..."
}
Enter fullscreen mode Exit fullscreen mode

Handle these status codes:

Code Meaning Action
200 Success (check status field) Process result
400 Bad format Fix input
401 Invalid API key Check key
429 Rate limit Wait, retry after Retry-After
502 VIES upstream down Use cached result or retry

Authentication

Pass your API key in the X-API-Key header:

X-API-Key: ev_live_your_key_here
Enter fullscreen mode Exit fullscreen mode

Get a free key (no credit card): eurovalidate.com

Pricing

Tier Price Requests
Free $0 100/hour
Starter $19/mo 5,000/hour
Growth $49/mo 25,000/hour
Scale $149/mo 100,000/hour

Next Steps

Top comments (0)