diff --git a/src/device/requirements.in b/src/device/requirements.in
index 5c38e92914207bf101ebc00b2cef453a3a85f82a..78abc96ad994c5d2acdb92ba9108b0527d61ecca 100644
--- a/src/device/requirements.in
+++ b/src/device/requirements.in
@@ -11,4 +11,5 @@ pytest-benchmark
 python-json-logger
 pytz
 redis
+requests
 xmltodict
diff --git a/src/device/service/drivers/transport_api/Tools.py b/src/device/service/drivers/transport_api/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..c569404bf7884501f9c8ea494f27983ca78ac3eb
--- /dev/null
+++ b/src/device/service/drivers/transport_api/Tools.py
@@ -0,0 +1,100 @@
+import json, logging, requests
+from device.service.driver_api._Driver import RESOURCE_ENDPOINTS
+
+LOGGER = logging.getLogger(__name__)
+
+
+def find_key(resource, key):
+    return json.loads(resource[1])[key]
+
+
+def config_getter(root_url, resource_key, timeout):
+    url = '{:s}/restconf/data/tapi-common:context'.format(root_url)
+    result = []
+    try:
+        response = requests.get(url, timeout=timeout)
+    except requests.exceptions.Timeout:
+        LOGGER.exception('Timeout connecting {:s}'.format(url))
+    except Exception as e:  # pylint: disable=broad-except
+        LOGGER.exception('Exception retrieving {:s}'.format(resource_key))
+        result.append((resource_key, e))
+    else:
+        context = json.loads(response.content)
+
+        if resource_key == RESOURCE_ENDPOINTS:
+            for sip in context['tapi-common:context']['service-interface-point']:
+                result.append(
+                    ('/endpoints/endpoint[{:s}]'.format(sip['uuid']), {'uuid': sip['uuid'], 'type': '10Gbps'}))
+
+    return result
+
+def create_connectivity_service(
+    root_url, timeout, uuid, input_sip, output_sip, direction, capacity_value, capacity_unit, layer_protocol_name,
+    layer_protocol_qualifier):
+
+    url = '{:s}/restconf/data/tapi-common:context/tapi-connectivity:connectivity-context'.format(root_url)
+    headers = {'content-type': 'application/json'}
+    data = {
+        'tapi-connectivity:connectivity-service': [
+            {
+                'uuid': uuid,
+                'connectivity-constraint': {
+                    'requested-capacity': {
+                        'total-size': {
+                            'value': capacity_value,
+                            'unit': capacity_unit
+                        }
+                    },
+                    'connectivity-direction': direction
+                },
+                'end-point': [
+                    {
+                        'service-interface-point': {
+                            'service-interface-point-uuid': input_sip
+                        },
+                        'layer-protocol-name': layer_protocol_name,
+                        'layer-protocol-qualifier': layer_protocol_qualifier,
+                        'local-id': input_sip
+                    },
+                    {
+                        'service-interface-point': {
+                            'service-interface-point-uuid': output_sip
+                        },
+                        'layer-protocol-name': layer_protocol_name,
+                        'layer-protocol-qualifier': layer_protocol_qualifier,
+                        'local-id': output_sip
+                    }
+                ]
+            }
+        ]
+    }
+    results = []
+    try:
+        LOGGER.info('Connectivity service {:s}: {:s}'.format(str(uuid), str(data)))
+        response = requests.post(url=url, data=json.dumps(data), timeout=timeout, headers=headers)
+        LOGGER.info('TAPI response: {:s}'.format(str(response)))
+    except Exception as e:  # pylint: disable=broad-except
+        LOGGER.exception('Exception creating ConnectivityService(uuid={:s}, data={:s})'.format(str(uuid), str(data)))
+        results.append(e)
+    else:
+        if response.status_code != 201:
+            msg = 'Could not create ConnectivityService(uuid={:s}, data={:s}). status_code={:s} reply={:s}'
+            LOGGER.error(msg.format(str(uuid), str(data), str(response.status_code), str(response)))
+        results.append(response.status_code == 201)
+    return results
+
+def delete_connectivity_service(root_url, timeout, uuid):
+    url = '{:s}/restconf/data/tapi-common:context/tapi-connectivity:connectivity-context/connectivity-service={:s}'
+    url = url.format(root_url, uuid)
+    results = []
+    try:
+        response = requests.delete(url=url, timeout=timeout)
+    except Exception as e:  # pylint: disable=broad-except
+        LOGGER.exception('Exception deleting ConnectivityService(uuid={:s})'.format(str(uuid)))
+        results.append(e)
+    else:
+        if response.status_code != 201:
+            msg = 'Could not delete ConnectivityService(uuid={:s}). status_code={:s} reply={:s}'
+            LOGGER.error(msg.format(str(uuid), str(response.status_code), str(response)))
+        results.append(response.status_code == 202)
+    return results
diff --git a/src/device/service/drivers/transport_api/TransportApiDriver.py b/src/device/service/drivers/transport_api/TransportApiDriver.py
index f20173dd022a517d1e5630dc23c3455b0ed3c710..b3e5f4fa33f20836629c06968261fb1ceac8f075 100644
--- a/src/device/service/drivers/transport_api/TransportApiDriver.py
+++ b/src/device/service/drivers/transport_api/TransportApiDriver.py
@@ -1,9 +1,97 @@
-import logging
+import logging, requests, threading
+from typing import Any, Iterator, List, Tuple, Union
+from common.type_checkers.Checkers import chk_string, chk_type
 from device.service.driver_api._Driver import _Driver
