How to use Stripe's Dynamic Tax Rate Feature for EU VAT Reporting

March 22, 2021

How CourseMaker supports EU+UK VAT reporting

As developers, we see Value Added Tax (VAT) and switch off. This is followed by a rude awakening when it's time to sell digital products to people in the EU. Note that I didn't say "businesses based in Europe"

  • if you have customers in the EU then you need to care.

Historically, this has been accompanied by lots of "surely it can't be that complicated" followed by the realization that actually, it is. Here's a classic write up from back in the day, and here's a more recent howl into the abyss.

The pain has created an entire cottage industry of SaaS products devoted to resolving exactly this problem:

  • Quaderno
  • Octobat
  • Taxamo

to name a few. Each complete with extensive blogs about the perils of not being compliant.

And for years I've thought "why can't Stripe help here?"

Well, Stripe has stepped up.

This is a big deal! It means that the SaaS payments landscape shifts from this:

payment gateway diagram

To this: payment gateway diagram updated

The New Feature

With dynamic taxes, Stripe updates your checkout on-the-fly to include tax. You can choose whether the tax is "inclusive" or "exclusive". When taxes are inclusive, the checkout total is not updated (but you still capture the tax amount for your reporting). When taxes are exclusive, then the tax is added to the checkout total.

It looks like this:

Exclusive

dynamic tax added to checkout

Inclusive

dynamic tax added to checkout

Pause and consider what a pain this feature is to implement otherwise

Where Do Tax Amounts Come From?

Now, there are some catches. This is not completely auto-magic. You first need to setup a set of Stripe tax rates which the Stripe checkout will then look to apply to a given transaction. Under the hood, the checkout looks at the billing address of the customer and sees if it matches the jurisdiction of any of the tax rates you have created.

In the next section I'll explain how to set these up for EU/UK VAT.

How to Use It

Step 1: Define your tax rates

Use Stripe.TaxRate.create docs.

Pro Tip If you are working with connected accounts, make sure you set a metadata field on the tax rates you create so in future you can access/archive tax rates you created and not interfere with any rates the connected account owner may have created.

Step 2: Update Your Stripe Checkout Code

In the below Python example, you pass a list of dynamic tax rate IDs to your Stripe checkout session creation:

line_items = {"price": price_id, "quantity": 1, "dynamic_tax_rates": dynamic_tax_rates}
session = stripe.checkout.Session.create(
customer=stripe_customer_id,
client_reference_id=client_reference_id,
payment_method_types=["card"],
line_items=line_items,
mode="payment",
success_url=success_url,
cancel_url=cancel_url,
stripe_account=stripe_account,
)

Step 3

Rejoice.

Code Samples

Here is a handy script to help you create & maintain your EU & UK VAT rates

Reporting

Once your customers are going through checkout, you can use Stripe's reporting features get the info you need for doing your tax filings. No Stripe doesn't remit the taxes for you - that would truly be the dream, but you can see why they're not rushing to volunteer to do this! For that service you'll want a merchant of record - here's an overview of the SaaS payment landscape

Compliance

I AM NOT AN ACCOUNTANT AND ANY/ALL OF THIS COULD BE WRONG It appears that the EU VATMOSS return does not expect the evidence to be included in the submission, but does expect a business to keep records of the evidence it used to determine a customer was from a given country. You can see this requirement here: "the information you used to work out where a customer is based"

Further digging uncovered this tax customs document

which contains the following "illustrative list of evidence"

  • the billing address of the customer;
  • the Internet Protocol (IP) address of the device used by the customer or any method of geolocation;
  • bank details such as the location of the bank account used for payment or the billing address of the customer held by that bank;
  • the Mobile Country Code (MCC) of the International Mobile Subscriber Identity (IMSI) stored on the Subscriber Identity Module (SIM) card used by the customer;
  • the location of the customer’s fixed land line through which the service is supplied to him;
  • other commercially relevant information

Smaller businesses (up to 100k EUR) need to keep one bit of the above evidence (see here https://ec.europa.eu/taxation_customs/business/vat/telecommunications-broadcasting-electronic-services/sites/mossportal/files/what_is_new_as_of_2019.pdf), whereas larger businesses need to keep 2 non-contradictory pieces of evidence.

Since Stripe captures the billing address and IP address, you should be covered.

I had some back-and-forth with the Stripe team about how whether any reporting tweaks are required:

They asked:

Would prefer that Stripe enforce these two pieces of non-conflicting evidence? For instance, today, the IP address may not match the card country and we'd still calculate the tax based on the card information. Would you prefer we error in this situation, or rather do you prefer the payment to go through and then perhaps we can add some sort of flag such that you know the evidence requirements were not completely fulfilled?

I've recommended that Stripe steer clear of any checkout blocks in case a customer is on vacation or some other edge case.

If anyone has set this up for US Sales tax I'd love to hear from you (chris@coursemaker.org / @chrissamiullah on twitter)

Want some tactics for your online course? Sign up to receive useful tips for new and experienced course authors, plus a free 72-page ebook.