diff --git a/inventory_provider/__init__.py b/inventory_provider/__init__.py
index 3155d6cce97b98ca09e7942da6806f23292a2181..fb6aa000e7510036de79c6f532c68192a4f62a1f 100644
--- a/inventory_provider/__init__.py
+++ b/inventory_provider/__init__.py
@@ -93,6 +93,9 @@ def create_app(setup_logging=True):
     from inventory_provider.routes import state_checker
     app.register_blueprint(state_checker.routes, url_prefix='/state-checker')
 
+    from inventory_provider.routes import map
+    app.register_blueprint(map.routes, url_prefix='/map')
+
     if app.config.get('ENABLE_TESTING_ROUTES', False):
         from inventory_provider.routes import testing
         app.register_blueprint(testing.routes, url_prefix='/testing')
diff --git a/inventory_provider/routes/__init__.py b/inventory_provider/routes/__init__.py
index 4cd55dfe6fb4089cb72a0b3ebed1c07d0c7eddb3..bbf6f098e71c4a5e4e62f9f4857e2e9709c06214 100644
--- a/inventory_provider/routes/__init__.py
+++ b/inventory_provider/routes/__init__.py
@@ -36,4 +36,5 @@ and www.json.org for more details.
 
 .. automodule:: inventory_provider.routes.neteng
 
+.. automodule:: inventory_provider.routes.map
 """
diff --git a/inventory_provider/routes/map.py b/inventory_provider/routes/map.py
new file mode 100644
index 0000000000000000000000000000000000000000..f75a65cac16ef5cd3b6e6fef4f5ba0dd8c37c218
--- /dev/null
+++ b/inventory_provider/routes/map.py
@@ -0,0 +1,135 @@
+"""
+mapping support endpoints
+=========================
+
+These endpoints are intended for use by the mapping-provider
+
+.. contents:: :local:
+
+/map/sites
+---------------------------------
+
+.. autofunction:: inventory_provider.routes.map.sites
+
+
+/map/routers
+---------------------------------
+
+.. autofunction:: inventory_provider.routes.map.routers
+
+
+/map/services/<service-type>
+---------------------------------
+
+.. autofunction:: inventory_provider.routes.map.services
+
+"""
+import json
+import logging
+
+from flask import Blueprint, Response, current_app, request, jsonify
+
+from inventory_provider.routes import common
+from inventory_provider.routes.classifier import get_ims_equipment_name, \
+    get_ims_interface
+from inventory_provider.routes import msr
+
+logger = logging.getLogger(__name__)
+routes = Blueprint('map-support-routes', __name__)
+
+
+SERVICE_LIST_SCHEMA = {
+    '$schema': 'https://json-schema.org/draft/2020-12/schema',
+
+    'definitions': {
+        'endpoint': {
+            'type': 'object',
+            'properties': {
+                'hostname': {'type': 'string'},
+                'interface': {'type': 'string'},
+            },
+        },
+        'service': {
+            'type': 'object',
+            'properties': {
+                'sid': {'type': 'string'},
+                'name': {'type': 'string'},
+                'type': {'type': 'string'},
+                'endpoints': {
+                    'type': 'array',
+                    'items': {'$ref': '#/definitions/endpoint'},
+                    'minItems': 1,
+                },
+                'overlays': {'type': 'object', 'properties': {
+                    'speed': {'type': 'number'},
+                }},
+            },
+            'required': ['sid', 'name', 'type', 'endpoints', 'overlays'],
+            'additionalProperties': False
+        },
+    },
+
+    'type': 'array',
+    'items': {'$ref': '#/definitions/service'}
+}
+
+
+@routes.route("/services", methods=['GET'])
+@routes.route('/services/<service_type>', methods=['GET'])
+@common.require_accepts_json
+def services(service_type=None):
+    """
+    Handler for `/map/services` and
+    `/map/services/<service_type>`
+    which returns information for either all services
+    or those of a specific service type.
+
+    This endpoint is used by the mapping-provider to get
+    static information about all operationalservices.
+    
+    .. asjson::
+       inventory_provider.routes.map.SERVICE_LIST_SCHEMA
+
+    :param service_type: optional, if present should be a router hostname
+    :return:
+    """
+
+    cache_key_all_services = "classifier-cache:map:services"
+
+    r = common.get_current_redis()
+    all_map_service_info = common._ignore_cache_or_retrieve(request, cache_key_all_services, r)
+    if not all_map_service_info:
+
+        def _operational(s):
+            return s["status"].lower() == "operational"
+
+        def _reformat_service(s):
+            return {
+                "name": s["name"],
+                "endpoints": s["endpoints"],
+                "sid": s["sid"],
+                "type": s["service_type"],
+                "overlays": {
+                    "speed": s["speed"],
+                }
+            }
+
+        msr_services = filter(_operational, msr.load_all_msr_services())
+        all_map_service_info = map(_reformat_service, msr_services)
+        all_map_service_info = list(all_map_service_info)
+        r.set(cache_key_all_services, json.dumps(all_map_service_info))
+
+    if service_type:
+        result = [s for s in all_map_service_info if s["type"] == service_type]
+    else:
+        result = all_map_service_info
+
+    if not result:
+        message = f'no {service_type} services found' \
+            if service_type else 'no services found'
+        return Response(
+            response=message,
+            status=404,
+            mimetype='text/html')
+
+    return jsonify(result)
diff --git a/inventory_provider/routes/msr.py b/inventory_provider/routes/msr.py
index 9ccdb3409777c363a8d4d39c091b759390c97a59..1650505335e9375901646e7967094d6e90ce038b 100644
--- a/inventory_provider/routes/msr.py
+++ b/inventory_provider/routes/msr.py
@@ -108,7 +108,7 @@ import threading
 from collections import defaultdict
 from typing import Dict
 
-from flask import Blueprint, Response, request, current_app
+from flask import Blueprint, Response, request, current_app, jsonify
 import jsonschema
 
 from inventory_provider.routes import common
@@ -1061,24 +1061,12 @@ def _endpoint_extractor(all_interfaces: Dict, endpoint_details: Dict):
             'port': endpoint_details['port']
         }
 
-
-@routes.route('/services', methods=['GET'])
-@common.require_accepts_json
-def get_system_correlation_services():
+def load_all_msr_services():
     """
