New EU VAT Regulations: A Solution with Stripe and Taxamo

This post explains how to add Taxamo to your Stripe subscription payment process so that your website can comply with new EU VAT regulations. For those who already know what these regulations are and why they suck, you can skip down to the "solution" section below where I go into it. For those who don't, let me explain/vent.


Basically, this new law impacts everyone who wants to sell digital services to customers in the EU. It doesn't matter if your business is based outside of the EU, you still will need to comply if you want to keep serving your EU customers. It doesn't matter if you are a UK business and your revenue is below the VAT threshold. If you sell something digital in Europe, you're probably affected.

Here's the blurb from HMRC's website:

Information for businesses who make cross-border supplies of digital services to consumers in other EU member states. From 1 January 2015 the place of taxation for these digital services will be the location of the consumer, not the location of the business supplying the service. This guidance explains the scope and application of these rules, as well as the options businesses have to account for the VAT involved.

In other words: previously you paid VAT based on where you business was registered. Now you pay VAT based on where you customer is located (if they are a customer from the EU).

Now, the UK government realized that this had the potential to be a horrific pain. In response, they have created a system called "VAT MOSS" which allows you to submit a document detailing the different EU VAT payments.

Using VAT MOSS, you can account for the VAT due on your business to consumer (B2C) sales in other EU countries by submitting a single quarterly return and payment to HM Revenue and Customs (HMRC).

So does VAT MOSS make everything easy then?

A bit. You are now obliged to obtain and keep 2 pieces of non-contradictory information to support and evidence the member state where the customer is normally located when you make a digital sale. The types of evidence suggested are:

  • the billing address of the customer
  • the Internet Protocol (IP) address of the device used by the customer
  • customer’s bank details
  • the country code of SIM card used by the customer
  • the location of the customer’s fixed land line through which the service is supplied
  • other commercially relevant information (for example, product coding information which electronically links the sale to a particular jurisdiction)

All this means that your website checkout process is about to get way more complicated. You've got to first capture two of these pieces of information, then check if they are non-contradictory, then calculate the VAT for the country you have calculated the customer is from (if they are in the EU), then either update the product price or take the cut in your own profit calcuation. If you know anything about web development, you will recognize that the series of things I have just described is not easy.

Let's explore some of the reasons why this law hurts small business owners

  1. The checkout process has to get more complex for the customer. 50% of my customers are accessing the service on a mobile. I've had to increase the number of form fields in order to collect the information for VAT MOSS (there was simply no way around it). Getting people to buy things on the internet is hard. Having to increase the complexity of the checkout process lowers the conversion rate, and hurts sales, especially on mobile.

  2. The complexity of implementing the change (I should note that this is if you are not using a CMS like wordpress, for which there will be easier plugin fixes). This should not be understated. I am a reasonably competent developer, and it took me a solid four full days to brainstorm, fully implement and test my solution. You can't afford not to thoroughly test something as crucial as your checkout process - and in a more complicated site with different subscription tiers, the logic can extensive. This post describes how it took four developers a week to come up with a solution. God help someone who isn't technically savvy - they will undoubtedly have to pay someone to help them do it, which is probably not going to be cheap or quick. During this time, they can't make sales. More pain for small businesses.

  3. The loss of revenue for small businesses that previously would not have had to deduct the cost of VAT from sales to customers in the EU - pretty self explanatory.

  4. The additional tax filing costs - more accountancy fees or admin.

  5. Loss of sales - if someone is on vacation, you may not be able to get your non-contradictory pieces of VAT evidence - IP address probably won't match billing address etc. There will be edge cases where sales are lost

  6. Finally, the elephant in the room: What are small business supposed to do about existing subscribers? Just email them and say, oh hey, could you tell me where you live? What percentage of those subscribers are going to reply? If the service is a game or something non-essential, that type of prying will probably prompt the user to unsubscribe.

As you may be able to tell, I do not think the new regulations are good. Here are a few questions that spring to mind:

So why is it being done?
It is being done because EU politicians want online retailers like Amazon to stop paying VAT tax at the lower rate it pays in Luxemburg. It is designed to get money out of Amazon, and it will, until they can find a different clever way to reduce their tax bill.

Fine, why can't we just apply the VAT threshold principle that applies in the UK, where small businesses that turn over less than £80,000 per year (or thereabouts) don't have to be VAT registered?

Because it's an EU thing: In some EU countries there is no VAT threshold, everyone has to pay. So it wouldn't be fair. Groan.

I was actually sufficiently annoyed about the whole thing to write to the EU. Maria Elena Scoppio wrote back to me, she is the Advisor of Pierre Moscovici, EU Commissioner for Economic and Financial Affairs, Taxation and Customs. She said some seemingly reasonable things in her defense of the policy, such as:

First of all, I would like to underline that the new VAT rules concerning the place of supply of services are an important development that will create a level playing field for micro-businesses and other companies that cannot relocate to a lower-tax Member State and who, up to now, may have lost out to more mobile competitors.

Sounds reasonable, right? Wrong. She is implying that micro businesses in other EU countries have 'lost out' because they had to pay a higher rate of VAT? Really?! I would have thought the things that caused micro businesses to 'lose out' were more likely to be poor product-market fit, poor management, insufficient capital, poor credit arrangement or unexpected growth. And for many micro business owners, the additional costs I have outlined above will far outweigh the savings from a few VAT percentage points.

Invoking the innocent-sounding term of 'level playing' field is absurd. There isn't going to be a level playing field when we have different rates of corporate and personal income tax in different EU countries, different staff wages, and different costs of capital. The blatant post-rationalization of the decision to squeeze money out of Amazon whilst cloaking it in disarming but actually completely inaccurate phrases like 'level playing field' is basically the reason why lots of people hate politicians.

