diff --git a/gso/api/api_v1/api.py b/gso/api/api_v1/api.py
index e2a2f5b472dd51f6ddc6f7298fb9db76115e5fc5..8166a11f53cad3c020b722974f6c96fc776e6cf1 100644
--- a/gso/api/api_v1/api.py
+++ b/gso/api/api_v1/api.py
@@ -5,9 +5,9 @@ from fastapi.routing import APIRouter
 
 from orchestrator.security import opa_security_default
 
-from gso.api.api_v1.endpoints import import_site
+from gso.api.api_v1.endpoints import imports
 
 api_router = APIRouter()
 api_router.include_router(
-    import_site.router, prefix="/import/site", dependencies=[Depends(opa_security_default)]
+    imports.router, prefix="/imports", dependencies=[Depends(opa_security_default)]
 )
\ No newline at end of file
diff --git a/gso/api/api_v1/endpoints/import_site.py b/gso/api/api_v1/endpoints/import_site.py
deleted file mode 100644
index 340c89b0fe65d2c74c9c5becc1e331bf7dce7c49..0000000000000000000000000000000000000000
--- a/gso/api/api_v1/endpoints/import_site.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from typing import Dict, Any
-
-from fastapi import HTTPException, status
-from fastapi.routing import APIRouter
-from orchestrator.services import processes, subscriptions
-from pydantic import BaseModel
-
-from gso.products.product_blocks.site import SiteTier
-
-router = APIRouter()
-
-
-class SiteImport(BaseModel):
-    site_name: str
-    site_city: str
-    site_country: str
-    site_country_code: str
-    site_latitude: float
-    site_longitude: float
-    site_bgp_community_id: int
-    site_internal_id: int
-    site_tier: SiteTier
-    site_ts_address: str
-
-
-@router.post("/", status_code=status.HTTP_201_CREATED, tags=["Import"])
-def import_site(site: SiteImport) -> Dict[str, Any]:
-    """
-    Import site by running the import_site workflow.
-    response:
-        - pid: The process id of the started process.
-    Raises:
-    HTTPException: If the site already exists or if there's an error in the process.
-    """
-    subscription = subscriptions.retrieve_subscription_by_subscription_instance_value(
-        resource_type="site_name", value=site.site_name, sub_status=("provisioning", "active"))
-    if subscription:
-        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Site already exists.")
-
-    pid = processes.start_process("import_site", [site.dict()])
-    if pid is None:
-        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to start the process.")
-
-    process = processes._get_process(pid)  # pylint: disable=protected-access
-    if process.last_status == "failed":
-        raise HTTPException(
-            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
-            detail=f"Process {pid} failed because of an internal error.")
-
-    return {"pid": str(pid)}
diff --git a/gso/api/api_v1/endpoints/imports.py b/gso/api/api_v1/endpoints/imports.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe510fea828bc8256924b5c5888774d3a30ea0df
--- /dev/null
+++ b/gso/api/api_v1/endpoints/imports.py
@@ -0,0 +1,105 @@
+import ipaddress
+from typing import Dict, Any, Optional
+from uuid import UUID
+
+from fastapi import HTTPException, status
+from fastapi.routing import APIRouter
+from orchestrator.services import processes, subscriptions
+from pydantic import BaseModel
+from sqlalchemy.exc import MultipleResultsFound
+
+from gso.products.product_blocks.router import RouterRole, RouterVendor
+from gso.products.product_blocks.site import SiteTier
+
+router = APIRouter()
+
+
+def start_process(process_name: str, data: dict) -> UUID:
+    """Utility function to start a process and handle common exceptions."""
+
+    pid = processes.start_process(process_name, [data])
+    if pid is None:
+        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to start the process.")
+
+    process = processes._get_process(pid)  # pylint: disable=protected-access
+    if process.last_status == "failed":
+        raise HTTPException(
+            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+            detail=f"Process {pid} failed because of an internal error. {process.failed_reason}",
+        )
+
+    return pid
+
+
+class SiteImport(BaseModel):
+    site_name: str
+    site_city: str
+    site_country: str
+    site_country_code: str
+    site_latitude: float
+    site_longitude: float
+    site_bgp_community_id: int
+    site_internal_id: int
+    site_tier: SiteTier
+    site_ts_address: str
+
+
+@router.post("/sites", status_code=status.HTTP_201_CREATED, tags=["Import"])
+def import_site(site: SiteImport) -> Dict[str, Any]:
+    """
+    Import site by running the import_site workflow.
+    Args:
+        - site: A SiteImport object containing site details.
+
+    Returns:
+        - A dictionary containing the detail message and the process id.
+
+    Raises:
+        - HTTPException: If there's an error in the process or if the site already exists.
+    """
+    try:
+        subscription = subscriptions.retrieve_subscription_by_subscription_instance_value(
+            resource_type="site_name", value=site.site_name, sub_status=("provisioning", "active")
+        )
+        if subscription:
+            raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Site already exists.")
+    except MultipleResultsFound:
+        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Multiple subscriptions found.")
+
+    pid = start_process("import_site", site.dict())
+    return {"detail": "Site import process started.", "pid": pid}
+
+
+class RouterImportModel(BaseModel):
+    customer: str
+    router_site: str
+    hostname: str
+    ts_port: int
+    router_vendor: RouterVendor
+    router_role: RouterRole
+    is_ias_connected: Optional[bool] = None
+    router_access_via_ts: Optional[bool] = None
+    router_lo_ipv4_address: Optional[ipaddress.IPv4Address] = None
+    router_lo_ipv6_address: Optional[ipaddress.IPv6Address] = None
+    router_lo_iso_address: Optional[str] = None
+    router_si_ipv4_network: Optional[ipaddress.IPv4Network] = None
+    router_ias_lt_ipv4_network: Optional[ipaddress.IPv4Network] = None
+    router_ias_lt_ipv6_network: Optional[ipaddress.IPv6Network] = None
+
+
+@router.post("/routers", status_code=status.HTTP_201_CREATED, tags=["Import"])
+def import_router(router_data: RouterImportModel):
+    """
+    Import router by running the import_router workflow.
+    Args:
+        - router_data: A RouterImportModel object containing router details.
+
+    Returns:
+        - A dictionary containing the detail message and the process id.
+
+    Raises:
+        - HTTPException: If there's an error in the process.
+    """
+
+    pid = start_process("import_router", router_data.dict())
+    return {"detail": f"Router added successfully", "pid": pid}
diff --git a/gso/cli/import_sites.py b/gso/cli/import_sites.py
index cf6347220183315e13c8f7c7e1259bad14a7640d..4a4af843d7f1f07b81163a73b9f9be45b376110a 100644
--- a/gso/cli/import_sites.py
+++ b/gso/cli/import_sites.py
@@ -1,47 +1,10 @@
-from typing import Any, Dict, Generator
-
-import requests
 import typer
