diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst
index bb7a2a69ca2c76900be5d138f6f3db610528538b..b98edde4222ab7f001fba8b36dfcc750d1821a8e 100644
--- a/docs/source/glossary.rst
+++ b/docs/source/glossary.rst
@@ -3,6 +3,9 @@ Glossary of terms
 
 .. glossary::
 
+  API
+    Application Programming Interface
+
   BGP
     Border Gateway Protocol: a path vector routing protocol described in
     `RFC 4271 <https://datatracker.ietf.org/doc/html/rfc4271>`_.
diff --git a/docs/source/module/products/index.rst b/docs/source/module/products/index.rst
index c68072cc071e570f268408b67e656b63a1ed4bf6..415b1c48357cd59d9a59fbd372be22cf11ac7b2c 100644
--- a/docs/source/module/products/index.rst
+++ b/docs/source/module/products/index.rst
@@ -1,6 +1,10 @@
 ``gso.products``
 ================
 
+.. automodule:: gso.products
+   :members:
+   :show-inheritance:
+
 Subpackages
 -----------
 
diff --git a/gso/api/v1/imports.py b/gso/api/v1/imports.py
index 242deb5ed47df089ebcf1c41b21a70f56dc4c0af..6f1cf4964c5f7d79fb31eb3d1170dd98d04e5a4e 100644
--- a/gso/api/v1/imports.py
+++ b/gso/api/v1/imports.py
@@ -1,17 +1,126 @@
+import ipaddress
 from typing import Any
 from uuid import UUID
 
 from fastapi import Depends, HTTPException, status
 from fastapi.routing import APIRouter
 from orchestrator.security import opa_security_default
-from orchestrator.services import processes, subscriptions
+from orchestrator.services import processes
+from orchestrator.services import subscriptions as wfo_subscriptions
+from pydantic import BaseModel, root_validator, validator
 from sqlalchemy.exc import MultipleResultsFound
 
-from gso.utils.types.imports import ImportResponseModel, IptrunkImportModel, RouterImportModel, SiteImportModel
+from gso.products.product_blocks.iptrunk import IptrunkType, PhyPortCapacity
+from gso.products.product_blocks.router import RouterRole, RouterVendor
+from gso.products.product_blocks.site import SiteTier
+from gso.services import subscriptions
+from gso.services.crm import CustomerNotFoundError, get_customer_by_name
+from gso.workflows.iptrunk.utils import LAGMember
 
 router = APIRouter(prefix="/imports", tags=["Imports"], dependencies=[Depends(opa_security_default)])
 
 
