diff --git a/inventory_provider/routes/testing.py b/inventory_provider/routes/testing.py
index 2f573f9a57dce667a9849c7351a40a59aa9fc33a..1ceefe00987d11bd4459a2df2fc556631b7d5a4b 100644
--- a/inventory_provider/routes/testing.py
+++ b/inventory_provider/routes/testing.py
@@ -20,6 +20,13 @@ def flushdb():
 
 # IMS routes
 
+
+@routes.route("update-interfaces-to-services", methods=['GET', 'POST'])
+def update_interfaces_to_services_ims():
+    worker.update_interfaces_to_services.delay(use_current=True)
+    return Response('OK')
+
+
 @routes.route("update-fibre-spans", methods=['GET', 'POST'])
 def update_fibre_spans_ims():
     worker.update_fibre_spans.delay(use_current=True)
@@ -33,7 +40,7 @@ def update_interfaces_to_port_id_ims():
 
 
 @routes.route("update-port-ids-to-services", methods=['GET', 'POST'])
-def update_interfaces_to_services_ims():
+def update_port_ids_to_services_ims():
     worker.update_port_ids_to_services.delay(use_current=True)
     return Response('OK')
 
diff --git a/inventory_provider/tasks/worker.py b/inventory_provider/tasks/worker.py
index 8c18412962ed07d373fe1f06778c29afd39cae00..1c6dac4182a5b78a9c2625a5573fb34e9f79fbfa 100644
--- a/inventory_provider/tasks/worker.py
+++ b/inventory_provider/tasks/worker.py
@@ -450,6 +450,7 @@ def internal_refresh_phase_2(self):
 
         subtasks = [
             update_circuit_hierarchy.apply_async(),
+            update_interfaces_to_services.apply_asynch(),
             update_interfaces_to_port_ids.apply_async(),
             update_port_ids_to_services.apply_async(),
             import_unmanaged_interfaces.apply_async()
@@ -533,6 +534,63 @@ def update_interfaces_to_port_ids(self, use_current=False):
     rp.execute()
 
 
+@app.task(
+    base=InventoryTask, bind=True, name='update_interfaces_to_services')
+@log_task_entry_and_exit
+def update_interfaces_to_services(self, use_current=False):
+    port_id_services = defaultdict(list)
+
+    c = InventoryTask.config["ims"]
+    ds = IMS(c['api'], c['username'], c['password'])
+
+    if use_current:
+        r = get_current_redis(InventoryTask.config)
+    else:
+        r = get_next_redis(InventoryTask.config)
+
+    rp = r.pipeline()
+    # scan with bigger batches, to mitigate network latency effects
+    for key in r.scan_iter('ims:port_id_services:*', count=2000):
+        rp.delete(key)
+    rp.execute()
+
+    locations = {k: v for k, v in ims_data.get_node_locations(ds)}
+    for service in ims_data.get_port_id_services(ds):
+        port_id_services[service["port_a_id"]].append(service)
+    rp = r.pipeline()
+
+    def _format_service(s, port, loc):
+        s['pop_name'] = loc['name']
+        s['pop_abbreviation'] = loc['abbreviation']
+        s['equipment'] = ''  # this is redundant I believe
+        s['card_d'] = ''  # this is redundant I believe
+        s['port'] = port  # this is redundant I believe
+        s['logical_unit'] = ''  # this is redundant I believe
+
+        s['other_end_pop_name'] = ''  # redundant
+        s['other_end_pop_abbreviation'] = ''  # redundant
+        s['other_end_equipment'] = ''  # this is redundant I believe
+        s['other_end_card_d'] = ''  # this is redundant I believe
+        s['other_end_port'] = ''  # this is redundant I believe
+        s['other_end_logical_unit'] = ''  # this is redundant I believe
+        s['manufacturer'] = ''  # this is redundant I believe
+        s.pop('port_a_id', None)
+        s.pop('port_b_id', None)
+
+    for port_info in ims_data.get_port_details(ds):
+        location = locations[port_info['equipment_name']]['pop']
+        services = []
+        for service in port_id_services[port_info['port_id']]:
+            _format_service(service, port_info['interface_name'], location)
+            services.append(service)
+
+        rp.set(
+            f'ims:interface_services:{port_info["equipment_name"]}:'
+            f'{port_info["interface_name"]}',
+            json.dumps(services))
+    rp.execute()
+
+
 @app.task(
     base=InventoryTask, bind=True, name='update_port_ids_to_services')
 @log_task_entry_and_exit