For developers · REST and MCP

VIES API (EU VAT)
validate a VAT number, no API key

Check an EU VAT number in the VIES system (European Commission) with a single GET that returns clean JSON. You get the validity flag, the trader's name and address (when the member state discloses them; for PL numbers just the town) and a timestamp of the check. No API key, no sign-up, no daily request limit. It is a convenience layer over the VIES service (SOAP) that handles the XML envelopes for you.

One GET, one JSON

The endpoint is public, the method is GET, and the ?format=json parameter returns machine-readable data (without it you get an HTML page for humans). The path is /vies/{country}/{number} — country is a two-letter EU country code (e.g. PL, DE), number is the VAT number without the country prefix:

curl "https://skanfirmy.pl/vies/PL/5260250995?format=json"

You get the validity of the number, the trader's name and address as VIES returns them — for Polish numbers, since 26 Sep 2026, just the town instead of the address (details below) — and a timestamp of the request (proof of the check):

{
  "countryCode": "PL",
  "vatNumber": "5260250995",
  "valid": true,
  "result": "valid",
  "name": "ORANGE POLSKA SPÓŁKA AKCYJNA",
  "address": null,
  "city": "WARSZAWA",
  "requestDate": "2026-09-26T08:15:02.000Z",
  "privacy": {
    "naturalPerson": null,
    "hidden": ["address"],
    "reason": "Dane osoby fizycznej prowadzącej działalność ograniczone do niezbędnych do weryfikacji kontrahenta (RODO). Pełny wpis publikuje rejestr źródłowy (officialSource).",
    "officialSource": "https://www.gov.pl/web/kas/wykaz-podatnikow-vat"
  },
  "checkedAt": "2026-09-26"
}

The valid field is the only authoritative answer to "is this EU VAT number valid". VIES returns name and address only when the member state discloses them — some states do not, in which case they can be empty.

No API key, no sign-up, no daily limit

The endpoint works right away: no account to create, no API key to generate, no daily request limit to watch. The only restriction protects the service from abuse: at most 20 requests per 10 seconds from one IP address (above that, HTTP 429 for 10 seconds; since 25 Sep 2026). That is a deliberate difference from commercial VIES wrappers: the goal is EU-VAT validation you can wire up in a minute, including from an AI agent. The service is free of charge and meant for single lookups triggered by users or their agents, not for bulk data harvesting.

Instead of VIES SOAP

The official service is the European Commission's VIES — SOAP with a checkVat operation, XML envelopes and a response you have to parse yourself. It works, but wiring it up can take an afternoon. Our endpoint runs that whole call server-side and returns ready JSON, so on your side it stays a single GET.

What /vies/{country}/{number} returns:

FieldMeaning
validBoolean — the only authoritative answer to whether the EU VAT number is valid in VIES at the moment of the check
resultDerived field (enum), present in every response — including error ones: valid — number valid, not_registered — well-formed but unregistered number, invalid_format — malformed number or non-EU country code (HTTP 400), source_unavailable — VIES or the national registry temporarily down (HTTP 502/503), restricted — the data of a PL number is not presented (HTTP 200, no valid field). It tells a typo apart from an unregistered number
nameTrader name as VIES returns it (may be empty if the member state does not disclose it)
addressTrader address as VIES returns it (may be empty or withheld in some member states). For PL numbers, since 26 Sep 2026, always null — see city
cityPL numbers only, since 26 Sep 2026: the town from the address VIES returned
countryCodeTwo-letter EU country code from the request
vatNumberVAT number without the country prefix
requestDateVIES timestamp — proof of when the check was made
privacySince 26 Sep 2026: for PL numbers with an address — what was left out (hidden), why (reason) and where the full entry is (officialSource); null for the others
checkedAtDate of the check

A number from another member state works the same way — e.g. a German number is checked with GET /vies/DE/811128135?format=json. The country prefix (DE, PL) goes in the path as {country} and the number without the prefix as {number}.

Polish VAT numbers — change since 26 Sep 2026

VIES does not say whether a Polish VAT number belongs to a company or to a natural person running a business — and a natural person's address is personal data and is sometimes their home address. So since 26 Sep 2026, for every PL number we return just the town instead of the address: the address field is null, the town is in the city field, and the privacy field says what was left out and where the full entry is (the VAT taxpayer register on gov.pl; naturalPerson is null because VIES does not tell). Such responses carry the X-Robots-Tag: noindex and Cache-Control: private, max-age=3600 headers, and the HTML page has no name in the title or in the structured data. Numbers from other member states are returned unchanged. For full data on a Polish company, including its registered address, use /nip/{nip}. The reason text comes from the API in Polish, verbatim.

In Python

With the requests library it is a few lines — check valid right away:

import requests

