Blog

Why price × standard rate is the wrong way to calculate EU VAT

Most EU VAT code starts like this:

const vat = price * (standardRate[country] / 100);
const total = price + vat;

It works for the first sale and the demo. It is also wrong in at least five ways that show up later, usually at the worst possible time: during a refund, a correction or an audit.

1. Rates change, and VAT uses the rate on the date of the sale

A table of today's rates answers the wrong question. VAT is due at the rate that applied when the sale happened.

Rates change more often than people expect. Germany cut its standard rate from 19% to 16% for the second half of 2020. Finland went from 24% to 25.5% in September 2024. Each change means:

  • a refund for a sale before the change must use the old rate,
  • a sale made in December and invoiced in January can straddle a change,
  • a correction to an earlier quarter's return uses that quarter's rates.

So the lookup needs a date: rate(country, date), not rate(country). Historical rate data needs checking too: even official sources get past rates wrong.

2. Not everything uses the standard rate

EU countries may apply reduced rates to some products. For digital sellers the big one is electronic publications: e-books, e-newspapers and e-magazines.

Country Standard rate E-books
Germany 19% 7%
France 20% 5.5%
Italy 22% 4%
Spain 21% 4%
Netherlands 21% 9%
Ireland 23% 0%

If you sell e-books and multiply by the standard rate, you overcharge your customers. If you sell e-books and templates and use one rate for both, one of them is wrong.

3. Business customers usually pay no VAT at all

When the customer is a business with a valid VAT number in another EU country, you normally don't charge VAT. The customer accounts for it under the reverse charge, and your invoice says so.

That means the calculation depends on who the customer is, and the VAT number needs checking in VIES (the EU's VAT number lookup) before you rely on it. A number the customer typed into a form proves nothing until it's checked.

4. Where you are based changes the answer

For a business established in one EU country, cross-border sales of digital services to consumers below €10,000 a year can be taxed at the seller's own rate. Above it, the customer's rate applies. The test also looks at the previous year.

For a business outside the EU, there's no threshold: the customer's rate applies from the first sale.

So standardRate[customerCountry] can be wrong for a small EU seller, and right for a US one, for the same sale.

5. Floating-point money and rounding

0.1 + 0.2 === 0.30000000000000004 // true

Money in binary floating point drifts, and VAT amounts need rounding to the cent at a defined point. Rounding each invoice line and then adding gives a different total from adding and then rounding. Use integer cents or a decimal type, and pick one rounding rule on purpose.

What the calculation actually needs

Put together, a correct VAT calculation needs at least:

  • the customer's country,
  • the date of the sale,
  • the product category (standard, or e-book and similar),
  • whether the customer is a business, and if so a checked VAT number,
  • where you are established, and for an EU seller, your cross-border sales so far this year and last year,
  • decimal arithmetic with an explicit rounding rule.

That is a lot more than a multiplication. It's the reason Duty27 exists. A request looks like this:

{
  "country_code": "DE",
  "date": "2020-08-01",
  "amount": "100.00",
  "amount_type": "NET",
  "b2b": false,
  "category": "EBOOK"
}

The response gives you the rate that applied on that date (rate_percent), the net, tax and gross amounts as decimal strings, and whether the reverse charge applies. You can try a calculation on the homepage without signing up, and the API docs cover the rest, including business customers and the €10,000 threshold.

Get an API keyRead the docs

General information, not tax advice. Confirm your own situation with a tax adviser or your tax authority.