laravel-vies-rest
A Laravel adapter for the VIES REST API package, utilizing Laravel's HTTP client.
Install
composer require omisai/laravel-vies-restLaravel VIES REST
A Laravel adapter for the VIES REST API package, utilizing Laravel's HTTP client.
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
- omisai/vies-rest (base package)
- illuminate/http v10 or higher (Laravel HTTP client)
Installation
Install the package via Composer:
composer require omisai/laravel-vies-rest
Quick Start
This package requires the base omisai/vies-rest package.
The Omisai\LaravelViesRest\ViesRestServiceProvider service provider automatically registers the Laravel HTTP client adapter. The Omisai\ViesRest\ViesClient will use Laravel's HTTP client instead of direct Guzzle.
Via Dependency Injection
...
use Omisai\ViesRest\ViesClient;
use Omisai\ViesRest\Enum\EuropeanUnionCountry;
class ExampleController extends Controller
{
public function __construct(
private ViesClient $viesClient,
) {}
public function checkVat(Request $request)
{
$countryCode = $request->input('country_code');
$vatNumber = $request->input('vat_number');
$isValidCountryCode = EuropeanUnionCountry::validateCountryCode($countryCode);
if (!$isValidCountryCode) {
return response()->json(['error' => 'Invalid country code'], 400);
}
$response = $this->viesClient->checkVat($countryCode, $vatNumber);
return response()->json([
'valid' => $response->valid,
'name' => $response->name,
'address' => $response->address,
]);
}
}
Via Service Container Resolution
<?php
// In a controller, service, or route closure
$client = app(ViesClient::class);
$response = $client->checkVat('DE', '123456789');
Using the Test Service
use Omisai\ViesRest\ViesClient;
use Omisai\ViesRest\ViesConfig;
$config = ViesConfig::test(); /
$factory = app(HttpClientFactoryInterface::class);
$client = new ViesClient($config, $factory);
$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
# Omisai\ViesRest\DTO\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 = app(ViesClient::class);
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 = app(ViesClient::class);
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 = app(ViesClient::class);
$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!