EU VAT rates database
Any european businesses are required to apply a value-added tax (VAT) on all purchases made by each of their european individual customers (B2C). Starting January 1st, 2015, the rate depends on the locality of the customer.
This project aims to centralize, in a machine-readable format (currently a plain CSV file), the list of applicable rates for each european country of residence, and all their territorial exceptions.
This is a painful job, so please help me keep this database up to date.
I'm impressed with your BFPO detail. -- Tim Whitlock
I'm glad to see independently researched data confirming mine! -- Will Bond
VAT application rules
The locality rule only concerns your european B2C customers.
Your european B2B customers are exempted of VAT, as long as they provide a registered VAT number. You can check their validity on the VAT Information Exchange System (VIES). I recommend using a third-party library to automate the process, like pyvat for Python. A B2B customer without VAT number is considered as a simple B2C customer, so local rate applies.
Note that starting January 1st, 2015, these rules applies to all non-european SaaS businesses with european customers.
This matrix expose the current completeness of the database:
|Administrative family||EU member states||Special territories, states, countries, collectivities, islands, departments, towns, …|
|Historical standard rates|
|Historical reduced rates|
|Historical increased rates|
|Historical parking rates|
|Historical currency codes|
start_date is an inclusive ISO 8601 calendar date from which the rate
starts to apply.
stop_date is an inclusive ISO 8601 calendar date from which the rate is
no longer valid.
territory_codes is a list of (eventually mixed):
- ISO 3166-1 alpha-2 country codes,
- European Commission country codes,
- ISO 3166-2 subdivision codes,
- normalized postal code with a leading ISO 3166-1 alpha-2 country codes.
rate is the decimal rate.
rate_type is the kind of rate. Either:
description human-readable description of the territory the rate applies to,
and eventual rationale behind the application.
Rows are sorted by
Staring from this database, your next step is to intepret the data.
By looking at the dates, you can compute if a rate is either current, historical or future. Beware, some rates changes in the middle of a month. That means your billing system should support application of several rates on a monthly invoice.
To choose the right rate, you then need to guess the location of your customer. I advise you to derive this data from the billing address, as it's the most common element with the necessary administrative granularity. An address that is properly normalized is precise enough, down to the postal code, to select the right VAT rule, including territorial exeptions. To solve the territory complex, I wrote a Python module to parse and normalize postal addresses.
The process of building up this database is somewhat fuzzy.
This database is unequivocally founded on the latest official VAT Rates document from the EC portal. It provides all member states' rates and their historical values. You'll also find there a description of regions and territories were special or no VAT rates applies.
Still, the hardest part of establishing this database lies in the
characterization of locality. Member states and some regions are easy: they
have a dedicated country code. For these we rely on ISO 3166-1 alpha-2, with an extra compatibility
layer for European Commission country codes (i.e. the
When this is not enough, we go down to a lower administrative level and leverage subdivision codes from ISO 3166-2.
Things get messy once VAT rules only applies to areas as small as a town. In which case I guesstimated the geographic zone with postal codes fetched from individual Wikipedia pages.
Finally, for completeness, I compiled the catalog of member's states special territories and restarted the locality characterization process for these. I was able to add the missing entries based on the list of included and excluded zones of the EU VAT area.
I decided to create this database because all the current VAT libs were quite naive about the territory definition. Most of the time it's only based on the country, while the territory a tax applies to, in a fiscal context, is a much more insidious concept carrying administrative, political and historical underlayings.
To match the place the supply takes place against the VAT database, I created a Python module to normalize and parse postal addressed of my customers.
The content of this repository is licensed under a BSD 2-Clause License.