-    Handler for `/msr/services`
+    utility method used to construct the response for /msr/services,
+    as well as other endpoints that construct similar responses
 
-    This method returns all known services with with information required
-    by the reporting tool stack.
-
-    cf. https://jira.software.geant.org/browse/POL1-530
-
-    The response will be formatted as follows:
-
-    .. asjson::
-       inventory_provider.routes.msr.SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA
-
-    :return:
+    :return: List of all reportable services
     """
 
     def _get_redundancy_asn(endpoints):
@@ -1099,14 +1087,14 @@ def get_system_correlation_services():
     cache_key = 'classifier-cache:msr:services'
 
     r = common.get_current_redis()
-    response = _ignore_cache_or_retrieve(request, cache_key, r)
-    if not response:
+    all_msr_services = _ignore_cache_or_retrieve(request, cache_key, r)
+    if not all_msr_services:
 
         all_interfaces = _load_all_interfaces()
 
         sid_services = json.loads(r.get('ims:sid_services').decode('utf-8'))
 
-        response = []
+        all_msr_services = []
         for sid, details in sid_services.items():
             service_info = {'endpoints': []}
             for d in details:
@@ -1128,14 +1116,38 @@ def get_system_correlation_services():
                 asn = _get_redundancy_asn(service_info['endpoints'])
                 if asn:
                     service_info['redundant_asn'] = asn
-                response.append(service_info)
+                all_msr_services.append(service_info)
 
+        # sanity
         jsonschema.validate(
-            response, SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA)
+            all_msr_services, SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA)
 
-        if response:
-            response = json.dumps(response, indent=2)
-            # r.set(cache_key, response.encode('utf-8'))
+        if all_msr_services:
+            # expected to always be non-empty
+            r.set(cache_key, json.dumps(all_msr_services).encode('utf-8'))
+
+    return all_msr_services
+
+@routes.route('/services', methods=['GET'])
+@common.require_accepts_json
+def get_system_correlation_services():
+    """
+    Handler for `/msr/services`
+
+    This method returns all known services with with information required
+    by the reporting tool stack.
+
+    cf. https://jira.software.geant.org/browse/POL1-530
+
+    The response will be formatted as follows:
+
+    .. asjson::
+       inventory_provider.routes.msr.SYSTEM_CORRELATION_SERVICES_LIST_SCHEMA
+
+    :return:
+    """
+
+    response = load_all_msr_services()
 
     if not response:
         return Response(
@@ -1143,7 +1155,7 @@ def get_system_correlation_services():
             status=404,
             mimetype="text/html")
 
-    return Response(response, mimetype="application/json")
+    return jsonify(response)
 
 
 @routes.route('/bgp', methods=['GET'])
diff --git a/test/test_map_routes.py b/test/test_map_routes.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b6943f59cdb5b9338e0dfa63de610035aaaa763
--- /dev/null
+++ b/test/test_map_routes.py
@@ -0,0 +1,20 @@
+import ipaddress
+import json
+import jsonschema
+
+import pytest
+
+from inventory_provider.routes.map import SERVICE_LIST_SCHEMA
+
+DEFAULT_REQUEST_HEADERS = {'Accept': ['application/json']}
+
+
+def test_get_all_services(client):
+    rv = client.get(
+        '/map/services',
+        headers=DEFAULT_REQUEST_HEADERS)
+    assert rv.status_code == 200
+    assert rv.is_json
+    response_data = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(response_data, SERVICE_LIST_SCHEMA)
+    assert response_data  # test data is non-empty