php-vies-rest
A lightweight, type-safe PHP package for validating EU VAT numbers via the European Commission's VIES (VAT Information Exchange System) REST service.
Install
composer require omisai/vies-restPHP VIES REST
A lightweight, type-safe PHP package for validating EU VAT numbers via the European Commission's VIES (VAT Information Exchange System) REST service.
Features
- Type-safe: PHP 8.1+ type declarations and modern enum support
- Clean architecture: DTOs, validation, and HTTP adapters
- Production + test modes: Switch services via
ViesConfig - Error handling: Structured exceptions for validation and REST errors
- Approximate matching: Trader detail matching support
- All EU countries: EU member states plus Northern Ireland
- Tested: Pest-based test suite
Requirements
- PHP 8.1 or higher
- ext-curl
- ext-json
- ext-mbstring
Installation
Install the package via Composer:
composer require omisai/vies-rest
Quick Start
Basic VAT Validation
use Omisai\ViesRest\ViesClient;
$client = new ViesClient();
$response = $client->checkVat('DE', '123456789');
if ($response->valid) {
echo "✅ Valid VAT: {$response->countryCode}{$response->vatNumber}\n";
echo "Company: {$response->name}\n";
echo "Address: {$response->address}\n";
} else {
echo "❌ Invalid VAT number\n";
}
Using the Test Service
use Omisai\ViesRest\ViesClient;
use Omisai\ViesRest\ViesConfig;
$client = new ViesClient(ViesConfig::test());
$response = $client->checkVat('DE', '100');
var_dump($response->valid); // true for test numbers
Configuration
Environment Configuration
use Omisai\ViesRest\ViesConfig;
$production = ViesConfig::production();
$test = ViesConfig::test();
$custom = ViesConfig::production(baseUrl: 'https://custom-vies.example.com');
HTTP Client Options
use Omisai\ViesRest\ViesClient;
use Omisai\ViesRest\ViesConfig;
$options = [
'timeout' => 30,
'connect_timeout' => 10,
'headers' => [
'User-Agent' => 'MyApp/1.0',
],
];
$client = new ViesClient(ViesConfig::production(options: $options));
API Reference
ViesClient
checkVat(string $countryCode, string $vatNumber): CheckVatResponse
Validates a VAT number and returns basic information.
checkVatApprox(CheckVatRequest $request): CheckVatResponse
Performs approximate validation with trader details.
checkStatus(): StatusInformationResponse
Returns availability info for member states.
Data Transfer Objects (DTOs)
CheckVatRequest
use Omisai\ViesRest\DTO\CheckVatRequest;
$request = new CheckVatRequest(
countryCode: 'NL',
vatNumber: '123456789B01',
traderName: 'Example B.V.',
traderStreet: 'Main Street 123',
traderPostalCode: '1234AB',
traderCity: 'Amsterdam',
requesterMemberStateCode: 'DE',
requesterNumber: '123456789',
);
CheckVatResponse
echo $response->countryCode;
echo $response->vatNumber;
echo $response->requestDate->format('Y-m-d');
echo $response->valid ? 'Yes' : 'No';
Supported Countries
use Omisai\ViesRest\Enum\EuropeanUnionCountry;
$isValid = EuropeanUnionCountry::isEuropeanUnionCountryCode('DE'); // true
$isValid = EuropeanUnionCountry::isEuropeanUnionCountryCode('US'); // false
Error Handling
Validation Errors
use Omisai\ViesRest\Exceptions\ViesValidationException;
use Omisai\ViesRest\ViesClient;
$client = new ViesClient();
try {
$client->checkVat('INVALID', '123');
} catch (ViesValidationException $e) {
echo "Validation error: {$e->getMessage()}\n";
}
REST API Errors
use Omisai\ViesRest\Exceptions\ViesApiException;
use Omisai\ViesRest\ViesClient;
$client = new ViesClient();
try {
$client->checkVat('DE', '123456789');
} catch (ViesApiException $e) {
echo "API error: {$e->getMessage()}\n";
echo "Status code: {$e->getStatusCode()}\n";
}
Advanced Usage
Custom HTTP Client Factory
use Omisai\ViesRest\ViesClient;
use Omisai\ViesRest\Http\HttpClientFactoryInterface;
class CustomHttpClientFactory implements HttpClientFactoryInterface
{
public function create(string $baseUrl, array $options = [])
{
// Return a custom adapter implementing HttpClientInterface
}
}
$client = new ViesClient(clientFactory: new CustomHttpClientFactory());
Custom Validation
use Omisai\ViesRest\ViesClient;
use Omisai\ViesRest\Validation\VatNumberValidator;
class CustomVatNumberValidator extends VatNumberValidator
{
// Implement custom validation logic
}
$client = new ViesClient(validator: new CustomVatNumberValidator());
Batch Processing
use Omisai\ViesRest\ViesClient;
$client = new ViesClient();
$vatNumbers = [
['DE', '123456789'],
['NL', '123456789B01'],
['FR', '12345678901'],
];
$results = [];
foreach ($vatNumbers as [$country, $vat]) {
try {
$response = $client->checkVat($country, $vat);
$results[] = [
'country' => $response->countryCode,
'vat' => $response->vatNumber,
'valid' => $response->valid,
'name' => $response->name,
];
} catch (Exception $e) {
$results[] = [
'country' => $country,
'vat' => $vat,
'error' => $e->getMessage(),
];
}
}
print_r($results);
Testing
Run the test suite using Pest:
composer test
Performance Considerations
- The VIES service has rate limits - avoid excessive requests
- REST calls are synchronous and may take 1-5 seconds
- Consider caching valid VAT numbers to reduce API calls
- Use the test service for development to avoid affecting production quotas
Limitations
- Requires internet connection to VIES service
- Service may be unavailable during maintenance windows
- Rate limiting applies to prevent abuse
- Some countries may have additional validation rules
Contributing
Please see CONTRIBUTING.md for details on how to contribute to this project.
Security
If you discover any security-related issues, please email [email protected] instead of using the issue tracker.
License
This package is open-sourced software licensed under the MIT license.
Sponsoring
If you find this package useful, please consider sponsoring the development: Sponsoring on GitHub
Your support helps us maintain and improve this open-source project!