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.
Java 11 introduced java.net.http.HttpClient as a modern, non-blocking replacement for the legacy HttpURLConnection. Combined with Jackson's ObjectMapper for JSON deserialization, it provides a clean, dependency-minimal path to calling the TaxID REST API. For Spring Boot applications, the natural pattern is to encapsulate the HttpClient in a @Service bean, inject the API key from @Value("${taxid.api-key}"), and return a typed VATResult record.
Define a Java record (Java 16+) or a simple POJO for VATResult with fields: boolean valid, String status, String companyName, String companyAddress, boolean cached, String requestId. Jackson's @JsonProperty annotation handles the snake_case-to-camelCase mapping. Using a record makes the result immutable and provides equals/hashCode/toString for free, simplifying caching and logging.
In Spring Boot, register the VATValidationService as a @Service, wire it into your @RestController or @Service billing layer, and test it with @SpringBootTest and a mocked HttpClient using Mockito. For integration tests, use WireMock to stub the TaxID API and simulate all three status responses (active, invalid, service_unavailable) to verify your branching logic without network access.
Implementation steps
- 1
Use java.net.http.HttpClient — no extra HTTP library needed
Create a shared HttpClient instance: HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build(). Make it a Spring @Bean or a static field — HttpClient is thread-safe and designed for reuse. Avoid creating a new HttpClient per request, which would bypass connection pooling and create unnecessary overhead under load.
- 2
Set the Authorization header with your API key from environment
Build the request: HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://api.taxid.pro/v1/validate/" + country + "/" + vat)).header("Authorization", "Bearer " + apiKey).timeout(Duration.ofSeconds(10)).GET().build(). Load apiKey from System.getenv("TAXID_API_KEY") or, in Spring Boot, inject it with @Value("${taxid.api-key}") in the service constructor. Never hardcode the key.
- 3
Deserialize the JSON response with Jackson ObjectMapper
Send the request synchronously with client.send(request, BodyHandlers.ofString()) and pass the response body to objectMapper.readValue(response.body(), VATResult.class). Configure ObjectMapper with DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES set to false so new fields added to the TaxID response in the future do not break deserialization. Throw a VATServiceException wrapping the HTTP status code for non-200 responses.
- 4
Return B2B validation status to your billing or checkout logic
Return the VATResult record to your caller and branch on result.status(): for "active", set the customer's taxTreatment to REVERSE_CHARGE in your billing model; for "invalid", throw a VATValidationException that your controller maps to a 422 response with a user-facing message; for "service_unavailable", throw a VATServiceUnavailableException that maps to 503 so the caller can implement retry logic without coupling it to the service implementation.
Code example
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("http://localhost:3000/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 "http://localhost:3000/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 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
EU VAT Number Validation: The Complete Developer Guide (2026)
VIES is SOAP-based, unreliable, and has no caching. This guide explains how EU VAT validation works end-to-end, how to h…
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…
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...