VAT Validation for Stripe Users: Coverage Gaps

Stripe is the most popular payment platform for SaaS businesses. It includes built-in VAT validation, but that validation has significant limitations. This guide covers exactly what Stripe validates, what it doesn't, and when you need a standalone VAT validation API alongside Stripe.

What Stripe actually validates

Stripe automatically validates tax IDs against government databases for three regions only:

  • EU VAT numbers via VIES
  • UK VAT numbers via HMRC
  • Australian ABNs via ABR

For all other tax ID types (100+ types across 50+ countries), Stripe only does format validation. It checks if the number matches the expected pattern but does not verify it exists in any government database.

From Stripe's own documentation: "If automatic validation isn't available, you must manually verify these IDs."

Stripe Tax applies reverse charge based on format alone, not validation. A correctly formatted but fake VAT number would still trigger reverse charge in Stripe.

Five gaps in Stripe's VAT validation

No Swiss validation

Stripe stores CH tax IDs but does not validate them against the BFS UID Register. Format check only. If you sell to Swiss businesses, you cannot rely on Stripe to confirm the number is real. See the Swiss VAT validation guide for how the BFS UID Register works.

No Norwegian validation

Same story. NO tax IDs get format-checked, not validated against the Bronnoysund Register.

No standalone API

Validation is tied to Stripe's Customer objects. You cannot just call an endpoint with a VAT number and get a result. You need a Stripe Customer and must attach the tax ID to it through the Tax IDs API first.

No periodic revalidation

Stripe validates once when the tax ID is added. It does not recheck over time. A VAT number that was valid last year could be revoked today, and Stripe would not know.

No validation outside billing

If you need to validate a VAT number at signup, in a CRM, in a partner onboarding flow, or anywhere outside a Stripe payment context, Stripe cannot help.

When to use Avatcado alongside Stripe

  • You sell to Swiss or Norwegian businesses (Stripe cannot validate these)
  • You need validation at signup before any Stripe interaction
  • You need periodic revalidation of existing customer tax IDs
  • You use Stripe for payments but need validation in other systems (CRM, onboarding, compliance)
  • You want to verify that the number is actually valid, not just correctly formatted

Validate before creating the Stripe customer:

import Avatcado from "@avatcado/node";
import Stripe from "stripe";

const avatcado = new Avatcado("avat_live_your_api_key");
const stripe = new Stripe("sk_live_your_stripe_key");

// Validate before creating the Stripe customer
const { data, error } = await avatcado.vat.validate({
  vatNumber: customer.vatNumber,
});

if (data?.data.valid) {
  // Safe to apply reverse charge in Stripe. Tax IDs are attached
  // through the Tax IDs API; the Update Customer API does not
  // accept tax_id_data (that parameter is create-only).
  await stripe.customers.createTaxId(customerId, {
    type: "eu_vat",
    value: customer.vatNumber,
  });
}

Using both: Avatcado for validation, Stripe for billing

Avatcado handles the validation (real government database check, all 32 countries). Stripe handles the billing (invoicing, tax calculation, payment collection). The two work together: validate with Avatcado first, then pass the validated number to Stripe.

This gives you the best of both: Stripe's billing infrastructure plus Avatcado's validation coverage. For a full integration example, see the SaaS billing guide.

Get started

Avatcado's free tier includes 500 validations per month with no credit card required. Add real government database validation to your Stripe integration in under 5 minutes.

Start validating for free →

Read the API documentation for integration details.

Frequently asked questions

Does Stripe validate Swiss VAT numbers?

No. Stripe stores Swiss (CH) tax IDs and checks their format, but it does not validate them against the BFS UID Register, so a plausibly formatted but nonexistent Swiss number looks the same to Stripe as a real one. Norway is the same story: NO tax IDs get a format check only, with no lookup against the Bronnoysund Register. Stripe's automatic government-database validation covers exactly three regions, EU VAT numbers via VIES, UK numbers via HMRC, and Australian ABNs via the ABR; for the 100+ other tax ID types it stores, Stripe's own documentation says you must manually verify these IDs where automatic validation is not available. If you sell to Swiss or Norwegian businesses, that gap is yours to close. Avatcado validates CH and LI numbers against the BFS UID Register and NO numbers against the Bronnoysund Register through the same endpoint as EU and UK numbers, so you can verify before the tax ID ever reaches Stripe.

Can I use Stripe's tax ID validation as a standalone API?

No. Stripe's validation is tied to its Customer objects: you cannot just call an endpoint with a VAT number and get back a result. To trigger validation, you need an existing Stripe Customer and must attach the tax ID to it through the Tax IDs API (note that the Update Customer API does not accept tax_id_data; that parameter is create-only). That coupling rules out common non-billing use cases: validating at signup before any Stripe interaction exists, checking numbers in a CRM or partner onboarding flow, or running compliance sweeps over records that have no Stripe customer at all. Avatcado is the standalone counterpart: GET /v1/validate with any supported VAT or GST number returns a validation result with no prerequisite objects, so you can validate anywhere in your stack and only afterwards, once the number checks out, attach it to a Stripe Customer for billing purposes.

Does Stripe revalidate tax IDs over time?

No. Stripe validates once, when the tax ID is added to a Customer, and never rechecks it. A VAT number that was valid last year can be revoked or deregistered today, and Stripe would not know: the customer keeps their reverse charge treatment and your zero-rated invoices keep flowing against a number that no longer exists. For subscription businesses this is the quiet gap in an otherwise automated setup, because the validation event happens exactly once at the start of a potentially years-long billing relationship. The remedy is periodic revalidation you run yourself: pull the tax IDs of active subscribers, batch-validate them through Avatcado (up to 50 per request on Pro and Business plans), and for any number that has gone invalid, update the customer's tax treatment in Stripe before the next invoice is generated. Monthly or quarterly is a common cadence, matching how registrations tend to lapse between billing cycles.

I only sell to EU and UK businesses. Do I still need Avatcado?

Maybe not, and it is worth being honest about that. Stripe validates EU numbers against VIES and UK numbers against HMRC, so if every customer is EU or UK and validation only ever needs to happen inside Stripe's billing flow, the built-in check may cover you. The reasons merchants add Avatcado anyway map to Stripe's structural gaps: validation outside billing (at signup, in a CRM, in partner onboarding, before a Stripe Customer exists), periodic revalidation of existing customers (Stripe checks once and never again), and coverage you might grow into, since Swiss and Norwegian numbers get format checks only. Also note Stripe Tax's behavior: it applies reverse charge based on format alone, so a correctly formatted but fake VAT number would still trigger reverse charge. If any of those cases apply now or will soon, validating with Avatcado first and then attaching the verified number to Stripe covers all of them at once.

Sources

Related guides