If you run an online subscription business, you’ll ultimately end up signing up customers from the European Union.

Tax Treatment for Business Customers

A business customer does not need to pay VAT. In order to verify that your customer is in fact a business customer, you have to ask for their VAT identification number and validate it in real-time.

If you use Stripe to handle subscription charges (there’s no reason why you shouldn’t), then you can simply add your business customer’s VAT number to the customer account. Stripe will initially check the VAT number registration status for you, but only once.

Upon positive validation, the reverse-charge mechanism applies. Reverse-charge is a legal term and means that the obligation to report VAT on a delivery has been reversed from the supplier to the customer. The customer is now made responsible to report and pay VAT, but since a business does not need to pay VAT, it’s a zero-sum.

Here’s the catch for recurring payments such as subscriptions: If the customer is a repeat customer, how do you know that the VAT number is still valid? You have to regularly re-validate it before every charge.

If you never re-validate a VAT number after the initial sign up and your customer’s VAT number expires, you suddenly face an unfortunate situation whereby you owe a VAT amount which you’ve never collected from your customer.

Webhook Events Trigger Re-Validation

Stripe emits webhook events whenever an invoice becomes due for charge. You can listen to the invoice.upcoming event and look up your customer by the customer ID included in the event’s payload. This type of event is emitted when an invoice is due in 7 and 3 days, respectively.

If you store your customer’s VAT number in Stripe’s records, you can pass the tax ID stored in the customer_tax_ids array to perform a re-validation with Vatstack. We store all your validation records securely in the cloud and you gain full traceability of your customer’s status.

What you could do on your backend is to query whether Vatstack has an entry for the same VAT number within the past 28 days (this accounts for shorter months such as February). The invoice.upcoming event is ideal to trigger re-validation. It’s sent twice, 7 and 3 days before a charge by default and we want to re-validate only on one occurrence.

const axios = require('axios')
const moment = require('moment')
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)

// Exportable router module.
module.exports.stripe = async (req, res, next) => {
  // Extract event object from Stripe’s payload.
  var sig = req.headers['stripe-signature']
  var event = await stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_KEY)

  if (!event.type) {
    // Error handling for invalid event.

  var eventObject = event.data.object

  if (event.type === 'invoice.upcoming') {
    // Iterate through stored tax IDs for the Stripe customer.
    await Promise.all(event.object.customer_tax_ids.map(taxId => {
      var threshold = moment().subtract('28', 'days').format('YYYY-MM-DD')

      var { data } = await axios.get('https://api.vatstack.com/v1/validations', {
        params: {
          key: process.env.VATSTACK_API_KEY,
          query: taxId.value,
          requested_since: threshold,



The above code uses the axios, moment and stripe NPM libraries. It first extracts Stripe’s event payload with a signature, then checks whether Vatstack has any historical record for the tax ID saved in your customer’s record on Stripe.

If there’s a result from the past 28 days, we want to skip the re-validation process as it’s either the 2nd invoice.upcoming event or it could be a recent signup.

Otherwise, we can proceed:


// Using "data" variable from the above code.
if (data.validations_count === 0) {
  var result = await axios.post('https://api.vatstack.com/v1/validations', {
    vat_id: taxId
  }, {
    headers: { Authorization: `Credential ${ process.env.VATSTACK_API_KEY }` }

  // Further processing if result.data.valid === false.


This creates a validation request with Vatstack and, in most cases, it will respond with an official result immediately. The response contains a valid boolean which you can use for further processing.

Automate Change of Tax Treatment

You can automate the change of tax treatment until there is no human intervention involved on your side. Several approaches come to mind:

  • Automated notification to customers: You can send your customer an automated email with the message that their VAT number is no longer valid and, as a result, you’re going to cancel the reverse-charge mechanism unless they enter a new VAT number (which will have to be validated of course).
  • Start collecting VAT: A failure to add a new VAT number would result in you collecting a VAT at their local rate in the upcoming invoices. Geolocated price quotations can also be performed with Vatstack and the obtained tax rate updated in Stripe.
  • Clean up tax IDs on Stripe: Remove the outdated VAT number from Stripe’s customer field customer_tax_ids.