Skip to main content

eu-vat-rates-data · Python

PyPI version Python versions Test Last updated License: MIT

VAT rates for 45 European countries — EU-27 plus Norway, Switzerland, UK, and more. EU rates sourced from the European Commission TEDB and checked daily. Non-EU rates maintained manually.

Part of VATNode VAT Rates · canonical dataset · methodology · other languages: JavaScript, PHP, Go, Ruby

  • Standard, reduced, super-reduced, and parking rates
  • eu_member flag on every country — True for EU-27, False for non-EU
  • vat_name — official name of the VAT tax in the country's primary official language
  • vat_abbr — short abbreviation used locally (e.g. "ALV", "MwSt", "TVA")
  • format — human-readable VAT number format (e.g. "ATU + 8 digits") — unique to this package
  • pattern — regex for VAT number validation + built-in validate_format() — free, no API key needed — unique to this package
  • Full type hints — works with mypy and pyright out of the box
  • Data embedded in the package — works offline, no network calls
  • EU rates checked daily via GitHub Actions, new version published only when rates change

Also available in: JavaScript/TypeScript (npm) · PHP (Packagist) · Go · Ruby (RubyGems)


Need live VIES validation?

This package gives you VAT rates and format checks for free, offline, in your code. It does not call VIES — validate_format() only checks the shape of a VAT number, not whether it actually exists.

For live VIES validation — confirming a VAT ID is real, pulling the registered company name and address, and getting the VIES consultation number as your reference for the check — there's vatnode:

  • Live VIES validation, with national-database fallback when VIES is down
  • Registered company name, address, registration date
  • VIES consultation number for compliance and audit trails
  • Webhooks for VAT status changes
  • Official MCP server so AI agents (Claude, Cursor, ChatGPT) can validate VAT IDs directly
  • Free tier — no credit card needed
curl https://api.vatnode.dev/v1/vat/IE6388047V \
  -H "Authorization: Bearer YOUR_API_KEY"

See what the API adds → · Get a free API key


Installation

pip install eu-vat-rates-data
# or
uv add eu-vat-rates-data
# or
poetry add eu-vat-rates-data

Usage

from eu_vat_rates_data import get_rate, get_standard_rate, get_all_rates, is_eu_member, has_rate, data_version

# Full rate object for a country
fi = get_rate("FI")
# {
#   "country": "Finland",
#   "currency": "EUR",
#   "eu_member": True,
#   "vat_name": "Arvonlisävero",
#   "vat_abbr": "ALV",
#   "standard": 25.5,
#   "reduced": [10.0, 13.5],
#   "super_reduced": None,
#   "parking": None
# }

# Just the standard rate
get_standard_rate("DE")   # → 19.0

# EU membership check — False for non-EU countries (GB, NO, CH, ...)
if is_eu_member(user_input):
    rate = get_rate(user_input)

# Dataset membership check (all 45 countries)
if has_rate(user_input):
    rate = get_rate(user_input)

# All 45 countries at once
all_rates = get_all_rates()
for code, rate in all_rates.items():
    print(f"{code}: {rate['standard']}%")

# When were EU rates last fetched?
print(data_version)  # e.g. "2026-03-27"

# VAT number format validation — no API key, no network call
from eu_vat_rates_data import validate_format
validate_format("ATU12345678")  # → True
validate_format("DE123456789")  # → True
validate_format("INVALID")      # → False

# Access format metadata directly
at = get_rate("AT")
print(at["format"])   # "ATU + 8 digits"
print(at["pattern"])  # "^ATU\\d{8}$"

# Flag emoji from a 2-letter country code — no lookup table, computed from regional indicator symbols
from eu_vat_rates_data import get_flag
get_flag("FI")  # => "🇫🇮"
get_flag("DE")  # => "🇩🇪"
get_flag("XX")  # => "" (empty string for unknown/invalid codes)

Example: charging VAT on an invoice

Rates alone do not determine invoice treatment. Resolve place-of-supply, customer status, category, exemptions, and any reverse-charge eligibility in your tax logic first; then use the dataset for the applicable numeric rate.

from eu_vat_rates_data import get_standard_rate


def invoice_total(net_cents, buyer_country, reverse_charge_eligible=False):
    """Money in minor units (cents). Never floats."""
    if reverse_charge_eligible:
        return {"vat_cents": 0, "total_cents": net_cents, "reverse_charge": True}

    rate = get_standard_rate(buyer_country)
    vat_cents = round(net_cents * rate / 100)
    return {
        "vat_cents": vat_cents,
        "total_cents": net_cents + vat_cents,
        "reverse_charge": False,
    }


# Domestic sale in Finland — 25.5%
invoice_total(10000, "FI")
# → {'vat_cents': 2550, 'total_cents': 12550, 'reverse_charge': False}

