Home / Use cases / React

React

Real-time VAT validation in React checkout

Add real-time VAT number validation to your React checkout form. Validates as the user types, shows company name confirmation, and handles loading/error states.

Real-time VAT validation in a React checkout improves B2B conversion by giving buyers instant feedback — they see the legal company name confirmed on screen before they complete payment, which builds trust and catches typos before they cause invoice problems downstream. The interaction pattern is: debounce input, send to a server-side API route (not directly to TaxID from the browser), display a loading spinner, then show the result inline.

The browser must never call TaxID directly because that would expose your API key. Instead, create a thin /api/validate-vat route in your Next.js or Express backend that proxies to GET /api/v1/validate/:country/:vat and returns only the fields the frontend needs (status, company_name). The React component uses a 500 ms debounce to avoid firing on every keystroke, and useTransition (in Next.js 14 Server Actions) or a standard useEffect + AbortController to cancel in-flight requests when the user keeps typing.

The component should manage four distinct UI states: idle (no input), loading (spinner), valid (green badge + company name), and error (red message with the specific error type). Distinguishing between 'invalid' (wrong number) and 'service_unavailable' (VIES temporarily down) in the error state prevents user confusion — for service_unavailable you should reassure the buyer that their number will be validated after checkout rather than implying their VAT registration is incorrect.

Implementation steps

  1. 1

    Add VAT number input field

    Render the VAT number input conditionally when the billing country is an EU member state, using a controlled input whose value is stored in React state. Show a short format hint below the field (e.g. 'DE + 9 digits for German VAT numbers') derived from the selected country code to reduce format-related validation failures before the user even submits.

  2. 2

    Debounce validation calls (500ms)

    Wrap the onChange handler with a useEffect cleanup pattern or a library like use-debounce to wait 500 ms of inactivity before triggering a fetch to your /api/validate-vat server route. Use an AbortController and pass its signal to fetch() so that if the user types again before the response arrives, the stale request is cancelled and you never apply an out-of-date validation result to the current input value.

  3. 3

    Show loading spinner and status

    Maintain a validationState value in component state ('idle' | 'loading' | 'valid' | 'invalid' | 'unavailable'). Set it to 'loading' immediately when the debounced call fires, then update it when the server responds. Render distinct UI for each state: a spinner icon during loading, a check icon during valid, an X icon during invalid, and a warning icon during unavailable, so the checkout form communicates status without relying on text alone.

  4. 4

    Display company name on success

    When the API returns status: 'active', display the company_name from the response in a highlighted confirmation block below the input (e.g. 'Validated: Acme GmbH'). This serves as a human-readable sanity check that the buyer entered the correct number for their business, and it gives your support team an instant reference when reviewing orders without needing to re-query VIES.

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:

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

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

Stripe EU VAT: Validate Tax IDs Before Charging Customers

Stripe EU VAT integration guide: validate EU VAT numbers server-side before applying zero-rate B2B e...

UK VAT validation in Shopify B2B

Validate UK VAT numbers for B2B customers in Shopify. Required under UK Making Tax Digital rules for...

WooCommerce Spain NIF/CIF validation

Validate Spanish NIF and CIF numbers in WooCommerce checkout. Automatically apply B2B tax exemptions...