Anyway, it's here now, so let's talk about the solution.


As the title of this post implies, this is how you can create a VAT compliant payment structure if you are currently using Stripe. I emailed Stripe to ask them what they recommended doing. I'll quote a lot of it, because it's all relevant:

Good point! Regarding the upcoming change in VAT rules, you will still need to handle appropriate calculation of taxes for each of your customers as you do today - it's the rules as to how to go about this that have been updated. Stripe will continue to handle charging each customer the total amount you specify at the end.

How you need to calculate the appropriate rate of VAT will differ depending on the nature of what you're selling, the type of customer you're selling to (a business or consumer), and where they are located. We recommend speaking to your accountant or tax advisor to determine the appropriate measures specific to your business.

As part of complying with the new VAT rules, you will likely need to collect various pieces of information about your customers such as billing address, IP address, country where their payment card was issued, and VAT number in the case of a business customer. Since you retain control over your full checkout flow and calculation of taxes while Stripe handles charging your customer the total amount you specify, you will need to build these steps into your own site or third-party platform you may be using.

If you're taking payments via your own site, you can use Stripe to determine the country of card issue, available through the API under the property: You can read this property as soon as you've tokenised a card, in order to help calculate the appropriate VAT rate before you actually place the charge.

You may also find one of these third-party services useful in helping you deal with the VAT rule changes and calculating the appropriate VAT rates for each customer:

For calculating tax rates and ensuring compliance:, Avalara

Specifically for invoicing:,

That's Stripe's way of basically saying: you're on your own. After sulking for a while, I decided to look at the thrid-party services Stripe recommended. Taxamo caught my attention because they supported Node.js, which my web app is built on. They also support Python, Ruby, Java and PHP.

Using the taxamo service involves quite a few steps. You won't get it up and running 'in no time'...but considering how much it is doing for you in the background, I'd say it was pretty decent.

This tutorial assumes you have applied for VAT MOSS registration. If you haven't, you need to.

For node, here's the sequence of steps:

  1. Connect to Taxamo
    On your server, connect to the Taxamo RESTful API. For this, you'll need to make sure that you add swagger-js to your package dependencies.

  1. Connect to Stripe
    Login to your Taxamo account and fill out your company details. Once you've done this you'll need to connect Taxamo to your Stripe account (this is a bit vague in the docs - go to 'integrate' and then Payment Service Providors. When you click 'connect to a Stripe account', you'll be prompted to login to Stripe and approve Taxamo. Now the two services are connected.

  1. Add your API keys
    Back on your server, add your taxamo (private) api key. Note that you'll still need your stripe keys like normal.

  2. Add taxamo.js
    Add the taxamo.js code to your html (or if you're using something like requirejs, then add it to your config setup). There is a debug version for testing, and a no-jQuery version if you are already using jQuery.

  3. Initialize Taxamo on the front-end
    In your Javascript, initialize Taxamo.

  4. Setup your Taxamo webhook in Stripe
    In your Taxamo dashboard you'll find a webhook URL for Stripe. You need to add this to your Stripe webhooks in order to do subscriptions. If you're not sure how webhooks work, I highly recommend learning more about them as they are extremely useful. Good starting points are the Stripe webhook documentation and this tutorial for node

  5. Taxamo doSubscriptionCheckout
    If you're doing just a single transaction, the Taxamo docs should suffice. For customer subscriptions, it's a little more complex.

The way I've set things up is, where previously I had a subscription checkout function that used Stripe.js to create a customer subscription, instead I've swapped in the Taxamo.js built in function: doSubscriptionCheckout()

This is where Taxamo really comes into its own. The automatically generated form basically makes the decision for you about whether to allow the customer to make the purchase, based on whether or not it is able to get two non-contradictory pieces of evidence (which comes from stuff like IP address, card CC number etc.). When the customer checks out, the new customer is registered in Stripe in exactly the same way as if you used Stripe.js. If you login to the Taxamo dashboard, you'll see the payments recorded there, with each transaction recorded with the VAT location evidence The form can be a bit sluggish, but I doubt I could code it to be faster, given how much is going on underneath the covers. It's all mobile responsive too.

  1. Updating Your App
    For more complex applications, you're probably going to want to store information about your new subscriber. So how to do this securely? Webhooks. Listen for the new subscriber event, and code the application logic there. You can query the Stripe database to get the subscriber email address (the taxamo form records this). If your web app is freemium, you can then lookup the existing customer and add new paying customer details.

  2. Refunds and Updates
    With your webhooks in place, if you want to update an existing subscriber, use the regular stripe.update function on your server and Taxamo will capture the change automatically (this is because Taxamo only concerns itself with payments, not subscription / customer details). If you flip a switch in your Taxamo dashboard settings, Stripe refunds will be propatated.

All in all, this seems to work pretty well. It's made my payment process clunkier and longer, but not unacceptably so. There are a few other minor complaints:

  • The only test cards available are for the US and Belgium.
  • The docs are pretty good, but more obscure scenarios like subscriptions and all the various edge-cases to do with them are not really documented (hence this post).
  • Limited ability to customize the taxamo form (it would be great to have an explanation for the customer about why it's confirming where they live)

On the positive side, the support desk was quite responsive - usually replying within 24 hours (better than Stripe, though I am spoiled by the amazingly quick support service I receive from mongolab). Taxamo also offer a range of reasonable payment plans, which include a pay as you go for 20 (Euro) cents per transaction.

In summary, Taxamo has made this process much easier. Unless anything goes wrong, I'll be sticking with their service.

I wish all small business owners and developers luck dealing with this particularly nasty piece of ill-conceived bureacracy.

I've created a demo repo on github to show the code for the whole process, feel free to clone it.