+from . import ALL_RESOURCE_KEYS
+from .Tools import create_connectivity_service, find_key, config_getter, delete_connectivity_service
 
 LOGGER = logging.getLogger(__name__)
 
-# TODO: Implement TransportAPI Driver
-
 class TransportApiDriver(_Driver):
-    pass
+    def __init__(self, address: str, port: int, **settings) -> None:    # pylint: disable=super-init-not-called
+        self.__lock = threading.Lock()
+        self.__started = threading.Event()
+        self.__terminate = threading.Event()
+        self.__tapi_root = 'http://' + address + ':' + str(port)
+        self.__timeout = int(settings.get('timeout', 120))
+
+    def Connect(self) -> bool:
+        url = self.__tapi_root + '/restconf/data/tapi-common:context'
+        with self.__lock:
+            if self.__started.is_set(): return True
+            try:
+                requests.get(url, timeout=self.__timeout)
+            except requests.exceptions.Timeout:
+                LOGGER.exception('Timeout connecting {:s}'.format(str(self.__tapi_root)))
+                return False
+            except Exception:  # pylint: disable=broad-except
+                LOGGER.exception('Exception connecting {:s}'.format(str(self.__tapi_root)))
+                return False
+            else:
+                self.__started.set()
+                return True
+
+    def Disconnect(self) -> bool:
+        with self.__lock:
+            self.__terminate.set()
+            return True
+
+    def GetInitialConfig(self) -> List[Tuple[str, Any]]:
+        with self.__lock:
+            return []
+
+    def GetConfig(self, resource_keys : List[str] = []) -> List[Tuple[str, Union[Any, None, Exception]]]:
+        chk_type('resources', resource_keys, list)
+        results = []
+        with self.__lock:
+            if len(resource_keys) == 0: resource_keys = ALL_RESOURCE_KEYS
+            for i, resource_key in enumerate(resource_keys):
+                str_resource_name = 'resource_key[#{:d}]'.format(i)
+                chk_string(str_resource_name, resource_key, allow_empty=False)
+                results.extend(config_getter(self.__tapi_root, resource_key, self.__timeout))
+        return results
+
+    def SetConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        results = []
+        if len(resources) == 0:
+            return results
+        with self.__lock:
+            for resource in resources:
+                LOGGER.info('resource = {:s}'.format(str(resource)))
+
+                input_sip = find_key(resource, 'input_sip')
+                output_sip = find_key(resource, 'output_sip')
+                uuid = find_key(resource, 'uuid')
+                capacity_value = find_key(resource, 'capacity_value')
+                capacity_unit = find_key(resource, 'capacity_unit')
+                layer_protocol_name = find_key(resource, 'layer_protocol_name')
+                layer_protocol_qualifier = find_key(resource, 'layer_protocol_qualifier')
+                direction = find_key(resource, 'direction')
+
+                data = create_connectivity_service(
+                    self.__tapi_root, self.__timeout, uuid, input_sip, output_sip, direction, capacity_value,
+                    capacity_unit, layer_protocol_name, layer_protocol_qualifier)
+                results.extend(data)
+        return results
+
+    def DeleteConfig(self, resources: List[Tuple[str, Any]]) -> List[Union[bool, Exception]]:
+        results = []
+        if len(resources) == 0: return results
+        with self.__lock:
+            for resource in resources:
+                LOGGER.info('resource = {:s}'.format(str(resource)))
+                uuid = find_key(resource, 'uuid')
+                results.extend(delete_connectivity_service(self.__tapi_root, self.__timeout, uuid))
+        return results
+
+    def SubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
+        # TODO: TAPI does not support monitoring by now
+        return [False for _ in subscriptions]
+
+    def UnsubscribeState(self, subscriptions : List[Tuple[str, float, float]]) -> List[Union[bool, Exception]]:
+        # TODO: TAPI does not support monitoring by now
+        return [False for _ in subscriptions]
+
+    def GetState(self, blocking=False) -> Iterator[Tuple[float, str, Any]]:
+        # TODO: TAPI does not support monitoring by now
+        return []
diff --git a/src/device/service/drivers/transport_api/__init__.py b/src/device/service/drivers/transport_api/__init__.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d2a2d4b1a6c224c370479103553a769ce8a0956f 100644
--- a/src/device/service/drivers/transport_api/__init__.py
+++ b/src/device/service/drivers/transport_api/__init__.py
@@ -0,0 +1,13 @@
+from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES
+
+ALL_RESOURCE_KEYS = [
+    RESOURCE_ENDPOINTS,
+    RESOURCE_INTERFACES,
+    RESOURCE_NETWORK_INSTANCES,
+]
+
+RESOURCE_KEY_MAPPINGS = {
+    RESOURCE_ENDPOINTS        : 'component',
+    RESOURCE_INTERFACES       : 'interface',
+    RESOURCE_NETWORK_INSTANCES: 'network_instance',
+}
diff --git a/src/device/tests/Device_Transport_Api_Template.py b/src/device/tests/Device_Transport_Api_Template.py
new file mode 100644
index 0000000000000000000000000000000000000000..6032f0ff8ba683cd3a39bb6bd3c7a8c905974ce6
--- /dev/null
+++ b/src/device/tests/Device_Transport_Api_Template.py
@@ -0,0 +1,40 @@
+from copy import deepcopy
+from device.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum
+from .Tools import config_rule_set, config_rule_delete
+
+# use "deepcopy" to prevent propagating forced changes during tests
+
+DEVICE_TAPI_UUID         = 'DEVICE-TAPI'
+DEVICE_TAPI_TYPE         = 'optical-line-system'
+DEVICE_TAPI_ADDRESS      = '0.0.0.0'
+DEVICE_TAPI_PORT         = '4900'
+DEVICE_TAPI_TIMEOUT      = '120'
+DEVICE_TAPI_DRIVERS      = [DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API]
+
+DEVICE_TAPI_ID = {'device_uuid': {'uuid': DEVICE_TAPI_UUID}}
+DEVICE_TAPI = {
+    'device_id': deepcopy(DEVICE_TAPI_ID),
+    'device_type': DEVICE_TAPI_TYPE,
+    'device_config': {'config_rules': []},
+    'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED,
+    'device_drivers': DEVICE_TAPI_DRIVERS,
+    'device_endpoints': [],
+}
+
+DEVICE_TAPI_CONNECT_RULES = [
+    config_rule_set('_connect/address',  DEVICE_TAPI_ADDRESS),
+    config_rule_set('_connect/port',     DEVICE_TAPI_PORT),
+    config_rule_set('_connect/timeout',  DEVICE_TAPI_TIMEOUT),
+]
+
+DEVICE_TAPI_CONFIG_RULES = [
+    config_rule_set('network_instance[DemoOFC-NetInst]/interface[13/1/3]', {
+        'name': 'DemoOFC-NetInst', 'id': '13/1/3',
+    })
+]
+
+DEVICE_TAPI_DECONFIG_RULES = [
+    config_rule_delete('network_instance[DemoOFC-NetInst]/interface[13/1/3]', {
+        'name': 'DemoOFC-NetInst', 'id': '13/1/3'
+    })
+]
\ No newline at end of file
diff --git a/src/device/tests/test_unitary.py b/src/device/tests/test_unitary.py
index 046131810a6b00cb8e345111b017450493b6fcba..f5c43309e1682cd12925d853793d8dd0982e245b 100644
--- a/src/device/tests/test_unitary.py
+++ b/src/device/tests/test_unitary.py
@@ -49,6 +49,21 @@ except ImportError:
     #       DEVICE_OC, DEVICE_OC_CONFIG_RULES, DEVICE_OC_DECONFIG_RULES, DEVICE_OC_CONNECT_RULES, DEVICE_OC_ID,
     #       DEVICE_OC_UUID)
 
