Component using the European Commission (EC) VAT Information Exchange System (VIES) to verify and validate VAT registration numbers in the EU, using PHP and Composer.
The Vies
class provides functionality to make a SOAP call to VIES and returns an object CheckVatResponse
containing the following information:
Stated on the European Commission website:
To make an intra-Community supply without charging VAT, you should ensure that the person to whom you are supplying the goods is a taxable person in another Member State, and that the goods in question have left, or will leave your Member State to another MS. VAT-number should also be in the invoice.
More information at http://ec.europa.eu/taxation_customs/vies/faqvies.do#item16
On May 25, 2018 the General Data Protection Regulation or GDPR becomes law within all 28 European Member States. Is this VIES service package going to be compliant with GDPR?
In short: yes.
The longer answer is that this VIES package only interacts with the service for VAT ID verification provided by the European Commission. VAT validation is mandatory in European countries and therefor this service is allowed as lawfulness and legal basis. Please read more about this in European DPO-3816.1. This service does not store any data itself or collects more information than what's strictly required by law and provided by the EC VIES service.
When you have implemented this service package in your own project, be sure that you're making sure you're just store the VAT ID, the timestamp of validation, the result of validation and optionally the given validation ID provided by the EC VIES service.
Please read the release notes for details.
This project is on Packagist!
To install the latest stable version use composer require dragonbe/vies
.
To install specifically a version (e.g. 2.2.0), just add it to the command above, for example composer require dragonbe/vies:2.2.0
Here's a usage example you can immediately execute on the command line (or in cron, worker or whatever) as this will most likely be your most common usecase.
<?php
use DragonBe\Vies\Vies;
use DragonBe\Vies\ViesException;
use DragonBe\Vies\ViesServiceException;
require_once dirname(__DIR__) . '/vendor/autoload.php';
$vies = new Vies();
if (false === $vies->getHeartBeat()->isAlive()) {
echo 'Service is not available at the moment, please try again later.' . PHP_EOL;
exit(1);
}
$vies = new Vies();
$options = [
'proxy_host' => '127.0.0.1',
'proxy_port' => '8888',
];
$vies->setOptions($options);
$heartBeat = new \DragonBe\Vies\HeartBeat('tcp://' . $options['proxy_host'], $options['proxy_port']);
$vies->setHeartBeat($heartBeat);
$isAlive = $vies->getHeartBeat()->isAlive();
Now that we know the service is alive, we can start validating VAT ID's
$vatResult = $vies->validateVat(
'BE', // Trader country code
'0203430576', // Trader VAT ID
'BE', // Requester country code
'0811231190' // Requester VAT ID
);
$vatResult = $vies->validateVat(
'BE', // Trader country code
'0203430576', // Trader VAT ID
'BE', // Requester country code
'0811231190' // Requester VAT ID
'B-Rail', // Trader name
'NV', // Trader company type
'Frankrijkstraat 65', // Trader street address
'1060', // Trader postcode
'Sint-Gillis' // Trader city
);
The most important functionality is to see if the VAT ID is valid
echo ($vatResult->isValid() ? 'Valid' : 'Not valid') . PHP_EOL;
// Result: Valid
echo 'Identifier: ' . $vatResult->getIdentifier() . PHP_EOL;
// Result: Identifier: WAPIAAAAWaXGj4Ra
Note: VIES service returns date and timezone, but no time
echo 'Date and time: ' . $vatResult->getRequestDate()->format('r') . PHP_EOL;
// Result: Date and time: Sat, 31 Aug 2019 00:00:00 +0200
echo 'Company name: ' . $vatResult->getName() . PHP_EOL;
// Result: Company name: NV OR NATIONALE MAATSCHAPPIJ DER BELGISCHE SPOORWEGEN
echo 'Company address: ' . $vatResult->getAddress() . PHP_EOL;
// Result: Company address: FRANKRIJKSTRAAT 56
1060 SINT-GILLIS (BIJ-BRUSSEL)
echo 'Trader name match: ' . $vatResult->getNameMatch() . PHP_EOL;
// Result: Trader name match:
echo 'Trader company type match: ' . $vatResult->getCompanyTypeMatch() . PHP_EOL;
// Result: Trader company type match:
echo 'Trader street match: ' . $vatResult->getStreetMatch() . PHP_EOL;
// Result: Trader street match:
echo 'Trader postcode match: ' . $vatResult->getPostcodeMatch() . PHP_EOL;
// Result: Trader postcode match:
echo 'Trader city match: ' . $vatResult->getCityMatch() . PHP_EOL;
// Result: Trader city match:
<?php
use DragonBe\Vies\Vies;
use DragonBe\Vies\ViesException;
use DragonBe\Vies\ViesServiceException;
require_once dirname(__DIR__) . '/vendor/autoload.php';
$vies = new Vies();
$company = [
'country_code' => 'BE',
'vat_id' => '0203430576',
'trader_name' => 'B-Rail',
'trader_company_type' => 'NV',
'trader_street' => 'Frankrijkstraat 65',
'trader_postcode' => '1060',
'trader_city' => 'Sint-Gillis',
];
try {
$vatResult = $vies->validateVat(
$company['country_code'], // Trader country code
$company['vat_id'], // Trader VAT ID
'BE', // Requester country code (your country code)
'0811231190', // Requester VAT ID (your VAT ID)
$company['trader_name'], // Trader name
$company['trader_company_type'], // Trader company type
$company['trader_street'], // Trader street address
$company['trader_postcode'], // Trader postcode
$company['trader_city'] // Trader city
);
} catch (ViesException $viesException) {
echo 'Cannot process VAT validation: ' . $viesException->getMessage();
exit (2);
} catch (ViesServiceException $viesServiceException) {
echo 'Cannot process VAT validation: ' . $viesServiceException->getMessage();
exit (2);
}
echo ($vatResult->isValid() ? 'Valid' : 'Not valid') . PHP_EOL;
echo 'Identifier: ' . $vatResult->getIdentifier() . PHP_EOL;
echo 'Date and time: ' . $vatResult->getRequestDate()->format('d/m/Y H:i') . PHP_EOL;
echo 'Company name: ' . $vatResult->getName() . PHP_EOL;
echo 'Company address: ' . $vatResult->getAddress() . PHP_EOL;
echo 'Trader name match: ' . $vatResult->getNameMatch() . PHP_EOL;
echo 'Trader company type match: ' . $vatResult->getCompanyTypeMatch() . PHP_EOL;
echo 'Trader street match: ' . $vatResult->getStreetMatch() . PHP_EOL;
echo 'Trader postcode match: ' . $vatResult->getPostcodeMatch() . PHP_EOL;
echo 'Trader city match: ' . $vatResult->getCityMatch() . PHP_EOL;
echo PHP_EOL;
When you run this, you will get the following result:
Valid
Identifier: WAPIAAAAWaYR0O8D
Date and time: 21/10/2018 02:00
Company name: NV OR NATIONALE MAATSCHAPPIJ DER BELGISCHE SPOORWEGEN
Company address: FRANKRIJKSTRAAT 56
1060 SINT-GILLIS (BIJ-BRUSSEL)
Trader name match:
Trader company type match:
Trader street match:
Trader postcode match:
Trader city match:
Here's a list of products or projects that have included this VIES package
If you have a product or a project that's using this package and you want some attribution for your work, send me an email or ping me on Twitter or Facebook.
If you like to have Docker containers, you can now make use of a container designed for that purpose.
docker run --rm -d -p 8000:18080 dragonbe/vies-web
Point your browser to localhost:8000 to use the web interface for validating VAT.
For Greece the international country ISO code is GR, but for VAT IDN's they use the prefix EL. Thanks to Johan Wilfer for reporting this.
Since January 1, 2021 the UK is no longer a member of the European Union and as a result, the VIES service provided by the European Commission no longer validates VAT ID's for the UK. There is one exception though and that is for Northern Ireland (XI) for which VAT ID's can be validated using this library and the EC VIES service.
DragonBe\Vies is released under the MIT Licence. See the bundled LICENCE file for details.