VATify.eu API
Javascript example

The script below implements a very simple VATify.eu REST API client written in Javascript. Note that this is example code without input sanitization or proper error handling.

Download the source file here. You can test it on a web site or some other de­ve­lop­ment environment. Using node.js, it can be executed directly, by pro­vi­ding the relevant parameters (client ID, access key, coun­try code and com­pany ID) on the command line. For example:

node.exe api_client.js kRZX9qr48dU5 hA2isapCd87T3w76mCgZyoCTYYQgJhgcn BE BE0248015142

See this guide for more in­for­ma­ti­on about how to use the VATify.eu REST APIs.

/*
 *  VATify.eu REST API: JavaScript client module (example code)
 *  Copyright (C) 2022 KoMnA d.o.o. <code@komna.com>
 *
 *  Permission to use, copy, modify, and distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
'use strict';


/*
 *  Try to load module "https".
 *  (node.js only)
 */
try {
    var https = require('https');
} catch (err) {}


/*
 *  Function to run if this script is being executed directly.
 *  (node.js only)
 *
 *  This function reads client credentials, country and company ID from
 *  command line arguments, authenticates to the VATify.eu API server,
 *  preforms a real-time query, and prints the resulting company data to
 *  standard output.
 */
async function main() {

    // Read client credentials, country and company id from the command line.
    const args = process.argv.slice(2);
    if (args.length != 4) {
        process.stderr.write(
          'Usage: ' + process.argv[0] + ' ' + process.argv[1] + 
          ' <client-id> <access-key> <country> <company-id>\n');
        process.exit(1);
    }
    const clientId = args[0];
    const accessKey = args[1];
    const countryId = args[2];
    const companyId = args[3];

    // Authenticate by exchanging the long-term login credentials for a
    // time-limited bearer token.
    const bearerToken = await getBearerToken(clientId, accessKey);

    // Start a VATify.eu real-time query.
    const poolingUrl = await runQuery(bearerToken, countryId, companyId);

    // Wait until the results are ready.
    let results, delay = 500;
    while (true) {
        await new Promise(resolve => setTimeout(resolve, delay));  // sleep

        results = await getQueryResults(bearerToken, poolingUrl);
        if (results !== null)
            break;

        if (delay < 10000)
            delay += 500;
    }

    // Print results.
    process.stdout.write(JSON.stringify(results, null, 2) + '\n');

}


/*
 *  Make an HTTPS request as specified by the arguments, returning a promise
 *  that resolves to a response.  This is just basic processing, no header
 *  analysis or JSON encoding/decoding included.
 *
 *  Note!  There are many ways to make HTTPS requests with Javascript.
 *         This just calls the appropriate (more specific) function,
 *         depending on the execution environment.
 */
async function makeHttpsRequest(method, url, headers, payload) {

    // Node.js: use module "https"
    if (typeof require === 'function')
        return await makeHttpsRequest_1(method, url, headers, payload);

    // Modern browser: use the Fetch API
    if (typeof fetch === 'function')
        return await makeHttpsRequest_2(method, url, headers, payload);

    // Traditional: use XmlHttpRequest (AJAX)
    return await makeHttpsRequest_3(method, url, headers, payload);
}


/*
 *  Make an HTTPS request using the "https" module that comes with node.js.
 */
function makeHttpsRequest_1(method, url, headers, payload) {
    return new Promise((resolve) => {

        const options = {
            method: method,
            headers: headers
          };

        if (payload)
            options.headers['Content-Length'] = payload.length;

        const req = https.request(url, options);
        if (payload)
            req.write(payload);

        req.on('response', (res) => {
            const chunks = [];

            res.on('data', (data) => {
                chunks.push(data);
              });

            res.on('end', () => {
                const response = {
                    status: res.statusCode,
                    headers: res.headers,
                    payload: Buffer.concat(chunks)
                  };
                resolve(response);
              });
          });

        req.end();
      });
}


/*
 *  Make an HTTPS request using the Fetch API available in modern browsers.
 */
function makeHttpsRequest_2(method, url, headers, payload) {
    return new Promise((resolve) => {

        const options = {
            method: method,
            headers: headers,
            mode: 'cors',
          };

        if (payload)
            options.body = payload;

        fetch(url, options)
          .then((res) => {
            res.text()
              .then((data) => {

                const response = {
                    status: res.status,
                    headers: {},
                    payload: data
                  };

                for (let header of res.headers)
                    response.headers[header[0]] = header[1];

                resolve(response);
              });
          });
      });
}


