diff --git a/inventory_provider/__init__.py b/inventory_provider/__init__.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2918d68e2776b9ce8c3de4f05f80c839742755b2 100644
--- a/inventory_provider/__init__.py
+++ b/inventory_provider/__init__.py
@@ -0,0 +1,43 @@
+"""
+automatically invoked app factory
+"""
+import logging
+import os
+from flask import Flask
+
+
+def create_app():
+    """
+    overrides default settings with those found
+    in the file read from env var SETTINGS_FILENAME
+
+    :return: a new flask app instance
+    """
+
+    app = Flask(__name__)
+    app.secret_key = "super secret session key"
+
+    from inventory_provider import data_routes
+    app.register_blueprint(data_routes.routes, url_prefix='/data')
+
+    if "SETTINGS_FILENAME" not in os.environ:
+        assert False, \
+            "environment variable SETTINGS_FILENAME' must be defined"
+    app.config.from_envvar("SETTINGS_FILENAME")
+
+    assert "INVENTORY_PROVIDER_CONFIG_FILENAME" in app.config, (
+        "INVENTORY_PROVIDER_CONFIG_FILENAME not defined in %s"
+        % os.environ["SETTINGS_FILENAME"])
+
+    assert os.path.isfile(app.config["INVENTORY_PROVIDER_CONFIG_FILENAME"]), (
+        "config file '%s' not found" %
+        app.config["INVENTORY_PROVIDER_CONFIG_FILENAME"])
+
+    from inventory_provider import config
+    with open(app.config["INVENTORY_PROVIDER_CONFIG_FILENAME"]) as f:
+        # test the config file can be loaded
+        config.load(f)
+
+    logging.debug(app.config)
+
+    return app
diff --git a/inventory_provider/data_routes.py b/inventory_provider/data_routes.py
new file mode 100644
index 0000000000000000000000000000000000000000..01b6f12cbcc84e9011a19851e43304c7ee4ccf5c
--- /dev/null
+++ b/inventory_provider/data_routes.py
@@ -0,0 +1,40 @@
+import functools
+import json
+
+from flask import Blueprint, request, Response
+#render_template, url_for
+
+routes = Blueprint("python-utils-ui-routes", __name__)
+
+VERSION = {
+    "api": "0.1",
+    "module": "0.1"
+}
+
+
+def require_accepts_json(f):
+    """
+    used as a route handler decorator to return an error
+    unless the request allows responses with type "application/json"
+    :param f: the function to be decorated
+    :return: the decorated function
+    """
+    @functools.wraps(f)
+    def decorated_function(*args, **kwargs):
+        # TODO: use best_match to disallow */* ...?
+        if not request.accept_mimetypes.accept_json:
+            return Response(
+                response="response will be json",
+                status=406,
+                mimetype="text/html")
+        return f(*args, **kwargs)
+    return decorated_function
+
+
+@routes.route("/version", methods=['GET', 'POST'])
+@require_accepts_json
+def version():
+    return Response(
+        json.dumps(VERSION),
+        mimetype="application/json"
+    )
diff --git a/requirements.txt b/requirements.txt
index 57746b4c8a1cafc94f5ccb363f4bd7cb1159b2fd..ea667eb9d92fa5f7855ca9f376c17a27a22e1686 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,5 +3,6 @@ mysql-connector
 pysnmp
 jsonschema
 paramiko
+flask
 
 pytest
diff --git a/setup.py b/setup.py
index c375511aead517d25b466a98df98935d15aaea7f..65e429b28e1424c732fa1a447ed49e7ee09e7cbc 100644
--- a/setup.py
+++ b/setup.py
@@ -14,6 +14,7 @@ setup(
         'mysql-connector',
         'pysnmp',
         'jsonschema',
-        'paramiko'
+        'paramiko',
+        'flask'
     ]
 )
