'VIES VAT number validation

How to incorporate a form on our website to validate the VIES? I find information to validate it through the website of the European Union.

http://ec.europa.eu/taxation_customs/vies/vieshome.do

And what interest me is validate directly from the form of payment data from my website.



Solution 1:[1]

Actually, the VIES database can be queried via their API.
They support only the SOAP protocol, but that should be sufficient.

Here's a simple example:

$client = new SoapClient("http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");
var_dump($client->checkVat(array(
  'countryCode' => $countryCode,
  'vatNumber' => $vatNo
)));

Here's the WSDL: http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl

There are multiple providers of APIs which are based on the original one, but provide it using different protocols. Simply told, they act like translators - using json with your application and connect using SOAP to the original API. These have a major problem with the connection timeout.

There are times where the VIES database is responding slowly, thus requiring more time to return a response. This should be considered while designing your application.

Solution 2:[2]

If for some reasons you can't use SOAP on your server (no available, whatever) then file_get_contents is your friend.

The implementation below does not depend on SOAP, Curl, XMLParser (Simple or not). It is standard PHP code that should work on any PHP version you may have.

The function returns the following items:

  • countryCode
  • vatNumber
  • requestDate
  • valid
  • name
  • address

Well, I hope it helps :-)

<?php
DEFINE ( 'VIES_URL', 'http://ec.europa.eu/taxation_customs/vies/services/checkVatService' );

/**
 * VIES VAT number validation
 *
 * @author Eugen Mihailescu
 *        
 * @param string $countryCode           
 * @param string $vatNumber         
 * @param int $timeout          
 */
function viesCheckVAT($countryCode, $vatNumber, $timeout = 30) {
    $response = array ();
    $pattern = '/<(%s).*?>([\s\S]*)<\/\1/';
    $keys = array (
            'countryCode',
            'vatNumber',
            'requestDate',
            'valid',
            'name',
            'address' 
    );

    $content = "<s11:Envelope xmlns:s11='http://schemas.xmlsoap.org/soap/envelope/'>
  <s11:Body>
    <tns1:checkVat xmlns:tns1='urn:ec.europa.eu:taxud:vies:services:checkVat:types'>
      <tns1:countryCode>%s</tns1:countryCode>
      <tns1:vatNumber>%s</tns1:vatNumber>
    </tns1:checkVat>
  </s11:Body>
</s11:Envelope>";

    $opts = array (
            'http' => array (
                    'method' => 'POST',
                    'header' => "Content-Type: text/xml; charset=utf-8; SOAPAction: checkVatService",
                    'content' => sprintf ( $content, $countryCode, $vatNumber ),
                    'timeout' => $timeout 
            ) 
    );

    $ctx = stream_context_create ( $opts );
    $result = file_get_contents ( VIES_URL, false, $ctx );

    if (preg_match ( sprintf ( $pattern, 'checkVatResponse' ), $result, $matches )) {
        foreach ( $keys as $key )
            preg_match ( sprintf ( $pattern, $key ), $matches [2], $value ) && $response [$key] = $value [2];
    }
    return $response;
}

print_r ( viesCheckVAT ( 'RO', '19386256' ) );
?>

Solution 3:[3]

This is a composer package, which wraps the VIES WebService. You can use this fast and easy: https://github.com/drahosistvan/vatvalidation

Solution 4:[4]

Here is a full stack validation javascript based validation script with regex + modulo per country:

http://www.braemoor.co.uk/software/vat.shtml

Download link: http://www.braemoor.co.uk/software/downloads/jsvat.zip

Using webservices is sometime not an option.

Also see PHP ports for EU VAT validation:

EDIT: Please note, that links above refer to unofficial validation libraries. That means some algos are not officially published, other may change in time. Libraries referred above might be helpful if utilizing official VIES webservices is not possible (e.g. intranet without online access, VIES offline etc.). If the validation using these libs passes then EU VAT has a good chance say 90-95% that it could be valid, but definitely not 100%. Only VIES can ensure 100% validity.

Solution 5:[5]

You can use now js lib for european VAT validation:

jsvat - small library to check validity of EU VAT number

Based on braemoor's vat lib, but rewrite with modern js standarts (braemoor, for exapmpe stil use .eval()) and added to bower and npm registry. Also with unit tests.

bower i jsvat --save

or

npm i jsvat --save

Solution 6:[6]

I needed this in ruby, so here is my code

  • gem install savon
  • add this method to your controller

    def validateVAT
      # create a client for the service
      client = Savon.client(wsdl: 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl')
      response = client.call(:check_vat, message: {countryCode: params[:country_code], vatNumber: params[:vat]})
      render json: { valid: response.body[:check_vat_response][:valid] }, status: :ok
    end
    

Solution 7:[7]

I used the REST service at http://vatid.eu, but since they were blocked by VIES (I guess due to high volume of requests), I have switched to http://apilayer.net/.

The free plan is 100 requests per month, so I have implemented a small cache and I generate my own table of valid VAT numbers (renewable every year), so I don't spend requests checking the same VAT number more than once. Suits my needs ;)

Solution 8:[8]

Here my solution in node:

import axios from "axios";
import { JSDOM } from "jsdom";

export async function checkVatNumber(vatIdentificationNumber: string) {
  const regexVat = new RegExp(/([A-Z]{2})([0-9A-Za-z\+\*\.]{2,12})/);
  const match = vatIdentificationNumber.match(regexVat);

  if (!match || match.length !== 3) return null;

  const [fullVat, countryCode, vatNumber] = match;

  let xmls = `
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Header/>
      <soapenv:Body>
      <tns1:checkVatApprox xmlns:tns1="urn:ec.europa.eu:taxud:vies:services:checkVat:types">
        <tns1:countryCode>${countryCode}</tns1:countryCode>
        <tns1:vatNumber>${vatNumber}</tns1:vatNumber>
      </tns1:checkVatApprox>
      </soapenv:Body>
    </soapenv:Envelope>
  `;

  const response = await axios.post(
    "http://ec.europa.eu/taxation_customs/vies/services/checkVatService",
    xmls,
    { headers: { "Content-Type": "text/xml" } }
  );

  const dom = new JSDOM(response.data, { contentType: "application/xml" });
  const valid = dom.window.document.querySelector("valid")?.textContent;
  const traderName =
    dom.window.document.querySelector("traderName")?.textContent;
  const traderCompanyType =
    dom.window.document.querySelector("traderCompanyType")?.textContent;
  const traderAddress =
    dom.window.document.querySelector("traderAddress")?.textContent;

  return { fullVat, valid, traderName, traderCompanyType, traderAddress };
}

Usage:

const vatData = await checkVatNumber("IE6388047V");
console.log({ vatData });

// vatData: {
//   fullVat: 'IE6388047V',
//   valid: 'true',
//   traderName: 'GOOGLE IRELAND LIMITED',
//   traderCompanyType: '---',
//   traderAddress: '3RD FLOOR, GORDON HOUSE, BARROW STREET, DUBLIN 4'
// }

You have to install these dependencies:

npm install axios jsdom
npm i --save-dev @types/jsdom // <-- if using Typescript

Obviously you want to add some error handling here and there but you get the gist ;)

Solution 9:[9]

There is also a API for the VIES database. https://vatlayer.com/documentation.

I'm looking for a work around for splitting the address information. Now you can get it but it is one string.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Eugen Mihailescu
Solution 3 ISTI
Solution 4
Solution 5 Sergei Panfilov
Solution 6 Ivan Stojkovic
Solution 7 Tarrakis
Solution 8
Solution 9 Wouter Schoofs