Home / VAT API / Integrations / Next.js
Next.js EU VAT Validation API
Validate EU VAT numbers in Next.js with the TaxID API from a Route Handler or Server Action. Keep your API key server-side, cache validated results with the App Router's fetch cache, and return only the boolean result to your client checkout form.
Quick start
CURL
curl -H "Authorization: Bearer YOUR_API_KEY" \ https://www.taxid.dev/api/v1/validate/DE/DE123456789
Code example
Full integration example including error handling for service_unavailable responses from VIES.
Vercel Edge
// app/api/validate-vat/route.ts
// Runs at the Vercel edge — global, sub-50ms cold starts
import { NextRequest, NextResponse } from 'next/server';
export const runtime = 'edge';
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const country = searchParams.get('country');
const vat = searchParams.get('vat');
if (!country || !vat) {
return NextResponse.json(
{ error: 'country and vat params required' },
{ status: 400 }
);
}
const res = await fetch(
`https://www.taxid.dev/api/v1/validate/${country}/${vat}`,
{
headers: { 'Authorization': `Bearer ${process.env.TAXID_API_KEY}` },
next: { revalidate: 3600 }, // cache validated results for 1 hour
}
);
const result = await res.json();
return NextResponse.json(result);
}cURL
# Test locally:
# curl "http://localhost:3000/api/validate-vat?country=DE&vat=DE123456789"
# Or call the TaxID API directly:
curl "https://www.taxid.dev/api/v1/validate/DE/DE123456789" \
-H "Authorization: Bearer $TAXID_API_KEY"
# {
# "valid": true,
# "status": "active",
# "company_name": "Example GmbH",
# "cached": false
# }API response
The TaxID API returns a consistent JSON response for every validation:
{
"valid": true,
"status": "active",
"country_code": "DE",
"vat_number": "DE123456789",
"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..."
}activeVAT number is valid and the business is registered
invalidVAT number format is wrong or not registered in VIES
service_unavailableVIES or the national authority is temporarily down — retry later, do not silently zero-rate
Implementation steps
- 1
Get a free TaxID API key
Sign up at taxid.dev/signup for a free key with 100 validations/month. Add it to .env.local as TAXID_API_KEY without the NEXT_PUBLIC_ prefix, so it stays on the server and is never bundled into client JavaScript.
- 2
Create a Route Handler
Add app/api/validate-vat/route.ts with a GET handler that reads the country and number from search params and calls https://www.taxid.dev/api/v1/validate/{country}/{vat} with an Authorization bearer header. Return NextResponse.json with only the fields your client needs. Because this runs server-side, the key never leaves your infrastructure.
- 3
Cache validated results
Pass next: { revalidate: 3600 } to the fetch call so the App Router caches a valid lookup for an hour, matching the API's own cache window. Repeat checks for the same number then resolve instantly at the framework layer without another round-trip to VIES.
- 4
Validate in a Server Action for forms
For a checkout form using Server Actions, mark an async function with 'use server', validate the submitted VAT number inside it, and return a typed result. This keeps the key server-side and lets you revalidatePath or update state without exposing an API route publicly.
- 5
Handle the three response states in the UI
Map 'active' to a success state that enables reverse-charge, 'invalid' to an inline form error, and 'service_unavailable' to a soft warning that lets the customer continue while you flag the number for a background re-check. Never silently zero-rate on a 'service_unavailable' response.
Frequently asked questions
Should VAT validation run in a Route Handler or a Server Action?
Both keep your key server-side. Use a Route Handler when you need a callable endpoint — for example, live validation as the user types via fetch from a client component. Use a Server Action when validation is part of a form submission, so you can validate and mutate state in one server round-trip without a separate API route.
How do I stop my TaxID API key from leaking to the browser?
Name the variable TAXID_API_KEY (not NEXT_PUBLIC_TAXID_API_KEY) and only read process.env.TAXID_API_KEY inside a Route Handler, Server Action, or server component. Anything prefixed with NEXT_PUBLIC_ is inlined into the client bundle, so never use that prefix for secrets.
Can I cache VAT validation results in the App Router?
Yes. Add next: { revalidate: 3600 } to the fetch that calls the TaxID API, and Next.js will serve a valid result from its Data Cache for an hour before re-fetching. This complements the API's own caching and cuts latency for repeat checks of the same number.
Does this work with the Edge runtime?
Yes. The handler uses standard fetch, so you can add export const runtime = 'edge' to run it at the Vercel Edge for lower latency. The validation logic is identical; only the deployment target changes.
Country-specific API docs:
In-depth integration guide:
EU VAT validation on Vercel Edge
Add EU VAT validation to your Next.js app using Vercel Edge Functions. The edge runtime runs your validation globally with sub-50ms cold starts and built-in Next.js caching via next: { revalidate }.
Start validating EU VAT numbers in Next.js
Free plan — 100 validations/month. No credit card required.