-from pydantic import ValidationError
-
-from gso.api.api_v1.endpoints.import_site import SiteImport, import_site
-from gso.products.product_blocks.site import SiteTier
 
 app: typer.Typer = typer.Typer()
 
 
-def get_site_details() -> Generator[Dict[str, Any], None, None]:
-    site_list_url = "https://prod-inventory-provider01.geant.org/neteng/pops"
-    site_details_url_template = "https://prod-inventory-provider01.geant.org/neteng/pop/{site}"
-    site_list_response = requests.get(site_list_url)
-    site_list = site_list_response.json()
-
-    for site in site_list:
-        site_details_url = site_details_url_template.format(site=site)
-        site_details_response = requests.get(site_details_url)
-        yield site_details_response.json()
-
-
 @app.command()
-def import_from_inventory_provider():
-    """
-    Import sites into GSO using Inventory Provider API.
-    """
-    for site_details in get_site_details():
-        try:
-            mapped_site_details = {
-                "site_name": site_details["name"],
-                "site_city": site_details["city"],
-                "site_country": site_details["country"],
-                "site_latitude": site_details["latitude"],
-                "site_longitude": site_details["longitude"],
-                "site_internal_id": 0,
-                "site_country_code": "NL",
-                "site_bgp_community_id": 0,
-                "site_tier": SiteTier.tier1
-            }
-            initial_data = SiteImport(**mapped_site_details)
-            import_site(initial_data)
-            typer.echo(f"Successfully imported site: {initial_data.site_name}")
-        except ValidationError as e:
-            typer.echo(f"Validation error: {e}")
+def import_sites():
+    """Import sites from a source."""
+    # TODO: Implement this CLI command to import sites from a source.
+    typer.echo("Importing sites...")
diff --git a/gso/services/crm.py b/gso/services/crm.py
index c5b4f139da9feccdeb8feac3b60e196d170e0605..cdff901f435787eda9fb759a81d6374ad998e3ae 100644
--- a/gso/services/crm.py
+++ b/gso/services/crm.py
@@ -1,6 +1,11 @@
 from typing import Optional
 
 
