diff --git a/inventory_provider/db/ims.py b/inventory_provider/db/ims.py
new file mode 100644
index 0000000000000000000000000000000000000000..c85c2d3c6f784615a93a540d58587b7643d1c125
--- /dev/null
+++ b/inventory_provider/db/ims.py
@@ -0,0 +1,198 @@
+import requests
+import time
+
+from enum import Enum
+
+
+# Navigation Properties
+
+# http://149.210.162.190:81/ImsVersions/4.19.9/html/2d27d509-77cb-537d-3ffa-796de7e82af8.htm  # noqa
+NODE_PROPERTIES = {
+    'equipment definition': 16,
+    'management system': 128,
+    'site': 256,
+    'node city': 32768,
+    'order': 67108864,
+    'node country': 1073741824
+}
+# http://149.210.162.190:81/ImsVersions/4.19.9/html/347cb410-8c05-47bd-ceb0-d1dd05bf98a4.htm  # noqa
+CITY_PROPERTIES = {
+    'country': 8
+}
+# http://149.210.162.190:81/ImsVersions/4.19.9/html/347cb410-8c05-47bd-ceb0-d1dd05bf98a4.htm  # noqa
+EQUIP_DEF_PROPERTIES = {
+    'nodes': 4096
+}
+# http://149.210.162.190:81/ImsVersions/4.19.9/html/9c8d50f0-842c-5959-0fa6-14e1720669ec.htm  # noqa
+SITE_PROPERTIES = {
+    'aliases': 64,
+    'city': 2,
+    'country': 256
+}
+
+
+class InventoryStatus(Enum):
+    PLANNED = 1
+    READY_FOR_SERVICE = 2
+    IN_SERVICE = 3
+    MIGRATION = 4
+    OUT_OF_SERVICE = 6
+    READY_FOR_CEASURE = 7
+
+
+class IMSError(Exception):
+    pass
+
+
+class IMS(object):
+
+    TIMEOUT_THRESHOLD = 1200
+    NO_OF_ELEMENTS_PER_ITERATION = 50
+    PERMITTED_RECONNECT_ATTEMPTS = 3
+    LOGIN_PATH = '/login'
+    IMS_PATH = '/ims'
+
+    cache = {}
+    base_url = None
+    bearer_token = None
+    bearer_token_init_time = None
+    reconnect_attempts = 0
+
+    def __init__(self, base_url, username, password):
+        IMS.base_url = base_url
+        self.username = username
+        self.password = password
+
+    @classmethod
+    def _init_bearer_token(cls, username, password):
+        re_init_time = time.time()
+        if not cls.bearer_token or \
+                re_init_time - cls.bearer_token_init_time \
+                > cls.TIMEOUT_THRESHOLD:
+            IMS.reconnect_attempts = 0
+        else:
+            cls.reconnect_attempts += 1
+            if cls.reconnect_attempts > cls.PERMITTED_RECONNECT_ATTEMPTS:
+                raise IMSError('Too many reconnection attempts made')
+
+        response = requests.post(
+            IMS.base_url + IMS.LOGIN_PATH,
+            auth=(username, password))
+        response.raise_for_status()
+        cls.bearer_token_init_time = re_init_time
+        cls.bearer_token = response.json()
+
+    def _get_entity(
+            self,
+            url,
+            params=None,
+            navigation_properties=None,
+            use_cache=False):
+        url = f'{self.base_url + IMS.IMS_PATH}/{url}'
+        cache_key = url
+        if navigation_properties:
+            params = params if params else {}
+            params['navigationproperty'] = navigation_properties if isinstance(
+                navigation_properties, int) else sum(navigation_properties)
+
+        if use_cache:
+            if params:
+                s = '-'.join(
+                    [f'{t}::{params[t]}'
+                     for t in sorted(params)])
+                cache_key = f'{cache_key}::{s}'
+            entity = IMS.cache.get(cache_key, None)
+            if entity:
+                print('Got from cache')  # Remove after demo
+                return entity
+
+        if not IMS.bearer_token:
+            self._init_bearer_token(self.username, self.password)
+
+        make_request = True
+        while make_request:
+            response = requests.get(
+                url,
+                headers={'Authorization': self.bearer_token},
+                params=params)
+            if response.status_code == requests.codes.unauthorized:
+                IMS._init_bearer_token(self.username, self.password)
+            else:
+                make_request = False
+
+        response.raise_for_status()
+        return_value = response.json()
+
+        if use_cache:
+            IMS.cache[cache_key] = return_value
+        return return_value
+
+    def get_entity_by_id(
+            self,
+            entity_type,
+            entity_id,
+            navigation_properties=None,
+            use_cache=False):
+
+        url = f'{entity_type}/{entity_id}'
+        return \
+            self._get_entity(url, None, navigation_properties, use_cache)
+
+    def get_entity_by_name(
+            self,
+            entity,
+            name,
+            navigation_properties=None,
+            use_cache=False):
+        url = f'{entity}/byname/{name}'
+        return self._get_entity(url, None, navigation_properties, use_cache)
+
+    def get_filtered_entities(
+            self,
+            entity,
+            filter_string,
+            navigation_properties=None,
+            use_cache=False):
+        more_to_come = True
+        start_entity = 0
+        while more_to_come:
+            params = {
+                'paginatorStartElement': start_entity,
+                'paginatorNumberOfElements': IMS.NO_OF_ELEMENTS_PER_ITERATION
+            }
+            url = f'{entity}/filtered/{filter_string}'
+            entities = self._get_entity(
+                url,
+                params,
+                navigation_properties,
+                use_cache)
+            more_to_come = False
+            if entities:
+                more_to_come = len(entities) >= IMS.NO_OF_ELEMENTS_PER_ITERATION
+                start_entity += IMS.NO_OF_ELEMENTS_PER_ITERATION
+                yield from entities
+
+    def get_all_entities(
+            self,
+            entity,
+            navigation_properties=None,
+            use_cache=False):
+        yield from self.get_filtered_entities(
+            entity,
+            'Id <> 0',
+            navigation_properties,
+            use_cache)
+
+
+if __name__ == '__main__':
+    import sys
+    username = sys.argv[1]
+    password = sys.argv[2]
+    ims = IMS('http://83.97.94.128:81/api', username, password)
+    i = ims.get_entity_by_name(
+        'Site',
+        'London',
+        SITE_PROPERTIES.values())
+    print(i)
+
+