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:
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:
To this:
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
Inclusive
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)