Home / Use cases / Custom

Custom

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. 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. 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. 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. 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:

200 OK (active)valid
{
  "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.

active

VAT number is valid and the business is registered

invalid

VAT number format is wrong or not registered in VIES

service_unavailable

VIES or the national system is temporarily down — retry later

Country-specific guides

Further reading

Evaluating EU VAT APIs? Compare TaxID with:

Ready to implement?

Get your free API key and start validating EU VAT numbers today.

Get free API key

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...