diff --git a/inventory_provider/db/ims.py b/inventory_provider/db/ims.py
index 1f38a0f78dbf9e0e7cc578c1b354f6621ae1471c..b50f3fc09e158a744516fe0bbb94ed24f0aa2d46 100644
--- a/inventory_provider/db/ims.py
+++ b/inventory_provider/db/ims.py
@@ -9,21 +9,24 @@ from enum import Enum
 from requests import HTTPError
 
 CIRCUIT_PROPERTIES = {
+    'Customer': 32,
+    'Product': 128,
     'Ports': 512,
     'InternalPorts': 1024,
+    'CarrierCircuits': 65536,
     'SubCircuits': 131072,
     'PortsFullDetails': 262144,
     'PortA': 34359738368,
     'PortB': 68719476736
 }
-# http://149.210.162.190:81/ImsVersions/4.19.9/html/dbc969d0-e735-132e-6281-f724c6d7da64.htm  # NOQA
+# http://149.210.162.190:81/ImsVersions/4.19.9/html/dbc969d0-e735-132e-6281-f724c6d7da64.htm  # noqa
 CONTACT_PROPERTIES = {
     'SiteRelatedContacts': 8,
     'CustomerRelatedContacts': 16,
     'GroupRelatedContacts': 32,
     'VendorRelatedContacts': 64
 }
-# http://149.210.162.190:81/ImsVersions/4.19.9/html/5a40472e-48ee-c120-0a36-52a85d52127c.htm  # NOQA
+# http://149.210.162.190:81/ImsVersions/4.19.9/html/5a40472e-48ee-c120-0a36-52a85d52127c.htm  # noqa
 CUSTOMER_PROPERTIES = {
     'CustomerRelatedContacts': 32768,
     'CustomerType': 262144
diff --git a/inventory_provider/db/ims_data.py b/inventory_provider/db/ims_data.py
index 2e6a59f7183c9117e506002e22c2d0d176eb3356..f370317f50c1ec0139a31c182e0b14df5fc7d85a 100644
--- a/inventory_provider/db/ims_data.py
+++ b/inventory_provider/db/ims_data.py
@@ -20,6 +20,27 @@ IMS_OPSDB_STATUS_MAP = {
 }
 
 
+def get_circuit_hierarchy(ds):
+    circuit_nav_props = [
+        ims.CIRCUIT_PROPERTIES['Customer'],
+        ims.CIRCUIT_PROPERTIES['Product'],
+        ims.CIRCUIT_PROPERTIES['SubCircuits'],
+        ims.CIRCUIT_PROPERTIES['CarrierCircuits']
+    ]
+    circuits = ds.get_all_entities(
+        'Circuit', circuit_nav_props, step_count=1000)
+    for circuit in circuits:
+        sub_circuits = [c['subcircuitid'] for c in circuit['subcircuits']]
+        carrier_circuits = [c['carriercircuitid'] for c in circuit['carriercircuits']]
+        yield {
+            'id': circuit['id'],
+            'product': circuit['product']['name'],
+            'project': circuit['customer']['name'],
+            'sub-circuits': sub_circuits,
+            'carrier-circuits': carrier_circuits
+        }
+
+
 def get_node_locations(ds):
     site_nav_props = [
         ims.SITE_PROPERTIES['City'],
diff --git a/inventory_provider/routes/testing.py b/inventory_provider/routes/testing.py
index 8919aab211da2a1989dd110d7717f6d27dc9c5ad..35357564a33d3e248cadfc5cadeb0b18db096b0d 100644
--- a/inventory_provider/routes/testing.py
+++ b/inventory_provider/routes/testing.py
@@ -21,6 +21,12 @@ def flushdb():
 
 # IMS routes
 
+@routes.route("update-circuit-hierarchy-ims", methods=['GET', 'POST'])
+def update_circuit_hierarchy_ims():
+    ims_worker.update_circuit_hierarchy_ims.delay(use_current=True)
+    return Response('OK')
+
+
 @routes.route("update-equipment-locations-ims", methods=['GET', 'POST'])
 def update_equipment_locations_ims():
     ims_worker.update_equipment_locations_ims.delay(use_current=True)
diff --git a/inventory_provider/tasks/ims_worker.py b/inventory_provider/tasks/ims_worker.py
index b2f2bec368cdf5858bf0890387293689596cb45c..87ee77be00dd9ebf6f6deb610da89c3968113296 100644
--- a/inventory_provider/tasks/ims_worker.py
+++ b/inventory_provider/tasks/ims_worker.py
@@ -21,6 +21,29 @@ environment.setup_logging()
 logger = logging.getLogger(__name__)
 
 
+@app.task(base=InventoryTask, bind=True, name='update_circuit_hierarchy_ims')
+@log_task_entry_and_exit
+def update_circuit_hierarchy_ims(self, use_current=False):
+
+    if use_current:
+        r = get_current_redis(InventoryTask.config)
+        # scan with bigger batches, to mitigate network latency effects
+    else:
+        r = get_next_redis(InventoryTask.config)
+    rp = r.pipeline()
+    for k in r.scan_iter('ims:circuit_hierarchy:*', count=1000):
+        rp.delete(k)
+    rp.execute()
+
+    c = InventoryTask.config["ims"]
+    ds = IMS(c['api'], c['username'], c['password'])
+
+    rp = r.pipeline()
+    for d in ims_data.get_circuit_hierarchy(ds):
+        rp.set(f'ims:circuit_hierarchy:{d["id"]}', json.dumps([d]))
+    rp.execute()
+
+
 @app.task(base=InventoryTask, bind=True, name='update_equipment_locations_ims')
 @log_task_entry_and_exit
 def update_equipment_locations_ims(self, use_current=False):