/*
 *  Make an HTTPS request using traditional AJAX (XmlHttpRequest object).
 */
function makeHttpsRequest_3(method, url, headers, payload) {
    return new Promise((resolve) => {

        const xhr = new XMLHttpRequest();

        xhr.onreadystatechange = function() {
            if (xhr.readyState != 4)
                return;

            const response = {
                status: xhr.status,
                headers: {},
                payload: xhr.responseText
              };

            const lines = xhr.getAllResponseHeaders().trim().split('\n');
            for (let i = 0; i < lines.length; i++) {
                const j = lines[i].trim().indexOf(':');
                const headerField = lines[i].slice(0, j).trim();
                const headerValue = lines[i].slice(j+1).trim();
                if (response.headers[headerField])
                    response.headers[headerField] += ', ' + headerValue;
                else
                    response.headers[headerField] = headerValue;
            }

            resolve(response);
          };

        xhr.open(method, url, true);
        for (key in headers)
            xhr.setRequestHeader(key, headers[key]);
        xhr.send(payload);

      });
}


/*
 *  Throw an exception with the appropriate message after a wrong/unexpected
 *  response was received from the VATify.eu REST API.
 */
function handleBadResponse(context, response) {

    var msg;

    try {
        msg = JSON.parse(response.payload)['errors'][0]['detail'];
    } catch {
        msg = 'API responded with (unexpected) status code ' + response.status;
    }

    throw (context + ': ' + msg);
}


/*
 *  Authenticate to the VATify.eu REST API by exchanging a (long-term)
 *  client ID and access key for a (time-limited) bearer token.  The
 *  return value is a string representing the newly issued bearer token.
 */
async function getBearerToken(clientId, accessKey) {

    // Concatenate the client ID and access key using colon as a separator.
    let credentials = clientId + ':' + accessKey;

    // Convert to a Base64-encoded string for HTTP "Basic" authentication.
    if (typeof btoa === 'function')
        credentials = btoa(credentials);  // browser environment, etc.
    else
        credentials = Buffer.from(credentials).toString('base64');  // node.js

    // Prepare HTTPS request.
    const url = 'https://api.vatify.eu/v1/oauth2/token';
    const headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': 'Basic ' + credentials
      };
    const payload = JSON.stringify({
        'grant_type': 'client_credentials'
      });

    // Make the API call and obtain the response.
    const response = await makeHttpsRequest('POST', url, headers, payload);

    // Check the response status.
    if (response.status != 200)
        handleBadResponse('getBearerToken()', response);

    // Return the bearer token.
    return JSON.parse(response.payload)['access_token'];
}


/*
 *  Run a VATify.eu real-time query for company information.  The return
 *  value is a URL address of the API endpoint to poll for query results.
 */
async function runQuery(bearerToken, countryId, companyId) {

    // Prepare HTTPS request.
    const url = 'https://api.vatify.eu/v1/query';
    const headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + bearerToken
      };
    const payload = JSON.stringify({
        'country': countryId,
        'identifier': companyId
      });

    // Make the API call and obtain the response.
    const response = await makeHttpsRequest('POST', url, headers, payload);

    // Check the response status.
    if (response.status != 202)
        handleBadResponse('runQuery()', response);

    // Return the value from the "Location" header.
    // This is the endpoint URL to poll for results.
    return response.headers['location'];
}


/*
 *  Check the status of a VATify.eu real-time query.  Return the query
 *  results (company data), if already available.
 */
async function getQueryResults(bearerToken, resultsURL) {

    // Prepare HTTPS request.
    const headers = {
        'Accept': 'application/json',
        'Authorization': 'Bearer ' + bearerToken
      };

    // Make the API call and obtain the response.
    const response = await makeHttpsRequest('GET', resultsURL, headers, null);

    // Check the response status.
    if (response.status == 202)
        return null;  // results not yet ready.
    if (response.status != 200)
        handleBadResponse('getQueryResults()', response);

    // Return the results (company information).
    return JSON.parse(response.payload)['result']['items'];
}


/*
 *  If this script is being executed directly via node.js, run the
 *  function main() which can be found at the top of this file.
 */
if (typeof require === 'function' && require.main === module) {
    main()
      .catch((error) => {
        process.stderr.write('\n[ERROR]\n' + error + '\n');
        process.exit(1);
      });
}