Home / VAT API / Integrations / Java (Spring Boot)
Java (Spring Boot) EU VAT Validation API
Validate EU VAT numbers from Java and Spring Boot with the TaxID API using the JDK's built-in HttpClient — no heavy SOAP stubs required. Add it to a @Service bean or a Bean Validation constraint so VAT numbers are checked against VIES before your application applies reverse-charge treatment or persists a customer.
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.
Java 11+
import java.net.URI;
import java.net.http.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
// Requires Java 11+ and jackson-databind
public class VATValidator {
static final HttpClient client = HttpClient.newHttpClient();
static final ObjectMapper mapper = new ObjectMapper();
@SuppressWarnings("unchecked")
public static Map<String, Object> validateVAT(
String country, String vatNumber) throws Exception {
var request = HttpRequest.newBuilder()
.uri(URI.create("https://www.taxid.dev/api/v1/validate/" + country + "/" + vatNumber))
.header("Authorization", "Bearer " + System.getenv("TAXID_API_KEY"))
.GET()
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
return mapper.readValue(response.body(), Map.class);
}
public static void main(String[] args) throws Exception {
var result = validateVAT("DE", "DE123456789");
if (Boolean.TRUE.equals(result.get("valid"))) {
System.out.println("Valid EU business: " + result.get("company_name"));
} else if ("service_unavailable".equals(result.get("status"))) {
System.out.println("VIES unavailable — retry later");
} else {
System.out.println("Invalid VAT number");
}
}
}cURL
curl "https://www.taxid.dev/api/v1/validate/DE/DE123456789" \
-H "Authorization: Bearer $TAXID_API_KEY"
# {
# "valid": true,
# "status": "active",
# "company_name": "Example GmbH",
# "company_address": "Musterstraße 1, 10115 Berlin",
# "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. Inject it through Spring's @Value("${taxid.api-key}") from application.yml, and source the value from an environment variable so it never lands in your JAR or version control.
- 2
Build a VatValidationService bean
Create a @Service that holds a single reusable java.net.http.HttpClient. Build a GET request to https://www.taxid.dev/api/v1/validate/{country}/{number} with an Authorization: Bearer header, send it, and deserialize the JSON body with Jackson into a small record. Reuse one HttpClient instance rather than creating one per call.
- 3
Expose it as a Bean Validation constraint
Define a @ValidVat annotation backed by a ConstraintValidator that calls the service. Annotate the vatNumber field on your request DTO so Spring MVC rejects invalid numbers with a 400 before they reach your controller. Return true on a 'service_unavailable' status so a VIES outage does not block legitimate submissions.
- 4
Persist the validation snapshot
When status equals 'active', store companyName, companyAddress, and a validatedAt Instant on your Customer JPA entity next to the VAT number. This provides the audit evidence tax authorities require and lets you skip a redundant lookup for numbers already validated inside the cache window.
- 5
Schedule re-validation with @Scheduled
Add a @Scheduled method that re-validates every customer flagged for reverse-charge on a monthly cadence. VAT registrations can lapse between invoices, so periodic re-checks keep your tax treatment defensible. Run the batch on a bounded thread pool and back off on 'service_unavailable' rather than marking numbers invalid.
Frequently asked questions
Do I need the VIES SOAP WSDL to validate VAT numbers in Java?
No. The classic approach of generating JAX-WS stubs from the VIES WSDL is brittle and hard to maintain. The TaxID API wraps VIES behind a plain REST endpoint, so you call it with the JDK's HttpClient and parse JSON — no SOAP, no wsimport, no XML marshalling.
How do I turn VAT validation into a Bean Validation annotation?
Create a custom @ValidVat annotation and a ConstraintValidator<ValidVat, String> whose isValid() method calls your validation service. Place @ValidVat on the DTO field, and Spring's @Valid handling will trigger it automatically, returning a MethodArgumentNotValidException (HTTP 400) for invalid numbers.
Should I reuse a single HttpClient across requests?
Yes. java.net.http.HttpClient is thread-safe and manages its own connection pool, so build one instance as a Spring singleton bean and inject it everywhere. Creating a new client per validation wastes resources and can exhaust file descriptors under load.
How do I handle a temporary VIES outage in Spring?
The API returns status 'service_unavailable' when a national registry is down. In your validator, do not fail closed — allow the submission through, log the event, and enqueue a background re-check. Configure Resilience4j or a simple @Retryable if you want automatic retries with backoff.
Country-specific API docs:
In-depth integration guide:
EU VAT validation in Java
Validate EU VAT numbers in Java using the built-in HttpClient (Java 11+) and Jackson for JSON deserialization. Works with Spring Boot, Quarkus, Micronaut, or any Java 11+ application.
Start validating EU VAT numbers in Java (Spring Boot)
Free plan — 100 validations/month. No credit card required.