+class CustomerNotFoundError(Exception):
+    """Exception raised when a customer is not found."""
+    pass
+
+
 def all_customers() -> list[dict]:
     return [
         {
@@ -15,4 +20,4 @@ def get_customer_by_name(name: str) -> Optional[dict]:
         if customer["name"] == name:
             return customer
 
-    return None
+    raise CustomerNotFoundError(f"Customer {name} not found")
diff --git a/gso/workflows/__init__.py b/gso/workflows/__init__.py
index 10045c9da30edf2b0cca632b0320474f39d4f8f4..afd2d56a71c7f66e7032d846068d5fbc9ee10d72 100644
--- a/gso/workflows/__init__.py
+++ b/gso/workflows/__init__.py
@@ -8,4 +8,5 @@ LazyWorkflowInstance("gso.workflows.iptrunk.modify_trunk_interface", "modify_tru
 LazyWorkflowInstance("gso.workflows.iptrunk.terminate_iptrunk", "terminate_iptrunk")
 LazyWorkflowInstance("gso.workflows.iptrunk.modify_isis_metric", "modify_isis_metric")
 LazyWorkflowInstance("gso.workflows.site.create_site", "create_site")
-LazyWorkflowInstance("gso.workflows.tasks.import_site", "import_site")
\ No newline at end of file
+LazyWorkflowInstance("gso.workflows.tasks.import_site", "import_site")
+LazyWorkflowInstance("gso.workflows.tasks.import_router", "import_router")
diff --git a/gso/workflows/tasks/import_router.py b/gso/workflows/tasks/import_router.py
new file mode 100644
index 0000000000000000000000000000000000000000..c6cd8d062e9084377cd732e69d45d9d67374a7d6
--- /dev/null
+++ b/gso/workflows/tasks/import_router.py
@@ -0,0 +1,134 @@
+import ipaddress
+from typing import Optional
+
+from orchestrator import workflow
+from orchestrator.db import (
+    ProductTable,
+    SubscriptionTable,
+    SubscriptionInstanceValueTable,
+    SubscriptionInstanceTable,
+    ResourceTypeTable,
+)
+from orchestrator.domain.base import S
+from orchestrator.forms import FormPage
+from orchestrator.targets import Target
+from orchestrator.types import FormGenerator, State, UUIDstr, SubscriptionLifecycle
+from orchestrator.workflow import StepList, init, step, done
+from orchestrator.workflows.steps import store_process_subscription, set_status, resync
+
+from gso.products import Site
+from gso.products.product_blocks import router as router_pb
+from gso.products.product_blocks.router import RouterVendor, RouterRole
+from gso.products.product_types import router
+from gso.products.product_types.router import RouterInactive
+from gso.services.crm import get_customer_by_name
+
+
+@step("Create subscription")
+def create_subscription(customer: str) -> State:
+    customer_id: UUIDstr = get_customer_by_name(customer)["id"]
+    product_id: UUIDstr = ProductTable.query.filter_by(name="Router").first().product_id
+    subscription = RouterInactive.from_product_id(product_id, customer_id)
+
+    return {
+        "subscription": subscription,
+        "subscription_id": subscription.subscription_id,
+    }
+
+
+def initial_input_form_generator() -> FormGenerator:
+    class ImportRouter(FormPage):
+        class Config:
+            title = "Import Router"
+
+        customer: str
+        router_site: str
+        hostname: str
+        ts_port: int
+        router_vendor: RouterVendor
+        router_role: RouterRole
+        is_ias_connected: Optional[bool] = None
+        router_access_via_ts: Optional[bool] = None
+        router_lo_ipv4_address: Optional[ipaddress.IPv4Address] = None
+        router_lo_ipv6_address: Optional[ipaddress.IPv6Address] = None
+        router_lo_iso_address: Optional[str] = None
+        router_si_ipv4_network: Optional[ipaddress.IPv4Network] = None
+        router_ias_lt_ipv4_network: Optional[ipaddress.IPv4Network] = None
+        router_ias_lt_ipv6_network: Optional[ipaddress.IPv6Network] = None
+
+    user_input = yield ImportRouter
+
+    return user_input.dict()
+
+
+def get_site_by_name(site_name: str) -> S:
+    subscription = (
+        SubscriptionTable.query.join(
+            ProductTable, SubscriptionInstanceTable, SubscriptionInstanceValueTable, ResourceTypeTable
+        )
+        .filter(SubscriptionInstanceValueTable.value == site_name)
+        .filter(ResourceTypeTable.resource_type == "site_name")
+        .filter(SubscriptionTable.status == "active")
+        .first()
+    )
+    if not subscription:
+        raise ValueError(f"Site with name {site_name} not found")
+    return Site.from_subscription(subscription.subscription_id)
+
+
+@step("Initialize subscription")
+def initialize_subscription(
+    subscription: RouterInactive,
+    hostname: str,
+    ts_port: int,
+    router_vendor: router_pb.RouterVendor,
+    router_site: str,
+    router_role: router_pb.RouterRole,
+    is_ias_connected: Optional[bool] = None,
+    router_lo_ipv4_address: Optional[ipaddress.IPv4Address] = None,
+    router_lo_ipv6_address: Optional[ipaddress.IPv6Address] = None,
+    router_lo_iso_address: Optional[str] = None,
+    router_si_ipv4_network: Optional[ipaddress.IPv4Network] = None,
+    router_ias_lt_ipv4_network: Optional[ipaddress.IPv4Network] = None,
+    router_ias_lt_ipv6_network: Optional[ipaddress.IPv6Network] = None,
+) -> State:
+    subscription.router.router_ts_port = ts_port
+    subscription.router.router_vendor = router_vendor
+    subscription.router.router_site = get_site_by_name(router_site).site
+    fqdn = (
+        f"{hostname}.{subscription.router.router_site.site_name.lower()}."
+        f"{subscription.router.router_site.site_country_code.lower()}"
+        ".geant.net"
+    )
+    subscription.router.router_fqdn = fqdn
+    subscription.router.router_role = router_role
+    subscription.router.router_access_via_ts = True
+    subscription.description = f"Router {fqdn}"
+    subscription.router.router_is_ias_connected = is_ias_connected
+    subscription.router.router_lo_ipv4_address = router_lo_ipv4_address
+    subscription.router.router_lo_ipv6_address = router_lo_ipv6_address
+    subscription.router.router_lo_iso_address = router_lo_iso_address
+    subscription.router.router_si_ipv4_network = router_si_ipv4_network
+    subscription.router.router_ias_lt_ipv4_network = router_ias_lt_ipv4_network
+    subscription.router.router_ias_lt_ipv6_network = router_ias_lt_ipv6_network
+
+    subscription = router.RouterProvisioning.from_other_lifecycle(subscription, SubscriptionLifecycle.PROVISIONING)
+
+    return {"subscription": subscription}
+
+
+@workflow(
+    "Import router",
+    initial_input_form=initial_input_form_generator,
+    target=Target.SYSTEM,
+)
+def import_router() -> StepList:
+    return (
+        init
+        >> create_subscription
+        >> store_process_subscription(Target.CREATE)
+        >> initialize_subscription
+        >> set_status(SubscriptionLifecycle.ACTIVE)
+        >> resync
+        >> done
+    )