How to Automate VAT ID Number Checks Before Stripe Invoice Charges

Business customers enjoy special tax treatment because they are not charged a VAT in the European Union. This tutorial attempts to automate VAT compliance for your business customers.

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 ID to the customer account. Stripe will initially check the VAT ID 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: If the customer is a repeat customer, how do you know that the VAT ID number is still officially registered? You have to regularly re-validate it before every charge.

If you never re-validate a VAT ID number after the initial sign up and your customer’s VAT ID 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. Other payment aggregators offer similar webhook events.

If you store your customer’s VAT ID 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 ID number within the past 30 days (this is because the invoice.upcoming event is sent twice, 7 and 3 days before a charge and you don’t need to re-validate on both occurrences).

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 data from Stripe's payload in req.body.
  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 =

  if (event.type === 'invoice.upcoming') {
    // Checking the first tax ID only. Refactor to iteration if you save multiple tax IDs.
    var taxId = eventObject.customer_tax_ids[0]
    var threshold = moment().subtract('30', 'days').format('YYYY-MM-DD')

    var { data } = await axios.get('', {
      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 30 days, we want to skip the re-validation process.

Otherwise, we can proceed:

// Using "data" variable from the above code.

if (data.validations_count === 0) {
  var result = await'', {
    vat_id: vatId
  }, {
    headers: { Authorization: `Credential ${ process.env.VATSTACK_API_KEY }` }

  // Further processing if === 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:

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