Validate VAT numbers before invoice generation
Automatically validate customer VAT numbers before generating B2B invoices. Prevent invalid numbers from appearing on invoices that could be rejected by tax authorities.
An EU B2B invoice that claims reverse-charge treatment must carry the buyer's valid VAT number at the time the invoice is issued. If the VAT number on the invoice turns out to be invalid — because it was entered incorrectly, the business deregistered, or it was never VIES-active — the invoice can be challenged by tax authorities in the buyer's country, resulting in denial of the buyer's input VAT reclaim and a potential VAT liability for the seller who zero-rated the supply without a valid registration to back it up.
The practical implementation is a pre-generation hook: before your invoicing engine (whether that is Stripe Billing, a custom PDF generator, or a third-party tool like Docusign or Invoiced) renders the invoice, call GET /api/v1/validate/:country/:vat. TaxID caches active numbers for 24 hours, so for high-volume invoice runs the majority of repeat lookups return in under 10 ms. Use the response's cached field to distinguish a live VIES confirmation from a cached one; for very high-value invoices, consider forcing a live check by implementing a separate daily re-validation routine.
If the validation returns invalid, block invoice generation and raise an alert to your accounts-receivable team with the customer ID, the failing VAT number, and the TaxID request_id. Store the full validation result — status, company_name, company_address, request_id, and timestamp — in an audit log table indexed by invoice_id. This log satisfies the EU requirement that businesses maintain evidence of the VAT status of their B2B customers for at least ten years.
Implementation steps
- 1
Trigger before invoice creation
Insert a pre-generation step in your invoicing pipeline that calls GET /api/v1/validate/:country/:vat immediately before rendering or dispatching the invoice. For Stripe Billing, implement this in an invoice.created webhook handler that checks the status and cancels (voids) the invoice via stripe.invoices.voidInvoice() if the VAT number is invalid, preventing an incorrect invoice from ever reaching the customer.
- 2
Cache validation result for 24h
Store the TaxID response in your application cache (Redis or database) using the key invoice_vat:{customer_id} with a TTL of 86400 seconds for active numbers and 3600 seconds for invalid ones, matching TaxID's own cache policy. Check this cache before calling the API so that monthly invoicing runs for thousands of customers do not each independently call the API for the same customer, preserving your API quota and keeping the pipeline fast.
- 3
Block invoice if VAT is invalid
When status is 'invalid', halt the invoicing pipeline for that customer, set a flag (e.g. invoice_blocked_reason: 'invalid_vat') on the customer record, and notify your AR team via email or Slack webhook with the customer name, the invalid VAT number, and the TaxID request_id. Do not silently generate the invoice with a valid-VAT assumption — the tax liability risk of issuing a zero-rated invoice without a confirmed active VAT registration sits with the seller.
- 4
Log validation for audit trail
Persist every validation check to an invoice_vat_audit table with columns: invoice_id, customer_id, country_code, vat_number, status, company_name, request_id, validated_at. Index on invoice_id and validated_at for efficient retrieval during tax audits. EU VAT regulations require records to be kept for at least 10 years, and having the request_id enables you to dispute any challenge by demonstrating you performed a live VIES verification at the time of invoicing.
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…
EU VAT Number Validation: The Complete Developer Guide (2026)
VIES is SOAP-based, unreliable, and has no caching. This guide explains how EU VAT validation works end-to-end, how to h…
Evaluating EU VAT APIs? Compare TaxID with:
Related use cases
EU VAT compliance for SaaS billing
Handle EU VAT for SaaS subscriptions. Validate customer VAT numbers at signup, determine B2B vs B2C ...
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...