Validate French TVA numbers (FR VAT)
Validate French Numéro de TVA intracommunautaire. French VAT numbers have a unique format with alphanumeric characters that can include letters O and I.
French TVA intracommunautaire numbers follow the format FR + 2 alphanumeric characters + 9 digits (the SIREN number of the company). Unlike most EU member states where the check characters are purely numeric, France allows letters in positions 3 and 4, including O and I, which commonly cause confusion with the digits 0 and 1. The 2-character key is algorithmically derived from the SIREN using the formula (12 + 3 × (SIREN mod 97)) mod 97, but this is an internal cross-check — the authoritative source for active status is VIES.
The DGFiP (Direction générale des Finances publiques) submits French VAT registrations to VIES, but there can be a lag of several days between when a company receives its TVA number and when it appears as active in VIES. This means a newly-registered French company may provide a syntactically valid TVA number that still returns service_unavailable or invalid from VIES while the registration propagates. Build a retry flow for this edge case rather than rejecting the buyer outright.
French invoicing rules (Code Général des Impôts Article 289) require that reverse-charge invoices include both the supplier's and the recipient's TVA intracommunautaire numbers. The company_name returned by TaxID from the VIES lookup should match the SIREN-registered name; mismatches (e.g. a holding company TVA number used on an invoice for a subsidiary's purchase) are a common source of input VAT denial by the French tax authority.
Implementation steps
- 1
Accept FRXX... format with alphanumeric chars
Validate input with /^FR[A-HJ-NP-Z0-9]{2}[0-9]{9}$/ — note the character class excludes I and O from the standard [A-Z0-9] set because the French algorithm never produces those characters, but if a user types them, provide a friendly message rather than a generic 'invalid format' error. Normalise the input to uppercase before validating, as many French businesses write their TVA in mixed case.
- 2
Handle French Tax Agency (DGFiP) VIES responses
Call GET /api/v1/validate/FR/:vatNumber and be prepared for a status of 'service_unavailable' when the DGFiP node is under maintenance, which occurs more frequently than for some other EU member states. Implement a retry strategy: if service_unavailable is returned, wait 60 seconds and retry up to three times before falling back to format-only validation and flagging the record for asynchronous re-validation.
- 3
Return SIRET-linked company name
The company_name in the TaxID response for French numbers is the official registered name from the DGFiP's VIES submission, which is typically linked to the company's SIREN record. Display it as a confirmation to the buyer and store it in your customer record; French invoices subject to reverse charge must include the exact registered company name as it appears in official registers, and using the VIES-returned name eliminates ambiguity.
- 4
Cache results for 24 hours
TaxID already caches active French VAT number responses for 24 hours server-side, so repeat calls for the same number within that window return in under 10 ms with cached: true in the response. Implement client-side caching in your application using the same 24-hour TTL for active numbers and a 1-hour TTL for invalid responses, using the composite key fr:{vatNumber} to namespace the cache.
Code example
Node.js
const res = await fetch(
'http://localhost:3000/api/v1/validate/DE/FRXX123456789',
{ 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/FRXX123456789",
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
Country-specific guides
Further reading
French VAT Number Validation: TVA Intracommunautaire Format, VIES, and Code Examples
French VAT numbers use FR + 2 alphanumeric characters + 9 digits. The first two characters can be letters or numbers — o…
VAT Percentage in France A Developer's Guide (2026)
Learn the current VAT percentage in France for 2026. This guide covers rates, B2B/B2C rules, VIES validation, and develo…
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...