# Finnish seller, German business buyer — reverse charge
invoice_total(10000, "DE", reverse_charge_eligible=True)
# → {'vat_cents': 0, 'total_cents': 10000, 'reverse_charge': True}

reverse_charge_eligible must come from applicable tax logic and evidence. validate_format() only checks a number's shape; it does not establish registration or eligibility.


Type hints

from eu_vat_rates_data import VatRate

rate: VatRate = get_rate("FI")  # type checker knows this is a TypedDict
class VatRate(TypedDict):
    country: str
    currency: str
    eu_member: bool
    vat_name: str
    vat_abbr: str
    standard: float
    reduced: list[float]
    super_reduced: float | None
    parking: float | None
    format: str          # "FI + 8 digits"
    pattern: str         # "^FI\\d{8}$" — always present for all 45 countries

Data structure

reduced may contain rates for special territories (e.g. French DOM departments, Azores/Madeira for Portugal). For EU countries, all values come from EC TEDB.

Standard ISO 3166-1 alpha-2 country codes. Greece is GR (TEDB internally uses EL, which this package normalises).

Example

get_rate("NO")
# {
#   "country": "Norway",
#   "currency": "NOK",
#   "eu_member": False,
#   "vat_name": "Merverdiavgift",
#   "vat_abbr": "MVA",
#   "standard": 25.0,
#   "reduced": [12.0, 15.0],
#   "super_reduced": None,
#   "parking": None
# }

Data source & update frequency

How the daily check works, and what changed when: vatnode.dev/data.

  • EU-27 rates: European Commission TEDB, checked against the source daily at 07:00 UTC, updated on any change
  • Non-EU rates: maintained manually, updated on official rate changes
  • Published to PyPI only when actual rates change (not on date-only updates)

Keeping rates current

Rates are bundled at install time. A new package version is published automatically whenever rates change — but your installed version will not update itself.

Recommended: add Renovate or Dependabot to your repo. They detect new versions and open a PR automatically whenever rates change — no manual update commands needed.

Need real-time accuracy? Fetch the always-current JSON directly:

https://cdn.jsdelivr.net/gh/vatnode/eu-vat-rates-data@main/data/eu-vat-rates-data.json

No package needed — parse it with a single fetch() / http.get() / file_get_contents() call and cache locally.


Covered countries

EU-27 (checked daily against EC TEDB, updated on any change):

AT BE BG CY CZ DE DK EE ES FI FR GR HR HU IE IT LT LU LV MT NL PL PT RO SE SI SK

Non-EU Europe (manually maintained):

AD AL BA CH GB GE IS LI MC MD ME MK NO RS TR UA XK


Changelog

See CHANGELOG.md.


License

MIT

If you find this useful, a ⭐ on GitHub is appreciated.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

eu_vat_rates_data-2026.8.23.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

eu_vat_rates_data-2026.8.23-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file eu_vat_rates_data-2026.8.23.tar.gz.

File metadata

  • Download URL: eu_vat_rates_data-2026.8.23.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for eu_vat_rates_data-2026.8.23.tar.gz
Algorithm Hash digest
SHA256 e71e8edc941d2346b1137dbaf2fbaf2aba60aab320d8a68c7babf331cd1af251
MD5 9eb4b7aebd1263a7546e0a7f22eddbec
BLAKE2b-256 a7f6ea37294a0cc667a353284229bd5ca78a8f0e2f487ba2a75feb33051e2964

See more details on using hashes here.

File details

Details for the file eu_vat_rates_data-2026.8.23-py3-none-any.whl.

File metadata

File hashes

Hashes for eu_vat_rates_data-2026.8.23-py3-none-any.whl
Algorithm Hash digest
SHA256 bd61624e9a7e46df795028531844e043ae06bb658ee6c1ecec98b74ed3e0fef5
MD5 df5a8082c28f06c84a9059ea622712b4
BLAKE2b-256 f081736d997ba3ca2cb2d292067b5483db60241a637642684803243a448d28bb

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

2026.8.23 This release

2 files

2026.8.20

2 files

2026.8.19

2 files

2026.8.14

2 files

2026.8.13

2 files

2026.8.12

2 files

2026.7.1

2 files

2026.5.20

2 files

2026.4.26

2 files

2026.4.25

2 files

2026.4.24

2 files

2026.4.4

2 files

2026.4.3

2 files

2026.4.2

2 files

2026.4.1

2 files

2026.3.32

2 files

2026.3.31

2 files

2026.3.30.1

2 files

2026.3.30

2 files

2026.3.27.1

2 files

2026.3.27

2 files

2026.3.26

2 files

2026.3.25

2 files

2026.3.23

2 files

2026.3.19

2 files

2026.3.18

2 files

2026.2.25

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page