Next.js server action for VAT validation
Use Next.js 14 Server Actions to validate EU VAT numbers server-side in a React form. No API route needed — validation runs securely on the server with full TypeScript types.
Next.js 14 Server Actions allow you to call server-side code directly from a React component without writing a separate API route. For VAT validation, this means the TaxID API key never leaves the server, the fetch call runs in the Node.js runtime where you have access to environment variables, and the result is streamed back to the client as a serialised server response. The form component uses useTransition to track the pending state and provide optimistic UI feedback while the validation runs.
The Server Action calls GET /api/v1/validate/:country/:vat with the Authorization header populated from process.env.TAXID_API_KEY, parses the JSON response into a typed VATResult object, and returns it to the client. The 'use server' directive marks the function as a Server Action, and calling it from the client triggers a POST to Next.js's internal actions endpoint — the network request is handled by the framework, not by your code.
Using useTransition alongside the Server Action provides two benefits: isPending is true while the action is running, which drives the loading spinner, and the transition does not block the React render pipeline, so the rest of the page remains interactive. Combine this with React's useOptimistic hook if you want to speculatively show a 'validating' state before the server confirms, giving instant visual feedback to users on high-latency connections.
Implementation steps
- 1
Create Server Action for VAT validation
Define an async function in a file with 'use server' at the top (or inline with the directive). The function signature should be: async function validateVAT(country: string, vat: string): Promise<VATResult>. Inside, call fetch(`https://api.taxid.pro/v1/validate/${country}/${vat}`, { headers: { Authorization: `Bearer ${process.env.TAXID_API_KEY}` }, next: { revalidate: 3600 } }) and return the typed response. The next.revalidate option enables Next.js data cache for repeated lookups.
- 2
Add optimistic UI with useTransition
In your client component, call const [isPending, startTransition] = useTransition() and wrap the Server Action call in startTransition(() => { validateVAT(country, vat).then(setResult) }). Set isPending to true immediately while the transition is in flight, which triggers your loading indicator without blocking the rest of the page. This pattern is idiomatic Next.js 14 and avoids the complexity of manual loading state management.
- 3
Display company name confirmation
When the Server Action resolves with status: 'active', update component state with the result and render the company_name from the VATResult in a highlighted confirmation block. For status: 'invalid', show an inline validation error adjacent to the VAT input field. For status: 'service_unavailable', display a non-blocking warning ('VAT verification is temporarily unavailable — your number will be validated shortly') and allow the form to proceed so users are not blocked by a VIES outage.
- 4
Handle pending and error states
Use isPending from useTransition to show a spinner on the submit button and disable the VAT input during validation, preventing double-submissions. Wrap the startTransition call in a try/catch to handle network errors and surface them as a user-facing error state rather than a silent failure. For the error state, distinguish between a TaxID API error (HTTP 4xx/5xx) and a VIES service_unavailable response (HTTP 200 with status: 'service_unavailable') — they require different UX responses.
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
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…
EU VAT Validation in Node.js: Complete Tutorial with Error Handling
Copy-paste Node.js / TypeScript implementation for EU VAT validation with proper error handling, caching, and test cover…
Evaluating EU VAT APIs? Compare TaxID vs Vatstack, Vatlayer, Avalara →
Related use cases
Validate EU VAT numbers in Stripe Checkout
Add EU VAT validation to your Stripe checkout flow. Verify customer VAT numbers server-side before a...
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...