EU VAT compliance for SaaS billing
Handle EU VAT for SaaS subscriptions. Validate customer VAT numbers at signup, determine B2B vs B2C tax treatment, and generate compliant invoices with the correct VAT amount.
EU VAT treatment for SaaS subscriptions hinges on a single question: is the customer a taxable person (business) or a private consumer? Under EU VAT Directive 2006/112/EC Article 196, if the buyer is a VAT-registered business in another EU member state, the supply is zero-rated and the buyer accounts for VAT under the reverse-charge mechanism. If the buyer is a consumer, you must charge VAT at the rate applicable in their country of residence, which is where the EU One Stop Shop (OSS) scheme becomes relevant.
At signup, call GET /api/v1/validate/:country/:vat to confirm the VAT number. A response with status: 'active' classifies the account as B2B: set tax_treatment: 'reverse_charge' in your billing database and pass tax_exempt: 'reverse' to Stripe. A missing or invalid VAT number classifies the account as B2C: determine the customer's country from their IP or billing address and apply the local OSS VAT rate. Store the company_name and company_address from the TaxID response on the customer record; these fields must appear on compliant EU VAT invoices.
Re-validate VAT numbers periodically — VIES supports querying at any time, and a business can deregister. A safe approach is to re-validate on each subscription renewal and cache the result for 24 hours (matching TaxID's cache window for active numbers). If a previously valid number returns invalid on renewal, freeze the reverse-charge treatment, notify the customer, and revert to charging VAT until a valid number is supplied.
Implementation steps
- 1
Collect VAT number at signup
Add an optional VAT number field to your signup form and show it conditionally when the user selects an EU country. Use a client-side regex to catch obvious format errors before the form is submitted (e.g. DE must be DE + exactly 9 digits), reducing unnecessary API calls and giving instant feedback to users who mistype their number.
- 2
Validate and classify customer (B2B/B2C)
On form submission, call GET /api/v1/validate/:country/:vat from your server. Set the customer's tax_treatment column to 'reverse_charge' when status === 'active', 'standard_rate' when status === 'invalid' or no VAT number was provided, and 'pending' when status === 'service_unavailable' so a background job can retry within the hour. Store the cached flag from the response to distinguish a live VIES confirmation from a cached result.
- 3
Configure billing engine for correct tax
Pass the tax classification to your billing engine: for reverse_charge customers, disable VAT calculation and add a 'Reverse charge — VAT to be accounted for by the recipient' line to the invoice per EU invoice Directive Article 226(11a). For B2C customers, apply the destination-country VAT rate and flag the invoice for OSS reporting. Using Stripe Tax, this translates to tax_exempt: 'reverse' for B2B and a standard tax_behavior: 'exclusive' subscription for B2C.
- 4
Generate compliant PDF invoices
EU-compliant invoices must include the supplier's VAT number, the buyer's VAT number (for reverse-charge invoices), the company_name and company_address from the TaxID validation response, and the reverse-charge annotation. Render these fields from your customer record into your PDF template; missing any of them can cause the invoice to be rejected by the buyer's tax authority and denied as input VAT credit.
Code example
Node.js
const res = await fetch(
'http://localhost:3000/api/v1/validate/DE/DE123456789',
{ headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
);
const { valid, status, company_name, company_address } = await res.json();
if (valid) {
console.log(`Valid EU business: ${company_name}`);
} else if (status === 'service_unavailable') {
// VIES is temporarily down — retry or allow with manual check
console.log('VIES unavailable — check back in a few minutes');
} else {
console.log('Invalid VAT number — charge local tax rate');
}Python
import requests
res = requests.get(
"http://localhost:3000/api/v1/validate/DE/DE123456789",
headers={"Authorization": "Bearer YOUR_API_KEY"}
)
data = res.json()
if data["valid"]:
print(f"Valid: {data['company_name']}")
elif data["status"] == "service_unavailable":
print("VIES temporarily unavailable")
else:
print("Invalid VAT number")API response
The TaxID API returns a consistent JSON response for every validation request:
{
"valid": true,
"status": "active",
"country_code": "DE",
"vat_number": "123456789",
"company_name": "Example GmbH",
"company_address": "Musterstraße 1, 10115 Berlin",
"request_date": "2026-05-10T00:00:00.000Z",
"cached": false,
"request_id": "req_01j..."
}Error handling
The API uses a consistent Stripe-style error format. Always handle service_unavailable separately — VIES has occasional downtime and you should not reject valid customers during outages.
activeVAT number is valid and the business is registered
invalidVAT number format is wrong or not registered in VIES
service_unavailableVIES or the national system is temporarily down — retry later
Further reading
B2B VAT Exemption in EU SaaS: What Your Billing System Must Do
Reverse charge sounds simple but the implementation details trip up most SaaS billing engineers. Here is what your syste…
VAT for Developers: The Complete 2026 Implementation Guide
VAT is a consumption tax collected at each stage of the supply chain. For developers, this means implementing rate looku…
SaaS VAT Compliance: A Developer's Complete Guide for EU Markets
Selling a SaaS product to EU customers means navigating B2B vs B2C VAT rules, determining the place of supply, registeri…
Evaluating EU VAT APIs? Compare TaxID with:
Related use cases
DAC7 marketplace seller VAT verification
Verify seller VAT numbers during marketplace onboarding for DAC7 compliance. EU platforms must colle...
Bulk VAT number validation via CSV import
Validate hundreds of EU VAT numbers in batch using parallel API requests. Ideal for CRM data cleansi...
Validate German USt-IdNr. (DE VAT numbers)
Specifically validate German Umsatzsteuer-Identifikationsnummern (USt-IdNr.) via VIES. Understand th...