+class ImportResponseModel(BaseModel):
+    pid: UUID
+    detail: str
+
+
+class SiteImportModel(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
+    customer: str
+
+
+class RouterImportModel(BaseModel):
+    customer: str
+    router_site: str
+    hostname: str
+    ts_port: int
+    router_vendor: RouterVendor
+    router_role: RouterRole
+    is_ias_connected: bool
+    router_lo_ipv4_address: ipaddress.IPv4Address
+    router_lo_ipv6_address: ipaddress.IPv6Address
+    router_lo_iso_address: str
+    router_si_ipv4_network: ipaddress.IPv4Network | None = None
+    router_ias_lt_ipv4_network: ipaddress.IPv4Network | None = None
+    router_ias_lt_ipv6_network: ipaddress.IPv6Network | None = None
+
+
+class IptrunkImportModel(BaseModel):
+    customer: str
+    geant_s_sid: str
+    iptrunk_type: IptrunkType
+    iptrunk_description: str
+    iptrunk_speed: PhyPortCapacity
+    iptrunk_minimum_links: int
+    side_a_node_id: str
+    side_a_ae_iface: str
+    side_a_ae_geant_a_sid: str
+    side_a_ae_members: list[LAGMember]
+    side_b_node_id: str
+    side_b_ae_iface: str
+    side_b_ae_geant_a_sid: str
+    side_b_ae_members: list[LAGMember]
+
+    iptrunk_ipv4_network: ipaddress.IPv4Network
+    iptrunk_ipv6_network: ipaddress.IPv6Network
+
+    @classmethod
+    def _get_active_routers(cls) -> set[str]:
+        return {
+            str(router_id) for router_id in subscriptions.get_active_router_subscriptions(fields=["subscription_id"])
+        }
+
+    @validator("customer")
+    def check_if_customer_exists(cls, value: str) -> str:
+        try:
+            get_customer_by_name(value)
+        except CustomerNotFoundError:
+            raise ValueError(f"Customer {value} not found")
+
+        return value
+
+    @validator("side_a_node_id", "side_b_node_id")
+    def check_if_router_side_is_available(cls, value: str) -> str:
+        if value not in cls._get_active_routers():
+            raise ValueError(f"Router {value} not found")
+
+        return value
+
+    @validator("side_a_ae_members", "side_b_ae_members")
+    def check_side_uniqueness(cls, value: list[str]) -> list[str]:
+        if len(value) != len(set(value)):
+            raise ValueError("Items must be unique")
+
+        return value
+
+    @root_validator
+    def check_members(cls, values: dict[str, Any]) -> dict[str, Any]:
+        min_links = values["iptrunk_minimum_links"]
+        side_a_members = values.get("side_a_ae_members", [])
+        side_b_members = values.get("side_b_ae_members", [])
+
+        len_a = len(side_a_members)
+        len_b = len(side_b_members)
+
+        if len_a < min_links:
+            raise ValueError(f"Side A members should be at least {min_links} (iptrunk_minimum_links)")
+
+        if len_a != len_b:
+            raise ValueError("Mismatch between Side A and B members")
+
+        return values
+
+
 def _start_process(process_name: str, data: dict) -> UUID:
     """Start a process and handle common exceptions."""
 
@@ -42,7 +151,7 @@ def import_site(site: SiteImportModel) -> dict[str, Any]:
     :raises HTTPException: If the site already exists or if there's an error in the process.
     """
     try:
-        subscription = subscriptions.retrieve_subscription_by_subscription_instance_value(
+        subscription = wfo_subscriptions.retrieve_subscription_by_subscription_instance_value(
             resource_type="site_name", value=site.site_name, sub_status=("provisioning", "active")
         )
         if subscription:
diff --git a/gso/products/__init__.py b/gso/products/__init__.py
index c48474d7e46da845761cd3b940f499f3d57164f8..e6a8c06f8850748b36233be63006a8fa9709d946 100644
--- a/gso/products/__init__.py
+++ b/gso/products/__init__.py
@@ -1,4 +1,9 @@
-"""Module that updates the domain model of :term:`GSO`. Should contain all types of subscriptions."""
+"""Module that updates the domain model of :term:`GSO`. Should contain all types of subscriptions.
+
+.. warning::
+   Whenever a new product type is added, this should be reflected in the :py:class:`gso.products.ProductType`
+   enumerator.
+"""
 from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY
 from pydantic_forms.types import strEnum
 
@@ -15,8 +20,8 @@ class ProductType(strEnum):
 
 SUBSCRIPTION_MODEL_REGISTRY.update(
     {
-        ProductType.SITE.value: Site,
-        ProductType.ROUTER.value: Router,
-        ProductType.IP_TRUNK.value: Iptrunk,
+        "Site": Site,
+        "Router": Router,
+        "IP trunk": Iptrunk,
     }
 )
diff --git a/gso/products/product_blocks/iptrunk.py b/gso/products/product_blocks/iptrunk.py
index 4f0a4ed5cb60cf78edcdaddacb40ae7e9db5e0e7..7fab56c0d20be1d1adb9e9b65ffebd8049caa1ff 100644
--- a/gso/products/product_blocks/iptrunk.py
+++ b/gso/products/product_blocks/iptrunk.py
@@ -8,7 +8,18 @@ from orchestrator.forms.validators import UniqueConstrainedList
 from orchestrator.types import SubscriptionLifecycle, strEnum
 
 from gso.products.product_blocks.router import RouterBlock, RouterBlockInactive, RouterBlockProvisioning
-from gso.utils.types.phy_port import PhyPortCapacity
+
+
+class PhyPortCapacity(strEnum):
+    """Physical port capacity enumerator.
+
+    An enumerator that has the different possible capacities of ports that are available to use in subscriptions.
+    """
+
+    ONE_GIGABIT_PER_SECOND = "1G"
+    TEN_GIGABIT_PER_SECOND = "10G"
+    HUNDRED_GIGABIT_PER_SECOND = "100G"
+    FOUR_HUNDRED_GIGABIT_PER_SECOND = "400G"
 
 
 class IptrunkType(strEnum):
diff --git a/gso/products/product_blocks/router.py b/gso/products/product_blocks/router.py
index e5bdc7d8eb6559dd00edd4ddbf04d617143a7333..a8a820448a1b7388b903b0be69b7da9d4c17d660 100644
--- a/gso/products/product_blocks/router.py
+++ b/gso/products/product_blocks/router.py
@@ -3,9 +3,9 @@ import ipaddress
 
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle, strEnum
+from pydantic import ConstrainedInt
 
 from gso.products.product_blocks.site import SiteBlock, SiteBlockInactive, SiteBlockProvisioning
-from gso.utils.types.ip_port import PortNumber
 
 
 class RouterVendor(strEnum):
@@ -23,6 +23,16 @@ class RouterRole(strEnum):
     AMT = "amt"
 
 
+class PortNumber(ConstrainedInt):
+    """Constrained integer for valid port numbers.
+
+    The range from 49152 to 65535 is marked as ephemeral, and can therefore not be selected for permanent allocation.
+    """
+
+    gt = 0
+    le = 49151
+
+
 class RouterBlockInactive(
     ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="RouterBlock"
 ):
diff --git a/gso/products/product_blocks/site.py b/gso/products/product_blocks/site.py
index 683636e15d7f89a38a7343185c61be6ca9fdc541..739e1a0a91629b6dc2e427bfbd6ccd93daa8bb63 100644
--- a/gso/products/product_blocks/site.py
+++ b/gso/products/product_blocks/site.py
@@ -1,8 +1,10 @@
 """The product block that describes a site subscription."""
+import re
+from typing import Union
+
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle, strEnum
-
-from gso.utils.types.snmp import LatitudeCoordinate, LongitudeCoordinate
+from pydantic import ConstrainedStr
 
 
 class SiteTier(strEnum):
@@ -18,6 +20,42 @@ class SiteTier(strEnum):
     TIER4 = 4
 
 
+class LatitudeCoordinate(ConstrainedStr):
+    """A latitude coordinate, modeled as a constrained string.
+
+    The coordinate must match the format conforming to the latitude range of -90 to +90 degrees. It can be a
+    floating-point number or an integer.
+    Valid examples: 40.7128, -74.0060, 90, -90, 0
+    """
+
+    regex = re.compile(r"^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$")
+
+    @classmethod
+    def validate(cls, value: Union[str]) -> Union[str]:
+        if not cls.regex.match(value):
+            raise ValueError("Invalid latitude coordinate. Valid examples: '40.7128', '-74.0060', '90', '-90', '0'.")
+
+        return value
+
+
+class LongitudeCoordinate(ConstrainedStr):
+    """A longitude coordinate, modeled as a constrained string.
+
+    The coordinate must match the format conforming to the longitude
+    range of -180 to +180 degrees. It can be a floating point number or an integer.
+    Valid examples: 40.7128, -74.0060, 180, -180, 0
+    """
+
+    regex = re.compile(r"^-?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$")
+
+    @classmethod
+    def validate(cls, value: Union[str]) -> Union[str]:
+        if not cls.regex.match(value):
+            raise ValueError("Invalid longitude coordinate. Valid examples: '40.7128', '-74.0060', '180', '-180'")
+
+        return value
+
+
 class SiteBlockInactive(ProductBlockModel, lifecycle=[SubscriptionLifecycle.INITIAL], product_block_name="SiteBlock"):
     """A site that's currently inactive, see :class:`SiteBlock`."""
 
diff --git a/gso/utils/functions.py b/gso/utils/helpers.py
similarity index 100%
rename from gso/utils/functions.py
rename to gso/utils/helpers.py
diff --git a/gso/utils/types/__init__.py b/gso/utils/types/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/gso/utils/types/imports.py b/gso/utils/types/imports.py
deleted file mode 100644
index 7c13292cd67732cab563571635873156ba8aec08..0000000000000000000000000000000000000000
--- a/gso/utils/types/imports.py
+++ /dev/null
@@ -1,114 +0,0 @@
-import ipaddress
-from typing import Any
-from uuid import UUID
-
-from pydantic import BaseModel, root_validator, validator
-
-from gso.products.product_blocks.iptrunk import IptrunkType
-from gso.products.product_blocks.router import RouterRole, RouterVendor
-from gso.products.product_blocks.site import SiteTier
-from gso.services import subscriptions
-from gso.services.crm import CustomerNotFoundError, get_customer_by_name
-from gso.utils.types.phy_port import PhyPortCapacity
-from gso.workflows.iptrunk.utils import LAGMember
-
-
-class ImportResponseModel(BaseModel):
-    pid: UUID
-    detail: str
-
-
-class SiteImportModel(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
-    customer: str
-
-
-class RouterImportModel(BaseModel):
-    customer: str
-    router_site: str
-    hostname: str
-    ts_port: int
-    router_vendor: RouterVendor
-    router_role: RouterRole
-    is_ias_connected: bool
-    router_lo_ipv4_address: ipaddress.IPv4Address
-    router_lo_ipv6_address: ipaddress.IPv6Address
-    router_lo_iso_address: str
-    router_si_ipv4_network: ipaddress.IPv4Network | None = None
-    router_ias_lt_ipv4_network: ipaddress.IPv4Network | None = None
-    router_ias_lt_ipv6_network: ipaddress.IPv6Network | None = None
-
-
-class IptrunkImportModel(BaseModel):
-    customer: str
-    geant_s_sid: str
-    iptrunk_type: IptrunkType
-    iptrunk_description: str
-    iptrunk_speed: PhyPortCapacity
-    iptrunk_minimum_links: int
-    side_a_node_id: str
-    side_a_ae_iface: str
-    side_a_ae_geant_a_sid: str
-    side_a_ae_members: list[LAGMember]
-    side_b_node_id: str
-    side_b_ae_iface: str
-    side_b_ae_geant_a_sid: str
-    side_b_ae_members: list[LAGMember]
-
-    iptrunk_ipv4_network: ipaddress.IPv4Network
-    iptrunk_ipv6_network: ipaddress.IPv6Network
-
-    @classmethod
-    def _get_active_routers(cls) -> set[str]:
-        return {
-            str(router_id) for router_id in subscriptions.get_active_router_subscriptions(fields=["subscription_id"])
-        }
-
-    @validator("customer")
-    def check_if_customer_exists(cls, value: str) -> str:
-        try:
-            get_customer_by_name(value)
-        except CustomerNotFoundError:
-            raise ValueError(f"Customer {value} not found")
-
-        return value
-
-    @validator("side_a_node_id", "side_b_node_id")
-    def check_if_router_side_is_available(cls, value: str) -> str:
-        if value not in cls._get_active_routers():
-            raise ValueError("Router not found")
-
-        return value
-
-    @validator("side_a_ae_members", "side_b_ae_members")
-    def check_side_uniqueness(cls, value: list[str]) -> list[str]:
-        if len(value) != len(set(value)):
-            raise ValueError("Items must be unique")
-
-        return value
-
-    @root_validator
-    def check_members(cls, values: dict[str, Any]) -> dict[str, Any]:
-        min_links = values["iptrunk_minimum_links"]
-        side_a_members = values.get("side_a_ae_members", {})
-        side_b_members = values.get("side_b_ae_members", {})
-
-        len_a = len(side_a_members)
-        len_b = len(side_b_members)
-
-        if len_a < min_links:
-            raise ValueError(f"Side A members should be at least {min_links} (iptrunk_minimum_links)")
-
-        if len_a != len_b:
-            raise ValueError("Mismatch between Side A and B members")
-
-        return values
diff --git a/gso/utils/types/ip_port.py b/gso/utils/types/ip_port.py
deleted file mode 100644
index 81e080618557b4431b1c58df1c9f9c172d79078f..0000000000000000000000000000000000000000
--- a/gso/utils/types/ip_port.py
+++ /dev/null
@@ -1,11 +0,0 @@
-from pydantic import ConstrainedInt
-
-
-class PortNumber(ConstrainedInt):
-    """Constrained integer for valid port numbers.
-
-    The range from 49152 to 65535 is marked as ephemeral, and can therefore not be selected for permanent allocation.
-    """
-
-    gt = 0
-    le = 49151
diff --git a/gso/utils/types/phy_port.py b/gso/utils/types/phy_port.py
deleted file mode 100644
index 0d55eecec1116ec25e7a5c5ef842ed7a0f62c286..0000000000000000000000000000000000000000
--- a/gso/utils/types/phy_port.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from orchestrator.types import strEnum
-
-
-class PhyPortCapacity(strEnum):
-    """Physical port capacity enumerator.
-
-    An enumerator that has the different possible capacities of ports that are available to use in subscriptions.
-    """
-
-    ONE_GIGABIT_PER_SECOND = "1G"
-    TEN_GIGABIT_PER_SECOND = "10G"
-    HUNDRED_GIGABIT_PER_SECOND = "100G"
-    FOUR_HUNDRED_GIGABIT_PER_SECOND = "400G"
diff --git a/gso/utils/types/snmp.py b/gso/utils/types/snmp.py
deleted file mode 100644
index 114e573611b457a6adf3360517c3bd599021e08b..0000000000000000000000000000000000000000
--- a/gso/utils/types/snmp.py
+++ /dev/null
@@ -1,40 +0,0 @@
-import re
-from typing import Union
-
-from pydantic import ConstrainedStr
-
-
-class LatitudeCoordinate(ConstrainedStr):
-    """A latitude coordinate, modeled as a constrained string.
-
-    The coordinate must match the format conforming to the latitude range of -90 to +90 degrees. It can be a
-    floating-point number or an integer.
-    Valid examples: 40.7128, -74.0060, 90, -90, 0
-    """
-
-    regex = re.compile(r"^-?([1-8]?\d(\.\d+)?|90(\.0+)?)$")
-
-    @classmethod
-    def validate(cls, value: Union[str]) -> Union[str]:
-        if not cls.regex.match(value):
-            raise ValueError("Invalid latitude coordinate. Valid examples: '40.7128', '-74.0060', '90', '-90', '0'.")
-
-        return value
-
-
-class LongitudeCoordinate(ConstrainedStr):
-    """A longitude coordinate, modeled as a constrained string.
-
-    The coordinate must match the format conforming to the longitude
-    range of -180 to +180 degrees. It can be a floating point number or an integer.
-    Valid examples: 40.7128, -74.0060, 180, -180, 0
-    """
-
-    regex = re.compile(r"^-?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$")
-
-    @classmethod
-    def validate(cls, value: Union[str]) -> Union[str]:
-        if not cls.regex.match(value):
-            raise ValueError("Invalid longitude coordinate. Valid examples: '40.7128', '-74.0060', '180', '-180'")
-
-        return value
diff --git a/gso/workflows/iptrunk/create_iptrunk.py b/gso/workflows/iptrunk/create_iptrunk.py
index 8501fc8b325bc89bf10a70170cb2dda1a0e9a3a0..f1ee2cce08adec12a375b0c0ca39233d26dfd5ce 100644
--- a/gso/workflows/iptrunk/create_iptrunk.py
+++ b/gso/workflows/iptrunk/create_iptrunk.py
@@ -10,7 +10,7 @@ from orchestrator.workflows.utils import wrap_create_initial_input_form
 from pydantic import validator
 from pynetbox.models.dcim import Interfaces
 
-from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlockInactive, IptrunkType
+from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlockInactive, IptrunkType, PhyPortCapacity
 from gso.products.product_blocks.router import RouterVendor
 from gso.products.product_types.iptrunk import IptrunkInactive, IptrunkProvisioning
 from gso.products.product_types.router import Router
diff --git a/gso/workflows/iptrunk/modify_trunk_interface.py b/gso/workflows/iptrunk/modify_trunk_interface.py
index 0b2b37f4d061e9b41cd8ec7b3c77d91f315c135c..9e402bbe01270563847124c949b06386a5602ea6 100644
--- a/gso/workflows/iptrunk/modify_trunk_interface.py
+++ b/gso/workflows/iptrunk/modify_trunk_interface.py
@@ -9,11 +9,10 @@ from orchestrator.workflow import StepList, done, init, step, workflow
 from orchestrator.workflows.steps import resync, store_process_subscription, unsync
 from orchestrator.workflows.utils import wrap_modify_initial_input_form
 
-from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock, IptrunkType
+from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock, IptrunkType, PhyPortCapacity
 from gso.products.product_types.iptrunk import Iptrunk
 from gso.services import provisioning_proxy
 from gso.services.provisioning_proxy import pp_interaction
-from gso.utils.types.phy_port import PhyPortCapacity
 from gso.workflows.iptrunk.utils import LAGMember
 
 
diff --git a/gso/workflows/router/create_router.py b/gso/workflows/router/create_router.py
index 48011b04df66e0f96697658310b25c305abc4adf..d559d245b0c051920d65f9415b870db6b285a1d8 100644
--- a/gso/workflows/router/create_router.py
+++ b/gso/workflows/router/create_router.py
@@ -11,15 +11,14 @@ from orchestrator.workflows.steps import resync, set_status, store_process_subsc
 from orchestrator.workflows.utils import wrap_create_initial_input_form
 from pydantic import validator
 
-from gso.products.product_blocks.router import RouterRole, RouterVendor, generate_fqdn
+from gso.products.product_blocks.router import PortNumber, RouterRole, RouterVendor, generate_fqdn
 from gso.products.product_types.router import RouterInactive, RouterProvisioning
 from gso.products.product_types.site import Site
 from gso.services import infoblox, provisioning_proxy, subscriptions
 from gso.services.crm import customer_selector
 from gso.services.netbox_client import NetboxClient
 from gso.services.provisioning_proxy import pp_interaction
-from gso.utils.functions import iso_from_ipv4
-from gso.utils.types.ip_port import PortNumber
+from gso.utils.helpers import iso_from_ipv4
 
 
 def _site_selector() -> Choice:
diff --git a/gso/workflows/site/create_site.py b/gso/workflows/site/create_site.py
index c00856efd2c9f5fdc194e274ae7624089d22756f..429b0d7e489be69a980050c6b4698cddd1a1dd10 100644
--- a/gso/workflows/site/create_site.py
+++ b/gso/workflows/site/create_site.py
@@ -11,9 +11,9 @@ from orchestrator.workflows.utils import wrap_create_initial_input_form
 from pydantic import validator
 
 from gso.products.product_blocks import site as site_pb
+from gso.products.product_blocks.site import LatitudeCoordinate, LongitudeCoordinate
 from gso.products.product_types import site
 from gso.services.crm import customer_selector
-from gso.utils.types.snmp import LatitudeCoordinate, LongitudeCoordinate
 
 
 def initial_input_form_generator(product_name: str) -> FormGenerator:  # noqa: C901
diff --git a/gso/workflows/tasks/import_iptrunk.py b/gso/workflows/tasks/import_iptrunk.py
index 8203a905ad899812c5bf3ff5887281e082f27fb6..fe58ea11041b5573ae427795b18039e04b5d683c 100644
--- a/gso/workflows/tasks/import_iptrunk.py
+++ b/gso/workflows/tasks/import_iptrunk.py
@@ -9,11 +9,10 @@ from orchestrator.workflow import StepList, done, init, step
 from orchestrator.workflows.steps import resync, set_status, store_process_subscription
 
 from gso.products import ProductType
-from gso.products.product_blocks.iptrunk import IptrunkType
+from gso.products.product_blocks.iptrunk import IptrunkType, PhyPortCapacity
 from gso.products.product_types.iptrunk import IptrunkInactive, IptrunkProvisioning
 from gso.services import subscriptions
 from gso.services.crm import get_customer_by_name
-from gso.utils.types.phy_port import PhyPortCapacity
 from gso.workflows.iptrunk.create_iptrunk import initialize_subscription
 from gso.workflows.iptrunk.utils import LAGMember
 
diff --git a/gso/workflows/tasks/import_router.py b/gso/workflows/tasks/import_router.py
index 272f2750119d20a06e6d00abdf8d5fcc8d80cb98..d7984b9264af68bed7815126bee445d29062daea 100644
--- a/gso/workflows/tasks/import_router.py
+++ b/gso/workflows/tasks/import_router.py
@@ -10,13 +10,12 @@ from orchestrator.workflows.steps import resync, set_status, store_process_subsc
 
 from gso.products import ProductType
 from gso.products.product_blocks import router as router_pb
-from gso.products.product_blocks.router import RouterRole, RouterVendor
+from gso.products.product_blocks.router import PortNumber, RouterRole, RouterVendor
 from gso.products.product_types import router
 from gso.products.product_types.router import RouterInactive
 from gso.products.product_types.site import Site
 from gso.services import subscriptions
 from gso.services.crm import get_customer_by_name
-from gso.utils.types.ip_port import PortNumber
 
 
 def _get_site_by_name(site_name: str) -> Site:
diff --git a/test/fixtures.py b/test/fixtures.py
index b7e95eb17be6da247939c449897581627f010d98..ec2b2bd56179f2fa6e54dfe69bfa78d21a408c08 100644
--- a/test/fixtures.py
+++ b/test/fixtures.py
@@ -6,14 +6,13 @@ from orchestrator.domain import SubscriptionModel
 from orchestrator.types import SubscriptionLifecycle, UUIDstr
 
 from gso.products import ProductType
-from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock, IptrunkSideBlock, IptrunkType
+from gso.products.product_blocks.iptrunk import IptrunkInterfaceBlock, IptrunkSideBlock, IptrunkType, PhyPortCapacity
 from gso.products.product_blocks.router import RouterRole, RouterVendor
 from gso.products.product_blocks.site import SiteTier
 from gso.products.product_types.iptrunk import IptrunkInactive
 from gso.products.product_types.router import Router, RouterInactive
 from gso.products.product_types.site import Site, SiteInactive
 from gso.services import subscriptions
-from gso.utils.types.phy_port import PhyPortCapacity
 
 CUSTOMER_ID: UUIDstr = "2f47f65a-0911-e511-80d0-005056956c1a"
 
diff --git a/test/imports/test_imports.py b/test/imports/test_imports.py
index b2bc58b61c8c91ce0a1608cca496823c68d61ae1..3cdfa3ed1d5f87abd72521198220a58687b7960d 100644
--- a/test/imports/test_imports.py
+++ b/test/imports/test_imports.py
@@ -5,10 +5,10 @@ import pytest
 from orchestrator.db import SubscriptionTable
 from orchestrator.services import subscriptions
 
-from gso.products.product_blocks.iptrunk import IptrunkType
+from gso.products.product_blocks.iptrunk import IptrunkType, PhyPortCapacity
 from gso.products.product_blocks.router import RouterRole, RouterVendor
 from gso.products.product_blocks.site import SiteTier
-from gso.utils.types.phy_port import PhyPortCapacity
+from gso.utils.helpers import iso_from_ipv4
 
 SITE_IMPORT_ENDPOINT = "/api/v1/imports/sites"
 ROUTER_IMPORT_ENDPOINT = "/api/v1/imports/routers"
@@ -21,20 +21,20 @@ def iptrunk_data(router_subscription_factory, faker):
     router_side_b = router_subscription_factory()
     return {
         "customer": "GÉANT",
-        "geant_s_sid": faker.pystr(),
+        "geant_s_sid": faker.geant_sid(),
         "iptrunk_type": IptrunkType.DARK_FIBER,
         "iptrunk_description": faker.sentence(),
         "iptrunk_speed": PhyPortCapacity.HUNDRED_GIGABIT_PER_SECOND,
         "iptrunk_minimum_links": 5,
         "side_a_node_id": router_side_a,
-        "side_a_ae_iface": faker.pystr(),
-        "side_a_ae_geant_a_sid": faker.pystr(),
+        "side_a_ae_iface": faker.network_interface(),
+        "side_a_ae_geant_a_sid": faker.geant_sid(),
         "side_a_ae_members": [
             {"interface_name": faker.network_interface(), "interface_description": faker.sentence()} for _ in range(5)
         ],
         "side_b_node_id": router_side_b,
-        "side_b_ae_iface": faker.pystr(),
-        "side_b_ae_geant_a_sid": faker.pystr(),
+        "side_b_ae_iface": faker.network_interface(),
+        "side_b_ae_geant_a_sid": faker.geant_sid(),
         "side_b_ae_members": [
             {"interface_name": faker.network_interface(), "interface_description": faker.sentence()} for _ in range(5)
         ],
@@ -45,23 +45,23 @@ def iptrunk_data(router_subscription_factory, faker):
 
 @pytest.fixture
 def mock_routers(iptrunk_data):
-    first_call = [iptrunk_data["side_a_node_id"], iptrunk_data["side_b_node_id"], str(uuid4())]
-    side_effects = [
-        first_call,
-        first_call,
-        [
-            (iptrunk_data["side_a_node_id"], "side_a_node_id description"),
-            (iptrunk_data["side_b_node_id"], "side_b_node_id description"),
-            (str(uuid4()), "random description"),
-        ],
-    ]
     with patch("gso.services.subscriptions.get_active_router_subscriptions") as mock_get_active_router_subscriptions:
-        mock_get_active_router_subscriptions.side_effect = side_effects
+
+        def _active_router_subscriptions(*args, **kwargs):
+            if kwargs["fields"] == ["subscription_id", "description"]:
+                return [
+                    (iptrunk_data["side_a_node_id"], "side_a_node_id description"),
+                    (iptrunk_data["side_b_node_id"], "side_b_node_id description"),
+                    (str(uuid4()), "random description"),
+                ]
+            return [iptrunk_data["side_a_node_id"], iptrunk_data["side_b_node_id"], str(uuid4())]
+
+        mock_get_active_router_subscriptions.side_effect = _active_router_subscriptions
         yield mock_get_active_router_subscriptions
 
 
 @patch("gso.api.v1.imports._start_process")
-def test_import_iptrunk_successful_with_mocked_process(mock_start_process, test_client, iptrunk_data, mock_routers):
+def test_import_iptrunk_successful_with_mocked_process(mock_start_process, test_client, mock_routers, iptrunk_data):
     mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
     response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
 
@@ -72,7 +72,7 @@ def test_import_iptrunk_successful_with_mocked_process(mock_start_process, test_
 @pytest.fixture
 def site_data(faker):
     return {
-        "site_name": faker.name(),
+        "site_name": faker.domain_word(),
         "site_city": faker.city(),
         "site_country": faker.country(),
         "site_country_code": faker.country_code(),
@@ -88,6 +88,7 @@ def site_data(faker):
 
 @pytest.fixture
 def router_data(faker, site_data):
+    mock_ipv4 = faker.ipv4()
     return {
         "hostname": "127.0.0.1",
         "router_role": RouterRole.PE,
@@ -96,9 +97,9 @@ def router_data(faker, site_data):
         "ts_port": 1234,
         "customer": "GÉANT",
         "is_ias_connected": True,
-        "router_lo_ipv4_address": faker.ipv4(),
+        "router_lo_ipv4_address": mock_ipv4,
         "router_lo_ipv6_address": faker.ipv6(),
-        "router_lo_iso_address": "TestAddress",
+        "router_lo_iso_address": iso_from_ipv4(mock_ipv4),
     }
 
 
@@ -169,7 +170,7 @@ def test_import_router_endpoint_with_invalid_data(test_client, site_data, router
     assert response["detail"][1]["msg"] == "value is not a valid IPv6 address"
 
 
-def test_import_iptrunk_successful_with_real_process(test_client, iptrunk_data, mock_routers):
+def test_import_iptrunk_successful_with_real_process(test_client, mock_routers, iptrunk_data):
     response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
     assert response.status_code == 201
 
@@ -184,7 +185,7 @@ def test_import_iptrunk_successful_with_real_process(test_client, iptrunk_data,
 
 
 @patch("gso.api.v1.imports._start_process")
-def test_import_iptrunk_invalid_customer(mock_start_process, test_client, iptrunk_data, mock_routers):
+def test_import_iptrunk_invalid_customer(mock_start_process, test_client, mock_routers, iptrunk_data):
     iptrunk_data["customer"] = "not_existing_customer"
     mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
     response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
@@ -205,32 +206,28 @@ def test_import_iptrunk_invalid_router_id_side_a_and_b(mock_start_process, test_
     assert response.status_code == 422
     assert response.json() == {
         "detail": [
-            {"loc": ["body", "side_a_node_id"], "msg": "Router not found", "type": "value_error"},
-            {"loc": ["body", "side_b_node_id"], "msg": "Router not found", "type": "value_error"},
+            {
+                "loc": ["body", "side_a_node_id"],
+                "msg": f"Router {iptrunk_data['side_a_node_id']} not found",
+                "type": "value_error",
+            },
+            {
+                "loc": ["body", "side_b_node_id"],
+                "msg": f"Router {iptrunk_data['side_b_node_id']} not found",
+                "type": "value_error",
+            },
         ]
     }
 
 
 @patch("gso.api.v1.imports._start_process")
-def test_import_iptrunk_non_unique_members_side_a(mock_start_process, test_client, iptrunk_data, mock_routers, faker):
+def test_import_iptrunk_non_unique_members_side_a(mock_start_process, test_client, mock_routers, iptrunk_data, faker):
     mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
 
     repeat_interface_a = {"interface_name": faker.network_interface(), "interface_description": faker.sentence()}
     repeat_interface_b = {"interface_name": faker.network_interface(), "interface_description": faker.sentence()}
-    iptrunk_data["side_a_ae_members"] = [
-        repeat_interface_a,
-        repeat_interface_a,
-        repeat_interface_a,
-        repeat_interface_a,
-        repeat_interface_a,
-    ]
-    iptrunk_data["side_b_ae_members"] = [
-        repeat_interface_b,
-        repeat_interface_a,
-        repeat_interface_a,
-        repeat_interface_b,
-        repeat_interface_b,
-    ]
+    iptrunk_data["side_a_ae_members"] = [repeat_interface_a for _ in range(5)]
+    iptrunk_data["side_b_ae_members"] = [repeat_interface_b for _ in range(5)]
 
     response = test_client.post(IPTRUNK_IMPORT_API_URL, json=iptrunk_data)
 
@@ -250,7 +247,7 @@ def test_import_iptrunk_non_unique_members_side_a(mock_start_process, test_clien
 
 @patch("gso.api.v1.imports._start_process")
 def test_import_iptrunk_fails_on_side_a_member_count_mismatch(
-    mock_start_process, test_client, iptrunk_data, mock_routers
+    mock_start_process, test_client, mock_routers, iptrunk_data
 ):
     mock_start_process.return_value = "123e4567-e89b-12d3-a456-426655440000"
 
diff --git a/test/schemas/test_types.py b/test/schemas/test_types.py
index b8f6eef13c84c74416ed829320a6cfb41edf4514..e5d757dbb84550df27f05949caf2e1ad78c7a2c8 100644
--- a/test/schemas/test_types.py
+++ b/test/schemas/test_types.py
@@ -1,6 +1,6 @@
 import pytest
 
-from gso.utils.types.snmp import LatitudeCoordinate, LongitudeCoordinate
+from gso.products.product_blocks.site import LatitudeCoordinate, LongitudeCoordinate
 
 
 @pytest.mark.parametrize(
diff --git a/test/workflows/iptrunk/test_create_iptrunk.py b/test/workflows/iptrunk/test_create_iptrunk.py
index cff8bed98c5c10ca3c79b918ec3ed5cca6720668..479fbb91c48d0943efb91209a13ff93dcfe14498 100644
--- a/test/workflows/iptrunk/test_create_iptrunk.py
+++ b/test/workflows/iptrunk/test_create_iptrunk.py
@@ -4,10 +4,9 @@ from unittest.mock import patch
 import pytest
 
 from gso.products import Iptrunk, ProductType
-from gso.products.product_blocks.iptrunk import IptrunkType
+from gso.products.product_blocks.iptrunk import IptrunkType, PhyPortCapacity
 from gso.services.crm import customer_selector, get_customer_by_name
 from gso.services.subscriptions import get_product_id_by_name
-from gso.utils.types.phy_port import PhyPortCapacity
 from test.workflows import (
     assert_aborted,
     assert_complete,
diff --git a/test/workflows/iptrunk/test_modify_trunk_interface.py b/test/workflows/iptrunk/test_modify_trunk_interface.py
index 4160f954de4f1ed113f7e03424ce41ceb1efc116..8f39c4d7f784be6c3beea80c3741f7d856271c20 100644
--- a/test/workflows/iptrunk/test_modify_trunk_interface.py
+++ b/test/workflows/iptrunk/test_modify_trunk_interface.py
@@ -3,8 +3,7 @@ from unittest.mock import patch
 import pytest
 
 from gso.products import Iptrunk
-from gso.products.product_blocks.iptrunk import IptrunkType
-from gso.utils.types.phy_port import PhyPortCapacity
+from gso.products.product_blocks.iptrunk import IptrunkType, PhyPortCapacity
 from test.workflows import (
     assert_complete,
     assert_suspended,