+try:
+    from .Device_Transport_Api_CTTC import (
+        DEVICE_TAPI, DEVICE_TAPI_CONNECT_RULES, DEVICE_TAPI_UUID, DEVICE_TAPI_ID, DEVICE_TAPI_CONFIG_RULES,
+        DEVICE_TAPI_DECONFIG_RULES)
+    ENABLE_TAPI = True
+except ImportError:
+    ENABLE_TAPI = False
+    # Create a Device_Transport_Api_??.py file with the details for your device to test it and import it as follows in
+    # the try block of this import statement.
+    #   from .Device_Transport_Api_?? import(
+    #       DEVICE_TAPI, DEVICE_TAPI_CONFIG_RULES, DEVICE_TAPI_DECONFIG_RULES, DEVICE_TAPI_CONNECT_RULES,
+    #       DEVICE_TAPI_ID, DEVICE_TAPI_UUID)
+
+#ENABLE_OPENCONFIG = False
+#ENABLE_TAPI       = False
 
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
@@ -586,3 +601,130 @@ def test_device_openconfig_delete(
     device_client.DeleteDevice(DeviceId(**DEVICE_OC_ID))
     driver : _Driver = device_service.driver_instance_cache.get(DEVICE_OC_UUID, {})
     assert driver is None
+
+
+# ----- Test Device Driver TAPI ----------------------------------------------------------------------------------
+
+def test_device_tapi_add_error_cases(
+    device_client : DeviceClient):      # pylint: disable=redefined-outer-name
+
+    if not ENABLE_TAPI: return # if there is no device to test against, asusme test is silently passed.
+
+    with pytest.raises(grpc.RpcError) as e:
+        DEVICE_TAPI_WITH_EXTRA_RULES = copy.deepcopy(DEVICE_TAPI)
+        DEVICE_TAPI_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_TAPI_CONNECT_RULES)
+        DEVICE_TAPI_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_TAPI_CONFIG_RULES)
+        device_client.AddDevice(Device(**DEVICE_TAPI_WITH_EXTRA_RULES))
+    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+    msg_head = 'device.device_config.config_rules(['
+    msg_tail = ']) is invalid; RPC method AddDevice only accepts connection Config Rules that should start '\
+               'with "_connect/" tag. Others should be configured after adding the device.'
+    except_msg = str(e.value.details())
+    assert except_msg.startswith(msg_head) and except_msg.endswith(msg_tail)
+
+
+def test_device_tapi_add_correct(
+    device_client: DeviceClient,        # pylint: disable=redefined-outer-name
+    device_service: DeviceService):     # pylint: disable=redefined-outer-name
+
+    if not ENABLE_TAPI: return # if there is no device to test against, asusme test is silently passed.
+
+    DEVICE_TAPI_WITH_CONNECT_RULES = copy.deepcopy(DEVICE_TAPI)
+    DEVICE_TAPI_WITH_CONNECT_RULES['device_config']['config_rules'].extend(DEVICE_TAPI_CONNECT_RULES)
+    device_client.AddDevice(Device(**DEVICE_TAPI_WITH_CONNECT_RULES))
+    driver: _Driver = device_service.driver_instance_cache.get(DEVICE_TAPI_UUID)
+    assert driver is not None
+
+
+def test_device_tapi_get(
+    context_client: ContextClient,      # pylint: disable=redefined-outer-name
+    device_client: DeviceClient):       # pylint: disable=redefined-outer-name
+
+    if not ENABLE_TAPI: return # if there is no device to test against, asusme test is silently passed.
+
+    initial_config = device_client.GetInitialConfig(DeviceId(**DEVICE_TAPI_ID))
+    LOGGER.info('initial_config = {:s}'.format(grpc_message_to_json_string(initial_config)))
+
+    device_data = context_client.GetDevice(DeviceId(**DEVICE_TAPI_ID))
+    LOGGER.info('device_data = {:s}'.format(grpc_message_to_json_string(device_data)))
+
+
+def test_device_tapi_configure(
+    context_client: ContextClient,      # pylint: disable=redefined-outer-name
+    device_client: DeviceClient,        # pylint: disable=redefined-outer-name
+    device_service: DeviceService):     # pylint: disable=redefined-outer-name
+
+    if not ENABLE_TAPI: return # if there is no device to test against, asusme test is silently passed.
+
+    driver : _Driver = device_service.driver_instance_cache.get(DEVICE_TAPI_UUID)
+    assert driver is not None
+
+    # Requires to retrieve data from device; might be slow. Uncomment only when needed and test does not pass directly.
+    #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    #LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
+
+    DEVICE_TAPI_WITH_CONFIG_RULES = copy.deepcopy(DEVICE_TAPI)
+    DEVICE_TAPI_WITH_CONFIG_RULES['device_config']['config_rules'].extend(DEVICE_TAPI_CONFIG_RULES)
+    device_client.ConfigureDevice(Device(**DEVICE_TAPI_WITH_CONFIG_RULES))
+
+    # Requires to retrieve data from device; might be slow. Uncomment only when needed and test does not pass directly.
+    #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    #LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
+
+    device_data = context_client.GetDevice(DeviceId(**DEVICE_TAPI_ID))
+    config_rules = [
+        (ConfigActionEnum.Name(config_rule.action), config_rule.resource_key, config_rule.resource_value)
+        for config_rule in device_data.device_config.config_rules
+    ]
+    LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format(
+        '\n'.join(['{:s} {:s} = {:s}'.format(*config_rule) for config_rule in config_rules])))
+    for config_rule in DEVICE_TAPI_CONFIG_RULES:
+        config_rule = (
+            ConfigActionEnum.Name(config_rule['action']), config_rule['resource_key'], config_rule['resource_value'])
+        assert config_rule in config_rules
+
+
+def test_device_tapi_deconfigure(
+    context_client: ContextClient,      # pylint: disable=redefined-outer-name
+    device_client: DeviceClient,        # pylint: disable=redefined-outer-name
+    device_service: DeviceService):     # pylint: disable=redefined-outer-name
+
+    if not ENABLE_TAPI: return # if there is no device to test against, asusme test is silently passed.
+
+    driver: _Driver = device_service.driver_instance_cache.get(DEVICE_TAPI_UUID)
+    assert driver is not None
+
+    # Requires to retrieve data from device; might be slow. Uncomment only when needed and test does not pass directly.
+    #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    #LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
+
+    DEVICE_TAPI_WITH_DECONFIG_RULES = copy.deepcopy(DEVICE_TAPI)
+    DEVICE_TAPI_WITH_DECONFIG_RULES['device_config']['config_rules'].extend(DEVICE_TAPI_DECONFIG_RULES)
+    device_client.ConfigureDevice(Device(**DEVICE_TAPI_WITH_DECONFIG_RULES))
+
+    # Requires to retrieve data from device; might be slow. Uncomment only when needed and test does not pass directly.
+    #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    #LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
+
+    device_data = context_client.GetDevice(DeviceId(**DEVICE_TAPI_ID))
+    config_rules = [
+        (ConfigActionEnum.Name(config_rule.action), config_rule.resource_key, config_rule.resource_value)
+        for config_rule in device_data.device_config.config_rules
+    ]
+    LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format(
+        '\n'.join(['{:s} {:s} = {:s}'.format(*config_rule) for config_rule in config_rules])))
+    for config_rule in DEVICE_TAPI_DECONFIG_RULES:
+        action_set = ConfigActionEnum.Name(ConfigActionEnum.CONFIGACTION_SET)
+        config_rule = (action_set, config_rule['resource_key'], config_rule['resource_value'])
+        assert config_rule not in config_rules
+
+
+def test_device_tapi_delete(
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    if not ENABLE_TAPI: return # if there is no device to test against, asusme test is silently passed.
+
+    device_client.DeleteDevice(DeviceId(**DEVICE_TAPI_ID))
+    driver : _Driver = device_service.driver_instance_cache.get(DEVICE_TAPI_UUID, {})
+    assert driver is None