diff --git a/gso/__init__.py b/gso/__init__.py
index 464bffa920d1ab17883cdb90bfe1a4d31f0c83a9..072559de81c3b3a25900bbff4fc9c905f95adcc9 100644
--- a/gso/__init__.py
+++ b/gso/__init__.py
@@ -1,7 +1,10 @@
 from typer import Typer
 
+from gso.cli import netbox
+
 
 def load_gso_cli(app: Typer) -> None:
     from gso.cli import import_sites
 
     app.add_typer(import_sites.app, name="import_sites")
+    app.add_typer(netbox.app, name="netbox-cli")
diff --git a/gso/cli/netbox.py b/gso/cli/netbox.py
new file mode 100644
index 0000000000000000000000000000000000000000..00f8f399287412b8cf13964d875e51089bcb9630
--- /dev/null
+++ b/gso/cli/netbox.py
@@ -0,0 +1,40 @@
+import typer
+from pynetbox import RequestError
+
+from gso.services.netbox_client import NetBoxClient, create_device_role, create_device_site
+
+app: typer.Typer = typer.Typer()
+
+
+@app.command()
+def netbox_initial_setup() -> None:
+    """Initial setup of NetBox.
+
+    It includes:
+    - Creating a default site (GEANT)
+    - Creating device roles (Router)
+    """
+    typer.echo("Initial setup of NetBox ...")
+    typer.echo("Connecting to NetBox ...")
+
+    try:
+        nbclient = NetBoxClient().connect()
+    except RequestError as e:
+        typer.echo(f"Error connecting to NetBox: {e}")
+        return
+
+    typer.echo("Creating GEANT site ...")
+    try:
+        create_device_site(nbclient, "GEANT", "geant")
+        typer.echo("Site created successfully.")
+    except RequestError as e:
+        typer.echo(f"Error creating site: {e}")
+
+    typer.echo("Creating Router device role ...")
+    try:
+        create_device_role(nbclient, "router", "router")
+        typer.echo("Device role created successfully.")
+    except RequestError as e:
+        typer.echo(f"Error creating device role: {e}")
+
+    typer.echo("NetBox initial setup completed successfully.")
diff --git a/gso/services/netbox_client.py b/gso/services/netbox_client.py
index 974bb7ba9d51578178e3979714c4da3ec0c33f62..eb69515c6d593f4071b4fd0f8ea04b5f5066f581 100644
--- a/gso/services/netbox_client.py
+++ b/gso/services/netbox_client.py
@@ -1,266 +1,338 @@
-# mypy: ignore-errors
-"""
-This module contains all methods
-to communicate with the
-NetBox API endpoint: Data Center Infrastructure Main (dcim)
-"""
-import pynetbox
-import pydantic
-
-
-# Define device models
-class Manufacturer(pydantic.BaseModel):
-    """
-    The device manufacturer.
-    Is mandatory to create a device in netbox.
-    Is needed to define the device type.
-    """
-    name: str
-    slug: str
-
-
-class DeviceType(pydantic.BaseModel):
-    """
-    The device type for a device.
-    Is mandatory to create a device.
-    The manufacturer should be created first to get the manufacturer id,
-    which is defined here as int.
-    """
-    manufacturer: int
-    model: str
-    slug: str
-
-
-class DeviceRole(pydantic.BaseModel):
-    """
-    The role of a device in netbox.
-    Is mandatory to create a device.
-    """
-    name: str
-    slug: str
-
-
-class Site(pydantic.BaseModel):
-    """
-    The site where to place the device.
-    Is mandatory to create a device.
-    """
-    name: str
-    slug: str
-
-
-# An exception for not found search
-class NotFoundError(Exception):
-    """Exception raised for not found search."""
-    pass
-
-
-# An exception on a workflow error
-class WorkflowStateException(Exception):
-    """Exception raised on problems during workflow."""
-    pass
-
-
-def connect(api, token):
-    """
-    Creates a netbox client to communicate
-    with the NetBox endpoints
-    The responses of the client are returned mostly as Records or RecordSet.
-    For more details see the dcim.py file in the
-    pynetbox package.
-
-    To create the client a main URL to NetBox is required. Something like:
-    api = 'http://127.0.0.1:8001'
-
-    To create a token, login to the NetBox web frontend or
-    post request directly a token from the NetBox API:
-    http://127.0.0.1:8001/api/users/tokens/provision/
-    """
-    return pynetbox.api(api, token=token)
-
-
-def get_all_devices(nbclient):
-    return list(nbclient.dcim.devices.all())
-
-
-# We need sometimes a specific device
-# for creating devices
-def get_device_by_name(nbclient, device_name):
-    device = nbclient.dcim.devices.get(name=device_name)
-
-    if device is None:
-        raise NotFoundError(f"Device: {device_name} not found")
-    else:
-        return device
-
-
-# get all interfaces for a device
-def get_interfaces_by_device(nbclient, device_name: str, speed: str):
-    device = get_device_by_name(nbclient, device_name)
-
-    return list(nbclient.dcim.interfaces.filter(device_id=device.id,
-                                                enabled=False,
-                                                mark_connected=False,
-                                                speed=speed
-                                                ))
-
-
-# Create a interface
-def create_interface(nbclient,
-                     iface_name: str,
-                     type: str,
-                     speed: str,
-                     device_name: str) -> dict:
-    """
-    Creates a new interface on
-    a device, where device is defined by name.
-    The type parameter can be 1000base-t, 10gbase-t, lag...
-    For more details on type definidtion have  a look in
-    choises.py in the netbox API implementation in module dcim.
-    Returns the new interface object as dict.
-    """
-    device = get_device_by_name(nbclient, device_name)
-
-    new_iface = nbclient.dcim.interfaces.create(name=iface_name,
-                                                type=type,
-                                                speed=speed,
-                                                enabled=False,
-                                                mark_connected=False,
-                                                device=device.id)
-
-    return dict(new_iface)
-
-
-def create_device_type(nbclient, manufacturer: str,
-                       model: str,
-                       slug: str) -> dict:
-
-    # First get manufacturer id
-    manufacturer_id = int(nbclient.dcim.manufacturers.get(name=manufacturer).id)
-
-    device_type = DeviceType(**{'manufacturer': manufacturer_id, 'model': model, 'slug': slug})
-
-    # Convert the format from DeviceType to dict
-    device_type = dict(device_type)
-
-    # Create device type
-    device_type = nbclient.dcim.device_types.create(device_type)
-    return dict(device_type)
-
-
-def create_device_role(nbclient, name: str, slug: str) -> dict:
-    device_role = DeviceRole(**{'name': name, 'slug': slug})
-    device_role = dict(device_role)
-    device_role = nbclient.dcim.device_roles.create(device_role)
-    return dict(device_role)
-
-
-def create_device_site(nbclient, name: str, slug: str) -> dict:
-    device_site = Site(**{'name': name, 'slug': slug})
-    device_site = dict(device_site)
-    device_site = nbclient.dcim.sites.create(device_site)
-    return dict(device_site)
-
-
-def create_device_manufacturer(nbclient, name: str, slug: str) -> dict:
-    device_manufacturer = Manufacturer(**{'name': name, 'slug': slug})
-    device_manufacturer = dict(device_manufacturer)
-    device_manufacturer = nbclient.dcim.manufacturers.create(device_manufacturer)
-    return dict(device_manufacturer)
-
-
-def create_device(nbclient,
-                  fqdn: str,
-                  model: str,
-                  device_role: str,
-                  site: str) -> dict:
-    """ Creates a device and
-    returns the new device as a dict
-    """
-
-    # Get device type id
-    device_type = nbclient.dcim.device_types.get(model=model)
-
-    # Get device role id
-    device_role = nbclient.dcim.device_roles.get(name=device_role)
-
-    # Get site id
-    device_site = nbclient.dcim.sites.get(name=site)
-
-    # Create new device
-    new_device = nbclient.dcim.devices.create(name=fqdn,
-                                              device_type=device_type.id,
-                                              role=device_role.id,
-                                              site=device_site.id)
-
-    return dict(new_device)
-
-
-def attach_interface_to_lag(nbclient, device_name: str, lag_name: str, iface_name: str) -> dict:
-    """
-    Assign a given interface to a lag.
-    Returns the lag object with the assignend interfaces
-    """
-    # Get device id
-    device = get_device_by_name(nbclient, device_name)
-
-    # Now get interface for device
-    iface = nbclient.dcim.interfaces.get(name=iface_name, device_id=device.id)
-
-    # Get lag
-    lag = nbclient.dcim.interfaces.get(name=lag_name, device_id=device.id)
-
-    # Assign interface to lag
-    iface.lag = lag.id
-
-    # Update interface
-    updated_iface = nbclient.dcim.interfaces.update(iface)
-
-    return dict(updated_iface)
-
-
-def reserve_interface(nbclient, device_name: str, iface_name: str) -> dict:
-    # First get interface from device
-    device = get_device_by_name(nbclient, device_name)
-    interface = nbclient.dcim.interfaces.get(device_id=device.id,
-                                             name=iface_name)
-
-    # Reserve interface by enabling it
-    if interface is None:
-        raise NotFoundError(f"Interface: {iface_name} on device: {device_name} not found.")
-
-    # Check if interface is reserved
-    if interface.enabled:
-        raise WorkflowStateException(f"The interface: {iface_name} on device: {device_name} is already reserved.")
-
-    # Reserve interface by enabling it
-    interface.enabled = True
-    interface.save()
-
-    return dict(interface)
-
-
-def allocate_interface(nbclient, device_name: str, iface_name: str) -> dict:
-    # First get interface from device
-    device = get_device_by_name(nbclient, device_name)
-    interface = nbclient.dcim.interfaces.get(device_id=device.id,
-                                             name=iface_name)
-
-    # allocate interface by marking it as connected
-    # Check if interface is available
-    if interface is None:
-        raise NotFoundError(f"Interface: {iface_name} on device: {device_name} not found.")
-
-    # Check if interface is reserved
-    if interface.mark_connected:
-        raise WorkflowStateException(f"The interface: {iface_name} on device: {device_name} is already allocated.")
-
-    # allocate interface by mark as connected
-    interface.mark_connected = True
-    interface.save()
-
-    return dict(interface)
-
-
-if __name__ == "__main__":
-    print(dict(create_device_manufacturer("Juniper", "juniper")))
+"""
+This module contains all methods
+to communicate with the
+NetBox API endpoint: Data Center Infrastructure Main (dcim)
+"""
+from typing import Optional
+from uuid import UUID
+
+import pynetbox
+import pydantic
+from pydantic import BaseModel
+
+from gso.products import Router
+
+
+# Define device models
+class Manufacturer(pydantic.BaseModel):
+    """
+    The device manufacturer.
+    Is mandatory to create a device in netbox.
+    Is needed to define the device type.
+    """
+
+    name: str
+    slug: str
+
+
+class DeviceType(pydantic.BaseModel):
+    """
+    The device type for a device.
+    Is mandatory to create a device.
+    The manufacturer should be created first to get the manufacturer id,
+    which is defined here as int.
+    """
+
+    manufacturer: int
+    model: str
+    slug: str
+
+
+class DeviceRole(pydantic.BaseModel):
+    """
+    The role of a device in netbox.
+    Is mandatory to create a device.
+    """
+
+    name: str
+    slug: str
+
+
+class Site(pydantic.BaseModel):
+    """
+    The site where to place the device.
+    Is mandatory to create a device.
+    """
+
+    name: str
+    slug: str
+
+
+class ModuleInfo(BaseModel):
+    device_type: str
+    module_bays_slots: list[int]
+    module_type: str
+    breakout_interfaces_per_slot: list[int]
+    total_10g_interfaces: int
+
+
+class TierInfo:
+    def __init__(self):
+        self.Tier1 = ModuleInfo(
+            device_type="7750-SR7s",
+            module_bays_slots=[1, 2],
+            module_type="XCM2s-XMA2s-36p-800g",
+            breakout_interfaces_per_slot=[36, 35, 34, 33],
+            total_10g_interfaces=80,
+        )
+        self.Tier2 = ModuleInfo(
+            device_type="7750-SR7s",
+            module_bays_slots=[1, 2],
+            module_type="XCM2s-XMA2s-36p-400g",
+            breakout_interfaces_per_slot=[36, 35, 34, 33],
+            total_10g_interfaces=60,
+        )
+
+    def get_module_by_name(self, name: str) -> Optional[ModuleInfo]:
+        if name == "Tier1":
+            return self.Tier1
+        elif name == "Tier2":
+            return self.Tier2
+        else:
+            return None
+
+
+FEASIBLE_LAG_RANGE = range(1, 11)
+
+
+# An exception for not found search
+class NotFoundError(Exception):
+    """Exception raised for not found search."""
+    pass
+
+
+# An exception on a workflow error
+class WorkflowStateException(Exception):
+    """Exception raised on problems during workflow."""
+    pass
+
+
+class NetBoxClient:
+    token = "6762782659eba4eb2a490716093dba9f2fc31b36"
+    api = "http://localhost:8000/"
+
+    def connect(self):
+        """
+        Creates a netbox client to communicate
+        with the NetBox endpoints
+        The responses of the client are returned mostly as Records or RecordSet.
+        For more details see the dcim.py file in the
+        pynetbox package.
+
+        To create the client a main URL to NetBox is required. Something like:
+        api = 'http://127.0.0.1:8001'
+
+        To create a token, login to the NetBox web frontend or
+        post request directly a token from the NetBox API:
+        http://127.0.0.1:8001/api/users/tokens/provision/
+        """
+
+        return pynetbox.api(self.api, self.token)
+
+
+def get_all_devices(nbclient):
+    return list(nbclient.dcim.devices.all())
+
+
+def get_device_by_name(nbclient, device_name: str) -> dict | None:
+    """ Returns the device object by name from netbox, or None if not found."""
+    return nbclient.dcim.devices.get(name=device_name)
+
+
+# get all interfaces for a device
+def get_interfaces_by_device(nbclient, device_name: str, speed: str):
+    device = get_device_by_name(nbclient, device_name)
+
+    return list(nbclient.dcim.interfaces.filter(device_id=device.id,
+                                                enabled=False,
+                                                mark_connected=False,
+                                                speed=speed
+                                                ))
+
+
+# Create a interface
+def create_interface(nbclient,
+                     iface_name: str,
+                     type: str,
+                     speed: str,
+                     device_name: str) -> dict:
+    """
+    Creates a new interface on
+    a device, where device is defined by name.
+    The type parameter can be 1000base-t, 10gbase-t, lag...
+    For more details on type definidtion have  a look in
+    choises.py in the netbox API implementation in module dcim.
+    Returns the new interface object as dict.
+    """
+    device = get_device_by_name(nbclient, device_name)
+
+    new_iface = nbclient.dcim.interfaces.create(name=iface_name,
+                                                type=type,
+                                                speed=speed,
+                                                enabled=False,
+                                                mark_connected=False,
+                                                device=device.id)
+
+    return dict(new_iface)
+
+
+def create_device_type(nbclient, manufacturer: str, model: str, slug: str) -> dict:
+    # First get manufacturer id
+    manufacturer_id = int(nbclient.dcim.manufacturers.get(name=manufacturer).id)
+
+    device_type = DeviceType(**{"manufacturer": manufacturer_id, "model": model, "slug": slug})
+
+    # Convert the format from DeviceType to dict
+    device_type = dict(device_type)
+
+    # Create device type
+    device_type = nbclient.dcim.device_types.create(device_type)
+    return dict(device_type)
+
+
+def create_device_role(nbclient, name: str, slug: str) -> dict:
+    device_role = DeviceRole(**{"name": name, "slug": slug})
+    device_role = dict(device_role)
+    device_role = nbclient.dcim.device_roles.create(device_role)
+    return dict(device_role)
+
+
+def create_device_site(nbclient, name, slug) -> dict:
+    device_site = Site(**{"name": name, "slug": slug})
+    device_site = nbclient.dcim.sites.create(dict(device_site))
+    return dict(device_site)
+
+
+def create_device_manufacturer(nbclient, name: str, slug: str) -> dict:
+    device_manufacturer = Manufacturer(**{"name": name, "slug": slug})
+    device_manufacturer = dict(device_manufacturer)
+    device_manufacturer = nbclient.dcim.manufacturers.create(device_manufacturer)
+    return dict(device_manufacturer)
+
+
+def create_device(router_name: str, site_tier: str) -> dict:
+    # fqdn: str, model: str, device_role: str, site: str
+    nbclient = NetBoxClient().connect()
+
+    # Get device type id
+    tier_info = TierInfo().get_module_by_name(f"Tier{site_tier}")
+    device_type = nbclient.dcim.device_types.get(model=tier_info.device_type)
+
+    # Get device role id
+    device_role = nbclient.dcim.device_roles.get(name="router")
+
+    # Get site id
+    device_site = nbclient.dcim.sites.get(name="Amsterdam")
+
+    # Create new device
+    device = nbclient.dcim.devices.create(
+        name=router_name, device_type=device_type.id, role=device_role.id, site=device_site.id
+    )
+    module_bays = list(nbclient.dcim.module_bays.filter(device_id=device.id))
+    card_type = nbclient.dcim.module_types.get(model=tier_info.module_type)
+    for module_bay in module_bays:
+        nbclient.dcim.modules.create(
+            device=device.id,
+            module_bay=module_bay.id,
+            module_type=card_type.id,
+            status="active",
+            comments="Installed via pynetbox",
+        )
+
+    return dict(device)
+
+
+def delete_device(router_name: str):
+    nbclient = NetBoxClient().connect()
+    nbclient.dcim.devices.get(name=router_name).delete()
+    return
+
+
+def attach_interface_to_lag(nbclient, device_name: str, lag_name: str, iface_name: str) -> dict:
+    """
+    Assign a given interface to a lag.
+    Returns the lag object with the assignend interfaces
+    """
+    # Get device id
+    device = get_device_by_name(nbclient, device_name)
+
+    # Now get interface for device
+    iface = nbclient.dcim.interfaces.get(name=iface_name, device_id=device.id)
+
+    # Get lag
+    lag = nbclient.dcim.interfaces.get(name=lag_name, device_id=device.id)
+
+    # Assign interface to lag
+    iface.lag = lag.id
+
+    # Update interface
+    updated_iface = nbclient.dcim.interfaces.update(iface)
+
+    return dict(updated_iface)
+
+
+def reserve_interface(nbclient, device_name: str, iface_name: str) -> dict:
+    # First get interface from device
+    device = get_device_by_name(nbclient, device_name)
+    interface = nbclient.dcim.interfaces.get(device_id=device.id,
+                                             name=iface_name)
+
+    # Reserve interface by enabling it
+    if interface is None:
+        raise NotFoundError(f"Interface: {iface_name} on device: {device_name} not found.")
+
+    # Check if interface is reserved
+    if interface.enabled:
+        raise WorkflowStateException(f"The interface: {iface_name} on device: {device_name} is already reserved.")
+
+    # Reserve interface by enabling it
+    interface.enabled = True
+    interface.save()
+
+    return dict(interface)
+
+
+def allocate_interface(nbclient, device_name: str, iface_name: str) -> dict:
+    # First get interface from device
+    device = get_device_by_name(nbclient, device_name)
+    interface = nbclient.dcim.interfaces.get(device_id=device.id,
+                                             name=iface_name)
+
+    # allocate interface by marking it as connected
+    # Check if interface is available
+    if interface is None:
+        raise NotFoundError(f"Interface: {iface_name} on device: {device_name} not found.")
+
+    # Check if interface is reserved
+    if interface.mark_connected:
+        raise WorkflowStateException(f"The interface: {iface_name} on device: {device_name} is already allocated.")
+
+    # allocate interface by mark as connected
+    interface.mark_connected = True
+    interface.save()
+
+    return dict(interface)
+
+
+def get_available_lags(router_id: UUID) -> list[str]:
+    """Returns all available lags not assigned to a device."""
+
+    nbclient = NetBoxClient().connect()
+    router_name = Router.from_subscription(router_id).router.router_fqdn
+    device = get_device_by_name(nbclient, router_name)
+
+    # Get the existing lag interfaces for the device
+    lag_interface_names = [
+        interface["name"] for interface in nbclient.dcim.interfaces.filter(device_name=device.id, type="lag")
+    ]
+
+    # Generate all feasible lags
+    all_feasible_lags = [f"LAG-{i}" for i in FEASIBLE_LAG_RANGE]
+
+    # Find available lags not assigned to the device
+    available_lags = [lag for lag in all_feasible_lags if lag not in lag_interface_names]
+    return available_lags
+
+
+if __name__ == "__main__":
+    print(dict(create_device_manufacturer("Juniper", "juniper")))
diff --git a/gso/workflows/router/create_router.py b/gso/workflows/router/create_router.py
index be23b4159398d38f8255fdd0584a66add973717e..ba48e89e090e74949e0b246f3e68efb90f36a56d 100644
--- a/gso/workflows/router/create_router.py
+++ b/gso/workflows/router/create_router.py
@@ -15,7 +15,7 @@ from gso.products.product_blocks.router import RouterRole, RouterVendor, generat
 from gso.products.product_types.router import RouterInactive, RouterProvisioning
 from gso.products.product_types.site import Site
 from gso.products.shared import PortNumber