diff --git a/test/test_data_routes.py b/test/test_data_routes.py
new file mode 100644
index 0000000000000000000000000000000000000000..617e89e6ff5cb1fd425f04dae0e264b5fa06f46d
--- /dev/null
+++ b/test/test_data_routes.py
@@ -0,0 +1,159 @@
+import json
+import logging
+import os
+import tempfile
+
+import pytest
+import jsonschema
+
+import inventory_provider
+
+# logging.basicConfig(level=logging.DEBUG)
+
+DEFAULT_REQUEST_HEADERS = {
+    "Content-type": "application/json",
+    "Accept": ["application/json"]
+}
+
+MODULE_DIR = os.path.realpath(os.path.join(
+    os.path.dirname(__file__),
+    "..",
+    "inventory_provider"))
+
+OID_LIST_CONF = """
+#
+#   This file is located in dbupdates/conf and is used by scripts under dbupdates/scripts.
+#   It holds OID values for retrieving details of a router.
+#
+
+## IPv4
+v4Address=.1.3.6.1.2.1.4.20.1.1
+v4InterfaceOID=.1.3.6.1.2.1.4.20.1.2
+v4InterfaceName=.1.3.6.1.2.1.31.1.1.1.1
+v4Mask=.1.3.6.1.2.1.4.20.1.3
+
+## IPv6
+v6AddressAndMask=.1.3.6.1.2.1.55.1.8.1.2
+v6InterfaceName=.1.3.6.1.2.1.55.1.5.1.2
+"""
+
+ROUTERS_COMMUNITY_CONF = """
+######################################################################################################################################
+##                                                                                                                                  ##
+##  This is a configuration file that stores router names and the SNMP community name in <router>=<community>,<IP address> format.  ##
+##                                                                                                                                  ##
+######################################################################################################################################
+
+mx2.ath.gr.geant.net=0pBiFbD,62.40.114.59
+mx1.tal.ee.geant.net=0pBiFbD,62.40.96.1
+mx2.tal.ee.geant.net=0pBiFbD,62.40.96.2
+mx2.rig.lv.geant.net=0pBiFbD,62.40.96.4
+mx1.kau.lt.geant.net=0pBiFbD,62.40.96.6
+mx2.kau.lt.geant.net=0pBiFbD,62.40.96.5
+mx2.zag.hr.geant.net=0pBiFbD,62.40.96.8
+mx2.lju.si.geant.net=0pBiFbD,62.40.96.10
+mx1.bud.hu.geant.net=0pBiFbD,62.40.97.1
+mx1.pra.cz.geant.net=0pBiFbD,62.40.97.2
+mx2.bra.sk.geant.net=0pBiFbD,62.40.97.4
+mx1.lon.uk.geant.net=0pBiFbD,62.40.97.5
+mx1.vie.at.geant.net=0pBiFbD,62.40.97.7
+mx2.bru.be.geant.net=0pBiFbD,62.40.96.20
+mx1.poz.pl.geant.net=0pBiFbD,62.40.97.10
+mx1.ams.nl.geant.net=0pBiFbD,62.40.97.11
+mx1.fra.de.geant.net=0pBiFbD,62.40.97.12
+mx1.par.fr.geant.net=0pBiFbD,62.40.97.13
+mx1.gen.ch.geant.net=0pBiFbD,62.40.97.14
+mx1.mil2.it.geant.net=0pBiFbD,62.40.97.15
+mx1.lis.pt.geant.net=0pBiFbD,62.40.96.16
+mx2.lis.pt.geant.net=0pBiFbD,62.40.96.17
+mx1.mad.es.geant.net=0pBiFbD,62.40.97.16
+mx1.sof.bg.geant.net=0pBiFbD,62.40.96.21
+mx1.buc.ro.geant.net=0pBiFbD,62.40.96.19
+mx1.ham.de.geant.net=0pBiFbD,62.40.96.26
+mx1.dub.ie.geant.net=0pBiFbD,62.40.96.3
+mx1.dub2.ie.geant.net=0pBiFbD,62.40.96.25
+mx1.mar.fr.geant.net=0pBiFbD,62.40.96.12
+mx1.lon2.uk.geant.net=0pBiFbD,62.40.96.15
+# rt1.clpk.us.geant.net=GEANT_RO,10.200.64.128
+# rt1.denv.us.geant.net=GEANT_RO,10.200.67.128
+mx1.ath2.gr.geant.net=0pBiFbD,62.40.96.39
+# qfx.par.fr.geant.net=0pBiFbD,62.40.117.170
+# qfx.fra.de.geant.net=0pBiFbD,62.40.117.162
+"""
+
+def data_config_filename(tmp_dir_name):
+    config = {
+        "alarms-db": {
+            "hostname": "xxxxxxx.yyyyy.zzz",
+            "dbname": "xxxxxx",
+            "username": "xxxxxx",
+            "password": "xxxxxxxx"
+        },
+        "oid_list.conf": os.path.join(tmp_dir_name, "oid_list.conf"),
+        "routers_community.conf": os.path.join(tmp_dir_name, "routers_community.conf"),
+        "ssh": {
+            "private-key": "private-key-filename",
+            "known-hosts": "known-hosts=filename"
+        }
+    }
+
+    with open(config["oid_list.conf"], "w") as f:
+        f.write(OID_LIST_CONF)
+
+    with open(config["routers_community.conf"], "w") as f:
+        f.write(ROUTERS_COMMUNITY_CONF)
+
+    filename = os.path.join(tmp_dir_name, "config.json")
+    with open(filename, "w") as f:
+        f.write(json.dumps(config))
+
+    return filename
+
+
+@pytest.fixture
+def app_config():
+    with tempfile.TemporaryDirectory() as tmpdir:
+
+        app_config_filename = os.path.join(tmpdir, "app.config")
+        with open(app_config_filename, "w") as f:
+            f.write("%s = '%s'\n" % (
+                "INVENTORY_PROVIDER_CONFIG_FILENAME",
+                data_config_filename(tmpdir)))
+
+        yield app_config_filename
+
+
+@pytest.fixture
+def client(app_config):
+    os.environ["SETTINGS_FILENAME"] = app_config
+    # with release_webservice.create_app().test_client() as c:
+    #         yield c
+    with inventory_provider.create_app().test_client() as c:
+        yield c
+
+
+def test_version_request(client):
+    version_schema = {
+        "$schema": "http://json-schema.org/draft-07/schema#",
+        "type": "object",
+        "properties": {
+            "api": {
+                "type": "string",
+                "pattern": r'\d+\.\d+'
+            },
+            "module": {
+                "type": "string",
+                "pattern": r'\d+\.\d+'
+    }
+        },
+        "required": ["api", "module"],
+        "additionalProperties": False
+    }
+
+    rv = client.post(
+        "data/version",
+        headers=DEFAULT_REQUEST_HEADERS)
+    assert rv.status_code == 200
+    jsonschema.validate(
+        json.loads(rv.data.decode("utf-8")),
+        version_schema)