diff --git a/mapping_provider/__init__.py b/mapping_provider/__init__.py
index aa309f9cfa78136a8ef621a23d83e13d37b4dffa..2898e51fb985552ec45e3fe3396316b75a9d6e65 100644
--- a/mapping_provider/__init__.py
+++ b/mapping_provider/__init__.py
@@ -1,15 +1,19 @@
-"""Initializes the FastAPI application."""
+"""
+Default entry point for the FastAPI application.
+"""
 
 from fastapi import FastAPI
 
-from mapping_provider.api.common import router as version_router
-
+from mapping_provider.api import common, map
 
 def create_app() -> FastAPI:
-    """Create a FastAPI application."""
+    """
+    Creates the FastAPI application instance, with routers attached.
+    """
     app = FastAPI(
         title="Mapping provider",
         description="Mapping provider endpoints for GÉANT maps",
     )
-    app.include_router(version_router)
+    app.include_router(common.router)
+    app.include_router(map.router, prefix='/map')
     return app
diff --git a/mapping_provider/api/map.py b/mapping_provider/api/map.py
new file mode 100644
index 0000000000000000000000000000000000000000..79c64800776e531733cac1065f151d93cb315837
--- /dev/null
+++ b/mapping_provider/api/map.py
@@ -0,0 +1,210 @@
+from importlib.metadata import version
+
+from fastapi import APIRouter
+import jsonschema
+from pydantic import BaseModel
+import requests
+
+router = APIRouter()
+
+
+class Site(BaseModel):
+    latitude: float
+    longitude: float
+    name: str
+
+    @classmethod
+    def from_inprov_site(cls, site: dict) -> 'Site':
+        return cls(
+            latitude=site['latitude'],
+            longitude=site['longitude'],
+            name=site['name']
+        )
+
+class SiteList(BaseModel):
+    sites: list[Site]
+
+class Router(BaseModel):
+    fqdn: str
+    site: str
+
+    @classmethod
+    def from_inprov_router(cls, router: dict) -> 'Router':
+        return cls(
+            fqdn = router['fqdn'],
+            site = router['site']
+        )
+
+class RouterList(BaseModel):
+    routers: list[Router]
+
+
+class Endpoint(BaseModel):
+    hostname: str
+    interface: str
+
+    @classmethod
+    def from_inprov_endpoint(cls, endpoint: dict) -> 'Endpoint':
+        return cls(
+            hostname = endpoint['hostname'],
+            interface = endpoint['interface'],
+        )
+
+class Overlays(BaseModel):
+    speed: int
+
+    @classmethod
+    def from_inprov_overlays(cls, overlays: dict) -> 'Overlays':
+        return cls(
+            speed = overlays['speed'],
+        )
+
+class Service(BaseModel):
+    sid: str
+    name: str
+    type: str
+    endpoints: list[Endpoint]
+    overlays: Overlays
+
+    @classmethod
+    def from_inprov_service(cls, service: dict) -> 'Service':
+        return cls(
+            sid = service['sid'],
+            name = service['name'],
+            type = service['type'],
+            endpoints = list(map(Endpoint.from_inprov_endpoint, service['endpoints'])),
+            overlays = Overlays.from_inprov_overlays(service['overlays']),
+        )
+
+class ServiceList(BaseModel):
+    services: list[Service]
+
+
+INPROV_SITE_LIST_SCHEMA = {
+    '$schema': 'https://json-schema.org/draft/2020-12/schema',
+
+    'definitions': {
+        'site': {
+            'type': 'object',
+            'properties': {
+                'name': {'type': 'string'},
+                'latitude': {'type': 'number'},
+                'longitude': {'type': 'number'},
+            },
+            'required': ['name', 'latitude', 'longitude'],
+            'additionalProperties': True,
+        },
+    },
+
+    'type': 'array',
+    'items': {'$ref': '#/definitions/site'}
+}
+
+INPROV_ROUTER_LIST_SCHEMA = {
+    '$schema': 'https://json-schema.org/draft/2020-12/schema',
+
+    'definitions': {
+        'router': {
+            'type': 'object',
+            'properties': {
+                'fqdn': {'type': 'string'},
+                'site': {'type': 'string'},
+            },
+            'required': ['fqdn', 'site'],
+        },
+    },
+
+    'type': 'array',
+    'items': {'$ref': '#/definitions/router'}
+}
+
+INPROV_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': ['speed'],
+                },
+            },
+            'required': ['sid', 'name', 'type', 'endpoints', 'overlays'],
+        },
+    },
+
+    'type': 'array',
+    'items': {'$ref': '#/definitions/service'}
+}
+
+@router.get("/sites")
+def get_sites() -> SiteList:
+    """
+    handler for /sites
+    """
+
+    # TODO: catch/handle the usual exceptions
+
+    rv = requests.get(
+        'https://test-inprov01.geant.org/map/sites',
+        headers={'Accept': 'application/json'})
+    rv.raise_for_status()
+    site_list_json = rv.json()
+    jsonschema.validate(site_list_json, INPROV_SITE_LIST_SCHEMA)
+
+    return SiteList(sites=map(Site.from_inprov_site, site_list_json))
+
+
+@router.get("/routers")
+def get_routers() -> RouterList:
+    """
+    handler for /sites
+    """
+
+    # TODO: catch/handle the usual exceptions
+
+    rv = requests.get(
+        'https://test-inprov01.geant.org/map/routers',
+        headers={'Accept': 'application/json'})
+    rv.raise_for_status()
+    router_list_json = rv.json()
+    jsonschema.validate(router_list_json, INPROV_ROUTER_LIST_SCHEMA)
+
+    return RouterList(routers=map(Router.from_inprov_router, router_list_json))
+
+
+@router.get("/trunks")
+def get_trunks() -> ServiceList:
+    """
+    handler for /trunks
+    """
+
+    # TODO: catch/handle the usual exceptions
+
+    rv = requests.get(
+        'https://test-inprov01.geant.org/map/services/IP TRUNK',
+        headers={'Accept': 'application/json'})
+    rv.raise_for_status()
+    service_list_json = rv.json()
+    jsonschema.validate(service_list_json, INPROV_SERVICE_LIST_SCHEMA)
+
+    return ServiceList(services=map(Service.from_inprov_service, service_list_json))
+
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/test/test_map_endpoints.py b/test/test_map_endpoints.py
new file mode 100644
index 0000000000000000000000000000000000000000..b8678717fc098a074303239210b01f474fd0d2f1
--- /dev/null
+++ b/test/test_map_endpoints.py
@@ -0,0 +1,35 @@
+import responses
+
+from mapping_provider.api.map import SiteList, RouterList, ServiceList
+
+
+# @responses.activate
+# def test_inventory_uri_validation():
+#     responses.add(
+#         method=responses.GET, url=re.compile(r".*/version$"), json={"api": "0.9"}
+#     )
+#     assert (
+#         classifier.verify_inventory_provider_uri(None, None, "http://a.b.c:9999")
+#         == "http://a.b.c:9999/"
+#     )
+
+
+def test_get_sites(client):
+    rv = client.get("/map/sites")
+    assert rv.status_code == 200
+    assert rv.json()
+    SiteList.model_validate(rv.json())
+
+
+def test_get_routers(client):
+    rv = client.get("/map/routers")
+    assert rv.status_code == 200
+    assert rv.json()
+    RouterList.model_validate(rv.json())
+
+
+def test_get_trunks(client):
+    rv = client.get("/map/trunks")
+    assert rv.status_code == 200
+    assert rv.json()
+    ServiceList.model_validate(rv.json())