-from gso.services import infoblox, provisioning_proxy, subscriptions
+from gso.services import infoblox, provisioning_proxy, subscriptions, netbox_client
 from gso.services.provisioning_proxy import pp_interaction
 from gso.workflows.utils import customer_selector, iso_from_ipv4
 
@@ -145,12 +145,21 @@ def provision_router_dry(subscription: RouterProvisioning, process_id: UUIDstr,
 def provision_router_real(subscription: RouterProvisioning, process_id: UUIDstr, tt_number: str) -> State:
     provisioning_proxy.provision_router(subscription, process_id, tt_number, False)
 
-    return {
+    return ({
         "subscription": subscription,
         "label_text": (
             "Deployment of base config for a new router. Deployment is being taken care of by the"
             " provisioning proxy, please wait for the results to come back before continuing."
         ),
+    })
+
+
+@step("Create NetBox Device")
+def create_netbox_device(subscription: RouterProvisioning) -> State:
+    netbox_client.create_device(subscription.router.router_fqdn, subscription.router.router_site.site_tier)
+
+    return {
+        "subscription": subscription
     }
 
 
@@ -211,6 +220,7 @@ def create_router() -> StepList:
         >> pp_interaction(provision_router_real, 3)
         >> verify_ipam_loopback
         >> should_allocate_ias(verify_ipam_ias)
+        >> create_netbox_device
         >> set_status(SubscriptionLifecycle.ACTIVE)
         >> resync
         >> done
diff --git a/gso/workflows/router/terminate_router.py b/gso/workflows/router/terminate_router.py
index 413e84b901994da275bad375433fbf5024cbe956..a564e48876ca06fedf90beeb6c4bbee875614fd7 100644
--- a/gso/workflows/router/terminate_router.py
+++ b/gso/workflows/router/terminate_router.py
@@ -11,6 +11,7 @@ from orchestrator.workflows.utils import wrap_modify_initial_input_form
 
 from gso.products.product_types.router import Router
 from gso.services import infoblox
+from gso.services import netbox_client
 
 logger = logging.getLogger(__name__)
 
@@ -58,6 +59,12 @@ def remove_config_from_router() -> None:
     pass
 
 
+@step("Remove Device from NetBox")
+def remove_device_from_netbox(subscription: Router) -> dict[str, Router]:
+    netbox_client.delete_device(subscription.router.router_fqdn)
+    return {"subscription": subscription}
+
+
 @workflow(
     "Terminate router",
     initial_input_form=wrap_modify_initial_input_form(initial_input_form_generator),
@@ -78,6 +85,7 @@ def terminate_router() -> StepList:
         >> unsync
         >> run_ipam_steps(ipam_steps)
         >> run_config_steps(remove_config_from_router)
+        >> remove_device_from_netbox
         >> set_status(SubscriptionLifecycle.TERMINATED)
         >> resync
         >> done