EU VAT Number Validation in PHP
A step-by-step guide to validating EU VAT numbers in PHP using the vatnode REST API. Includes examples with curl, Guzzle, and the Laravel HTTP client.
Basic validation with curl
The vatnode API works with PHP's built-in cURL extension — no additional packages required:
PHP — curl
<?php
function validateVatNumber(string $vatId): array
{
$apiKey = getenv('VATNODE_API_KEY');
$url = 'https://api.vatnode.dev/v1/vat/' . urlencode($vatId);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $apiKey"],
CURLOPT_TIMEOUT => 10,
]);
$body = curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($statusCode === 503) {
return ['error' => 'VIES_UNAVAILABLE'];
}
return json_decode($body, true);
}
$result = validateVatNumber('IE6388047V');
if (isset($result['error'])) {
// Queue for retry
echo "VIES unavailable, retry later
";
} elseif ($result['valid']) {
echo "Valid: {$result['companyName']}
"; // GOOGLE IRELAND LIMITED
echo "CheckId: {$result['checkId']}
"; // store on invoice
} else {
echo "Invalid VAT number
";
}Using Guzzle
PHP — Guzzle
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ServerException;
$client = new Client([
'base_uri' => 'https://api.vatnode.dev',
'headers' => ['Authorization' => 'Bearer ' . getenv('VATNODE_API_KEY')],
'timeout' => 10,
]);
function validateVat(Client $client, string $vatId): array
{
try {
$response = $client->get('/v1/vat/' . urlencode($vatId));
return json_decode($response->getBody()->getContents(), true);
} catch (ServerException $e) {
if ($e->getCode() === 503) {
return ['error' => 'VIES_UNAVAILABLE'];
}
throw $e;
} catch (ClientException $e) {
return ['error' => 'INVALID_VAT_NUMBER'];
}
}
$result = validateVat($client, 'DE134214316');
if ($result['valid'] ?? false) {
// Apply reverse charge
$vatRate = 0;
} else {
// Charge local VAT
$vatRate = $result['countryVat']['standardRate'] / 100;
}Laravel HTTP client
Laravel's HTTP facade wraps Guzzle with a fluent interface. Add your API key to .env:
PHP — Laravel
<?php
// Add to .env: VATNODE_API_KEY=vat_live_...
use Illuminate\Support\Facades\Http;
function validateVatLaravel(string $vatId): array
{
$response = Http::withToken(config('services.vatnode.key'))
->timeout(10)
->get("https://api.vatnode.dev/v1/vat/" . urlencode($vatId));
if ($response->status() === 503) {
return ['error' => 'VIES_UNAVAILABLE'];
}
$response->throw(); // throws on 4xx errors
return $response->json();
}
// config/services.php
return [
'vatnode' => [
'key' => env('VATNODE_API_KEY'),
],
];Do not block checkout on VIES unavailability. When vatnode returns a 503, queue the validation job (e.g. using Laravel Queue) and proceed with standard VAT. Retry the check asynchronously — VIES will recover.
Add VAT validation to your PHP app
Free plan: 20 requests/month, no credit card. Works with curl, Guzzle, and Laravel.