Home / Use cases / PHP

PHP

EU VAT validation in PHP / Laravel

Validate EU VAT numbers in PHP applications with Laravel, Symfony, or plain PHP. Includes service class, validation rule, and database storage pattern.

PHP applications using Laravel can integrate TaxID validation through a combination of a service class, a custom FormRequest validation rule, and a database migration for storing results. The service class wraps the HTTP call, the custom rule hooks into Laravel's validator so VAT numbers can be validated in any FormRequest with a single line, and the database table provides the audit trail required by EU VAT regulations.

The HTTP call itself uses Laravel's Http facade (built on Guzzle): Http::withToken(config('services.taxid.api_key'))->get("https://api.taxid.pro/v1/validate/{$country}/{$vat}"). The response JSON maps to a PHP array with keys valid, status, company_name, company_address, cached, and request_id. Cache the response in Redis using Cache::put("vat:{$country}:{$vat}", $response, $ttl) where $ttl is 86400 for active numbers and 3600 for invalid ones.

Symfony users follow the same pattern using Symfony's HttpClient component (HttpClient::create()->request('GET', $url, ['auth_bearer' => $apiKey])) and a custom ConstraintValidator. The key architectural difference is registering the validator as a tagged service in services.yaml. In either framework, surfacing validation feedback in the Blade or Twig template as an inline message (company name on success, error text on failure) significantly reduces checkout abandonment compared to generic error messages.

Implementation steps

  1. 1

    Create VATValidationService

    Generate a service class (php artisan make:service VATValidationService) that injects Laravel's Http facade and calls GET https://api.taxid.pro/v1/validate/{country}/{vat} with withToken(config('services.taxid.api_key')). Return the decoded JSON as a PHP object or DTO so callers never access raw array keys and get IDE autocompletion on status, company_name, and request_id.

  2. 2

    Add Laravel validation rule

    Create a custom rule class (php artisan make:rule ValidEUVatNumber) that calls VATValidationService::validate() in the passes() method and returns true only when status === 'active'. Use the rule in your FormRequest: 'vat_number' => ['required', 'string', new ValidEUVatNumber($request->country)]. This makes VAT validation available anywhere Laravel's validator runs, including API controllers and queue jobs.

  3. 3

    Cache results in Redis

    Before making an HTTP request in VATValidationService, check Cache::get("vat:{$country}:{$vat}"). On a cache miss, call the API and store the result with Cache::put("vat:{$country}:{$vat}", $result, $ttl) where $ttl = $result->status === 'active' ? 86400 : 3600. Using Laravel's cache abstraction means you can switch from Redis to Memcached or database cache without changing the service class.

  4. 4

    Display validation feedback in Blade

    After the form submits, pass the VATValidationResult to your Blade view and conditionally render an inline confirmation block: show the company_name in green when status is active, an error alert when invalid, and a warning notice when service_unavailable. Displaying the company name that VIES returned is a strong trust signal for B2B buyers and reduces support tickets from customers unsure whether their number was accepted.

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:

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