Home / Use cases / Java

Java

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. 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. 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. 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. 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:

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...