def validate_eu_vat(country: str, number: str) -> dict:
    r = requests.get(f"https://skanfirmy.pl/vies/{country}/{number}?format=json", timeout=10)
    r.raise_for_status()
    data = r.json()
    if not data["valid"]:
        raise ValueError(f"EU VAT number {country}{number} is not valid in VIES")
    return data

d = validate_eu_vat("PL", "5260250995")
print(d["name"])
# ORANGE POLSKA SPÓŁKA AKCYJNA

Every response (errors included) carries a result field, so you can branch on one value instead of the HTTP status alone. The key point: a typo and an unregistered number are two different states — a malformed number is result: "invalid_format" (HTTP 400), while a well-formed but unregistered number is valid: false with result: "not_registered" (HTTP 200). So you never confuse a mistyped number with a genuine lack of registration.

In JavaScript

const r = await fetch("https://skanfirmy.pl/vies/PL/5260250995?format=json");
if (r.ok) {
  const d = await r.json();
  console.log(d.valid, d.name);
}

In PHP

$ch = curl_init("https://skanfirmy.pl/vies/PL/5260250995?format=json");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$d = json_decode(curl_exec($ch), true);
echo $d["valid"] ? $d["name"] : "number not valid";

National VAT and register data, from one NIP

VIES answers the question about an EU VAT number. If you are checking a Polish company and need its national VAT status (VAT register / White List), a KRS entry and the REGON number (except for natural persons), use /nip/{nip}?format=json — it combines those sources in one response. The other endpoints (all GET → JSON, no key):

  • /vies/{country}/{number} — EU VAT number validation (VIES, European Commission)
  • /nip/{nip} — VAT status + White List + KRS + REGON (except for natural persons)
  • /nips/{list} — several NIPs at once (comma-separated)
  • /regon/{nip} — data from the REGON register (GUS)

For AI agents, at https://skanfirmy.pl/mcp there is a Model Context Protocol (MCP) server with a tool for EU VAT validation (and several others for NIP, KRS and REGON), also with no key. A model-readable map of the endpoints is in llms.txt, and the full machine spec is in OpenAPI 3.1. For a lookup in the UI, use the VIES (EU VAT) tool.

The public endpoint vs a typical paid VIES API

Most commercial REST wrappers over VIES run on a freemium model — an account, an API key and a daily request limit on the free tier. This endpoint is public and free, and beyond valid alone it also returns the name, address and a dated proof of the check. The differences in short:

Typical paid VIES APIskanfirmy.pl /vies
API keyrequirednot needed
Registration / accountyesno
Free-tier limitusually yes20 requests per 10 s per IP, no daily quota
Response formatREST/JSONREST/JSON
MCP server for AI agentsusually noneyes
Returnsusually valid alonevalid + name + address (for PL numbers the town) + date of the check
Modelfreemium / subscriptionfree

This is not the official VIES API — the data comes from the same source (the European Commission's VIES system), just exposed with a single GET request.

Where the data comes from, and what this is not

The data comes straight from the VIES system run by the European Commission. This is an independent tool; it is not the official VIES API and is not affiliated with it — it only exposes VIES data in a more convenient form. VIES returns the name and address only when the member state discloses them, and the valid flag reflects the state at the moment in the requestDate field — the status can change later.

Frequently asked questions

Do I need an API key or to sign up?

No. The /vies/{country}/{number} endpoint is public — it returns JSON once you add ?format=json, with no API key, no account and no daily request limit.

How do I validate an EU VAT number in JSON?

Send a GET to https://skanfirmy.pl/vies/{COUNTRY}/{NUMBER}?format=json, where COUNTRY is a two-letter EU country code (e.g. DE, PL) and NUMBER is the VAT number without the country prefix. The response contains the valid field and — when the member state discloses them — the trader's name and address.

How is this different from the VIES (SOAP) service?

The official VIES service is SOAP with a checkVat operation, XML envelopes and a response you have to parse yourself. Our endpoint runs that call server-side and returns ready JSON, so on your side it stays a single GET request.

Why are the name and address sometimes empty?

VIES returns the name and address only when the member state discloses them — some states do not, in which case the name and address fields are empty. That is a limitation on the VIES side; the authoritative answer about the number's validity remains the valid field. One exception: for Polish numbers, since 26 Sep 2026 we ourselves return just the town instead of the address (the city field), because the number may belong to a natural person running a business (GDPR).

Does the check tell a typo in the number apart from an unregistered number?

Yes. A malformed number (or a non-EU country code) returns result: "invalid_format" with HTTP 400, while a well-formed but unregistered number returns valid: false with result: "not_registered" and HTTP 200. When VIES or a given member state's registry is temporarily down, you get result: "source_unavailable" (HTTP 502/503). So you never confuse a mistyped number with a genuine lack of registration — a common problem, because many checkers just return "not found" in both cases.

Is it free to use?

Yes. The endpoint is free and requires no registration. The data comes straight from the VIES system run by the European Commission, and the valid flag reflects the state at the moment in the requestDate field.