Vatline

API documentation

Vatline validates EU VAT numbers against VIES, the VAT Information Exchange System operated by the European Commission, and returns the answer as flat JSON. Covers the 27 member states plus Northern Ireland (XI).

Quick start. Subscribe on RapidAPI (the free plan needs no card), copy your key, and run the curl example below. Your first answer arrives in under a minute.

Base URL and authentication

https://vatline.p.rapidapi.com

Every request carries the two standard RapidAPI headers. Billing, keys and quotas are handled by RapidAPI.

X-RapidAPI-Key:  YOUR_KEY
X-RapidAPI-Host: vatline.p.rapidapi.com
Content-Type:    application/json

POST /v1/check

Validate one VAT number.

FieldTypeRequiredNotes
vat_numberstringyesWith or without the country prefix. FR40303265045 and 40303265045 (with country) are equivalent. Spaces, dots and dashes are ignored.
countrystringnoTwo-letter code. Omit it when the prefix is already in vat_number. GR is accepted as an alias of EL.
requesterobjectno{"country": "FR", "vat_number": "40303265045"}: your own VAT number. Supplying it returns a VIES consultation number (see below).

curl

curl -X POST https://vatline.p.rapidapi.com/v1/check \
  -H 'Content-Type: application/json' \
  -H 'X-RapidAPI-Key: YOUR_KEY' \
  -H 'X-RapidAPI-Host: vatline.p.rapidapi.com' \
  -d '{"vat_number": "IT00743110157"}'

Python

import requests

r = requests.post(
    "https://vatline.p.rapidapi.com/v1/check",
    json={"vat_number": "IT00743110157"},
    headers={"X-RapidAPI-Key": "YOUR_KEY",
             "X-RapidAPI-Host": "vatline.p.rapidapi.com"},
    timeout=30,
)
data = r.json()
if r.ok:
    print(data["valid"], data["name"])
elif data["error"]["retryable"]:
    pass  # upstream hiccup: back off and retry later
else:
    raise ValueError(data["error"]["message"])  # fix the input

JavaScript (Node 18+)

const r = await fetch("https://vatline.p.rapidapi.com/v1/check", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-RapidAPI-Key": process.env.RAPIDAPI_KEY,
    "X-RapidAPI-Host": "vatline.p.rapidapi.com",
  },
  body: JSON.stringify({ vat_number: "IT00743110157" }),
});
const data = await r.json();

Response

{
  "valid": true,
  "country": "IT",
  "vat_number": "00743110157",
  "name": "MOTOROLA SOLUTIONS ITALIA SRL",
  "address": "LARGO FRANCESCO RICHINI 6 \n20122 MILANO MI",
  "name_available": true,
  "address_available": true,
  "consultation_number": null,
  "checked_at": "2026-10-05T22:20:58+00:00",
  "source": "upstream",
  "fetched_at_unix": 1791238858.412,
  "breaker_open": false
}
FieldMeaning
validWhether the member state recognises the number. An invalid number is still HTTP 200: read this field.
name, addressAs returned by the member state, or null when not disclosed.
name_available, address_availableRead these before treating a null as a failure. Germany and Spain never disclose name or address through VIES: the flags are false and the null is expected.
consultation_numberOnly when you sent requester. Keep it as evidence of verification in case of a tax audit.
checked_atWhen the underlying VIES answer was obtained (ISO 8601, UTC), not when you called us.
sourceupstream (fresh from VIES), cache, coalesced (shared with an identical concurrent request) or cache_stale (expired entry served because the member state is down).
fetched_at_unixSame instant as checked_at, as a Unix timestamp.
breaker_opentrue when the circuit breaker for that member state is open (only together with cache_stale).

POST /v1/check/batch

Up to 100 numbers in one call (paid plans). Each item takes the same fields as /v1/check. Duplicates share one upstream lookup. A failed item never fails the batch: it carries its own error object.

curl -X POST https://vatline.p.rapidapi.com/v1/check/batch \
  -H 'Content-Type: application/json' \
  -H 'X-RapidAPI-Key: YOUR_KEY' \
  -H 'X-RapidAPI-Host: vatline.p.rapidapi.com' \
  -d '{"items": [
        {"vat_number": "IT00743110157"},
        {"vat_number": "FR40303265045"},
        {"country": "DE", "vat_number": "129273398"}
      ]}'

The response holds count and a results array in the same order as your items. Each entry has the shape of a single check plus input, the number you sent.

Consultation number (proof of verification)

VIES only issues a consultation number when the request includes the requester's own VAT number. Add requester and Vatline switches to the VIES checkVatApprox operation. VIES issues the number only when the requester number is itself valid; otherwise the field stays null and the rest of the answer is unchanged.

Errors

Every error has the same shape. Branch on code (stable); message is for humans and may change.

{"error": {"code": "MS_MAX_CONCURRENT_REQ", "message": "...", "retryable": true}}

retryable tells you what to do: true means the failure is upstream and transient, so back off and retry; false means the same request will fail the same way.

CodeHTTPRetryWhat happened
INVALID_INPUT400noThe number does not match its member state's format or check digit. Rejected locally, never sent to VIES. The message states the expected structure.
UNAUTHORIZED401noMissing or wrong RapidAPI headers.
PAYLOAD_TOO_LARGE413noRequest body over 64 KB.
RATE_LIMITED429yesToo many requests in a short window. Honour Retry-After.
MS_MAX_CONCURRENT_REQ503yesThe member state is saturated (country-wide VIES limit).
GLOBAL_MAX_CONCURRENT_REQ503yesVIES as a whole is saturated.
MS_UNAVAILABLE503yesThe member state's system is down.
SERVICE_UNAVAILABLE, TIMEOUT, UPSTREAM_TIMEOUT503yesVIES did not answer in time or is unavailable.
COUNTRY_BREAKER_OPEN503yesRepeated failures for this country and nothing in cache: we stopped calling it for a short cooldown.
MS_INVALID_REQUEST502noThe member state rejected the request.
INTERNAL502noUnexpected error on our side. It is logged; contact us if it persists.

Service status

GET /health needs no key and returns the relay's live limits, cache statistics and per-country breaker states: api.vatlineapi.com/health. GET /health/{country} returns the breaker state of one member state; check it before sending a large batch for that country.

Caching

A valid answer is cached for 24 hours, an invalid one for 15 minutes (a number may become valid the same day). Cached answers cost the same quota but never touch VIES and come back in milliseconds. The cache survives restarts, so a redeploy never sends a burst of calls upstream.

Good practice

Vatline is an independent service. It is not affiliated with, endorsed by, or partnered with the European Commission or any national tax administration. VIES is cited only as the upstream source of the data.