diff --git a/Changelog.md b/Changelog.md
index d490a8bfe7769d4024704346facc5b5b18eaac93..2711dd1ca9518252d537b187665950696a9bc924 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,11 @@
 # Changelog
 
+# [3.1] - 2025-04-29
+- Allow running the prefix validation workflow on out-of-sync subscriptions
+- Only check Kentik licenses during router validation in production
+- Add optional TTL security field to BGP session product block
+- Refactor the code and improve the code quality
+
 # [3.0] - 2025-04-23
 - Breaking change: reworked all the Layer 3 Core services, splitting them up into separate product types.
 - Allow for creating an Edge Port on a Juniper router.
diff --git a/docs/includes/glossary.md b/docs/includes/glossary.md
index a29d245259baa8a8b27cd16feade66bd5fa6c732..af5cb334a0a5bb5417b18de02a196add0967bd44 100644
--- a/docs/includes/glossary.md
+++ b/docs/includes/glossary.md
@@ -36,6 +36,7 @@
 *[NREN]: National Research and Education Network
 *[OOB]: Out-of-band
 *[OSS]: Operational Support Systems
+*[OTRS]: Trouble Ticket system software package
 *[PoP]: Point of Presence
 *[REST]: Representational State Transfer
 *[RFC]: Request For Comments
@@ -44,6 +45,7 @@
 *[SNMP]: Simple Network Management Protocol
 *[SOT]: Source Of Truth
 *[TBA]: To be added
+*[TTL]: Time To Live
 *[UAT]: User Acceptance Testing
 *[VM]: Virtual Machine
 *[VRF]: Virtual Routing and Forwarding
diff --git a/docs/vale/styles/config/vocabularies/geant-jargon/accept.txt b/docs/vale/styles/config/vocabularies/geant-jargon/accept.txt
index aeb0c40d8ae8adc250f8ab38c568ad95d4855393..a7e4a6f7c0f83ed5c864b816583fe3e667cc4449 100644
--- a/docs/vale/styles/config/vocabularies/geant-jargon/accept.txt
+++ b/docs/vale/styles/config/vocabularies/geant-jargon/accept.txt
@@ -55,6 +55,7 @@ OIDC
 OOB
 OPA
 (OSS|oss)
+OTRS
 PHASE 1
 Po[Pp]
 Pydantic
@@ -69,6 +70,7 @@ SOT
 SURF
 TBA
 TERMINATED?
+TTL
 TWAMP
 UAT
 UTC
diff --git a/gso/cli/imports.py b/gso/cli/imports.py
index 6a82ddecc513fc71496de598d83d2499272bab5a..fdcba0f6bdb0df597fc0a155b94e595a09eaa08e 100644
--- a/gso/cli/imports.py
+++ b/gso/cli/imports.py
@@ -259,6 +259,7 @@ class L3CoreServiceImportModel(BaseModel):
         is_multi_hop: bool
         rtbh_enabled: bool  # whether Remote Triggered Blackhole is enabled
         prefix_limit: NonNegativeInt | None = None
+        ttl_security: NonNegativeInt | None = None
 
     class BFDSettingsModel(BaseModel):
         """BFD Settings model."""
diff --git a/gso/migrations/versions/2025-04-28_a3177c5f9641_add_optional_ttl_security_to_bgp_session.py b/gso/migrations/versions/2025-04-28_a3177c5f9641_add_optional_ttl_security_to_bgp_session.py
new file mode 100644
index 0000000000000000000000000000000000000000..cbcb3558ba6586aac3d518c5cbce6f1ed74a503d
--- /dev/null
+++ b/gso/migrations/versions/2025-04-28_a3177c5f9641_add_optional_ttl_security_to_bgp_session.py
@@ -0,0 +1,41 @@
+"""Add optional TTL security to BGP session.
+
+Revision ID: a3177c5f9641
+Revises: fffe36624681
+Create Date: 2025-04-28 10:21:54.820219
+
+"""
+import sqlalchemy as sa
+from alembic import op
+
+# revision identifiers, used by Alembic.
+revision = 'a3177c5f9641'
+down_revision = 'fffe36624681'
+branch_labels = None
+depends_on = None
+
+
+def upgrade() -> None:
+    conn = op.get_bind()
+    conn.execute(sa.text("""
+INSERT INTO resource_types (resource_type, description) VALUES ('ttl_security', 'BGP TTL security') RETURNING resource_types.resource_type_id
+    """))
+    conn.execute(sa.text("""
+INSERT INTO product_block_resource_types (product_block_id, resource_type_id) VALUES ((SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BGPSession')), (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ttl_security')))
+    """))
+
+
+def downgrade() -> None:
+    conn = op.get_bind()
+    conn.execute(sa.text("""
+DELETE FROM product_block_resource_types WHERE product_block_resource_types.product_block_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BGPSession')) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ttl_security'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM subscription_instance_values USING product_block_resource_types WHERE subscription_instance_values.subscription_instance_id IN (SELECT subscription_instances.subscription_instance_id FROM subscription_instances WHERE subscription_instances.subscription_instance_id IN (SELECT product_blocks.product_block_id FROM product_blocks WHERE product_blocks.name IN ('BGPSession'))) AND product_block_resource_types.resource_type_id = (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ttl_security'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM subscription_instance_values WHERE subscription_instance_values.resource_type_id IN (SELECT resource_types.resource_type_id FROM resource_types WHERE resource_types.resource_type IN ('ttl_security'))
+    """))
+    conn.execute(sa.text("""
+DELETE FROM resource_types WHERE resource_types.resource_type IN ('ttl_security')
+    """))
diff --git a/gso/products/product_blocks/bgp_session.py b/gso/products/product_blocks/bgp_session.py
index 863a2da0ac904a5522b58fb15e048c9ee013173b..638c06607ab5ad4690257b8d7893528469500e55 100644
--- a/gso/products/product_blocks/bgp_session.py
+++ b/gso/products/product_blocks/bgp_session.py
@@ -48,6 +48,7 @@ class BGPSessionInactive(ProductBlockModel, lifecycle=[SubscriptionLifecycle.INI
     bfd_enabled: bool = False
     ip_type: IPTypes | None = None
     prefix_limit: NonNegativeInt | None = None
+    ttl_security: NonNegativeInt | None = None
 
 
 class BGPSessionProvisioning(BGPSessionInactive, lifecycle=[SubscriptionLifecycle.PROVISIONING]):
@@ -65,6 +66,7 @@ class BGPSessionProvisioning(BGPSessionInactive, lifecycle=[SubscriptionLifecycl
     bfd_enabled: bool
     ip_type: IPTypes
     prefix_limit: NonNegativeInt | None
+    ttl_security: NonNegativeInt | None
 
 
 class BGPSession(BGPSessionProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE]):
@@ -83,6 +85,7 @@ class BGPSession(BGPSessionProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE
         bfd_enabled: Settings for BFD.
         ip_type: The IP type of the session.
         prefix_limit: A prefix limit, if required.
+        ttl_security: A limit on time-to-live used for TTL security.
     """
 
     peer_address: IPAddress
@@ -97,3 +100,4 @@ class BGPSession(BGPSessionProvisioning, lifecycle=[SubscriptionLifecycle.ACTIVE
     bfd_enabled: bool
     ip_type: IPTypes
     prefix_limit: NonNegativeInt | None
+    ttl_security: NonNegativeInt | None
diff --git a/gso/services/lso_client.py b/gso/services/lso_client.py
index 2318cffd7396e51c620fa55087faea21e7043187..67e2791752d1d5d9c4be584b21915e9f5ec9832a 100644
--- a/gso/services/lso_client.py
+++ b/gso/services/lso_client.py
@@ -14,7 +14,7 @@ from orchestrator.forms import SubmitFormPage
 from orchestrator.utils.errors import ProcessFailureError
 from orchestrator.workflow import Step, StepList, begin, callback_step, conditional, inputstep
 from pydantic import ConfigDict
-from pydantic_forms.types import FormGenerator, State
+from pydantic_forms.types import FormGenerator, State, UUIDstr
 from pydantic_forms.validators import Label, LongText, ReadOnlyField
 from unidecode import unidecode
 
@@ -64,7 +64,7 @@ def _send_request(parameters: dict, callback_route: str) -> None:
 
 @step("Execute Ansible playbook")
 def _execute_playbook(
-    playbook_name: str, callback_route: str, inventory: dict[str, Any], extra_vars: dict[str, Any]
+    playbook_name: str, callback_route: str, inventory: dict[str, Any], extra_vars: dict[str, Any], process_id: UUIDstr
 ) -> None:
     """Execute a playbook remotely through the provisioning proxy.
 
@@ -112,7 +112,10 @@ def _execute_playbook(
         extra_vars: Any extra variables that the playbook relies on. This can include a subscription object, a boolean
             value indicating a dry run, a commit comment, etc. All unicode character values are decoded to prevent
             sending special characters to remote machines that don't support this.
+        process_id: The process ID of the workflow that is running the playbook. This is used in Ansible playbooks to
+            fetch custom configuration.
     """
+    extra_vars["gso_process_id"] = process_id
     parameters = {
         "playbook_name": playbook_name,
         "inventory": inventory,
diff --git a/gso/translations/en-GB.json b/gso/translations/en-GB.json
index 98d936fa0b0bbc830395531474ccf0e9b866d619..b1d6a36a4ee673823c9a346447340c9211c90bb8 100644
--- a/gso/translations/en-GB.json
+++ b/gso/translations/en-GB.json
@@ -58,6 +58,7 @@
             "v4_bgp_bfd_enabled": "IPv4 BGP - BFD enabled",
             "v4_bgp_multipath_enabled":  "IPv4 - BGP multipath enabled",
             "v4_bgp_prefix_limit": "IPv4 - BGP prefix limit",
+            "v4_bgp_ttl_security": "IPv4 - BGP TTL security",
             "v4_bgp_is_passive":  "IPv4 - BGP is passive",
             "v4_bgp_send_default_route": "IPv4 - BGP send default route",
             "v4_bgp_add_v4_multicast":  "IPv4 - BGP add multicast",
@@ -71,6 +72,7 @@
             "v6_bgp_bfd_enabled":  "IPv6 - BGP BFD enabled",
             "v6_bgp_multipath_enabled": "IPv6 - BGP multipath enabled",
             "v6_bgp_prefix_limit":  "IPv6 - BGP prefix limit",
+            "v6_bgp_ttl_security":  "IPv6 - BGP TTL security",
             "v6_bgp_is_passive": "IPv6 - BGP is passive",
             "v6_bgp_send_default_route":  "IPv6 - BGP send default route",
             "v6_bgp_add_v6_multicast": "IPv6 - BGP add multicast"
diff --git a/gso/workflows/__init__.py b/gso/workflows/__init__.py
index f69279021b2fae317e08094b3aae013ff14bcda7..8b1f4065d11869daa09e3ab124caf4b7484a89e0 100644
--- a/gso/workflows/__init__.py
+++ b/gso/workflows/__init__.py
@@ -1,6 +1,6 @@
 """Initialisation class that imports all workflows into GSO."""
 
-from orchestrator.services.subscriptions import WF_USABLE_MAP
+from orchestrator.services.subscriptions import WF_USABLE_MAP, WF_USABLE_WHILE_OUT_OF_SYNC
 from orchestrator.types import SubscriptionLifecycle
 from orchestrator.workflows import LazyWorkflowInstance
 
@@ -28,6 +28,8 @@ WF_USABLE_MAP.update({
     "validate_iptrunk": [SubscriptionLifecycle.PROVISIONING, SubscriptionLifecycle.ACTIVE],
 })
 
+WF_USABLE_WHILE_OUT_OF_SYNC.extend(["validate_geant_ip_prefix_list"])
+
 #  IP trunk workflows
 LazyWorkflowInstance("gso.workflows.iptrunk.activate_iptrunk", "activate_iptrunk")
 LazyWorkflowInstance("gso.workflows.iptrunk.create_iptrunk", "create_iptrunk")
diff --git a/gso/workflows/l3_core_service/base_create_imported_l3_core_service.py b/gso/workflows/l3_core_service/base_create_imported_l3_core_service.py
index 3f8bf13f324771ea4dd2c4f33dffbafb65d2c26e..7261633b4439a9ab2602237865d9e80a1f8a26d2 100644
--- a/gso/workflows/l3_core_service/base_create_imported_l3_core_service.py
+++ b/gso/workflows/l3_core_service/base_create_imported_l3_core_service.py
@@ -40,6 +40,7 @@ def initial_input_form_generator() -> FormGenerator:
         is_multi_hop: bool
         rtbh_enabled: bool
         prefix_limit: NonNegativeInt | None = None
+        ttl_security: NonNegativeInt | None = None
 
     class ServiceBindingPort(BaseModel):
         edge_port: UUIDstr
diff --git a/gso/workflows/l3_core_service/base_create_l3_core_service.py b/gso/workflows/l3_core_service/base_create_l3_core_service.py
index 6d8c451ea82e3af081020977c05943e06797c4d2..90221ec0ed482de386762c097c88eb7a9e8298e0 100644
--- a/gso/workflows/l3_core_service/base_create_l3_core_service.py
+++ b/gso/workflows/l3_core_service/base_create_l3_core_service.py
@@ -70,6 +70,7 @@ def initial_input_form_generator(product_name: str) -> FormGenerator:
         bfd_enabled: bool = False
         multipath_enabled: bool = False
         prefix_limit: NonNegativeInt | None = None
+        ttl_security: NonNegativeInt | None = None
         is_passive: bool = False
         add_v4_multicast: bool = Field(default=False, exclude=True)
         send_default_route: bool = False
@@ -91,6 +92,7 @@ def initial_input_form_generator(product_name: str) -> FormGenerator:
         bfd_enabled: bool = False
         multipath_enabled: bool = False
         prefix_limit: NonNegativeInt | None = None
+        ttl_security: NonNegativeInt | None = None
         is_passive: bool = False
         add_v6_multicast: bool = Field(default=False, exclude=True)
         send_default_route: bool = False
diff --git a/gso/workflows/l3_core_service/base_modify_l3_core_service.py b/gso/workflows/l3_core_service/base_modify_l3_core_service.py
index 4185ef26965e3fe003c51dcf8cdb0c0f61db64b4..e16364ad1095734f4904c7288d54f46f9dbd808c 100644
--- a/gso/workflows/l3_core_service/base_modify_l3_core_service.py
+++ b/gso/workflows/l3_core_service/base_modify_l3_core_service.py
@@ -74,6 +74,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
         bfd_enabled: bool = False
         multipath_enabled: bool = False
         prefix_limit: NonNegativeInt | None = None
+        ttl_security: NonNegativeInt | None = None
         is_passive: bool = False
         add_v4_multicast: bool = Field(default=False, exclude=True)
         send_default_route: bool = False
@@ -95,6 +96,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
         bfd_enabled: bool = False
         multipath_enabled: bool = False
         prefix_limit: NonNegativeInt | None = None
+        ttl_security: NonNegativeInt | None = None
         is_passive: bool = False
         add_v6_multicast: bool = Field(default=False, exclude=True)
         send_default_route: bool = False
@@ -282,6 +284,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
                 v4_bgp_bfd_enabled: bool = Field(v4_peer.bfd_enabled, exclude=True)
                 v4_bgp_multipath_enabled: bool = Field(v4_peer.multipath_enabled, exclude=True)
                 v4_bgp_prefix_limit: NonNegativeInt | None = Field(v4_peer.prefix_limit, exclude=True)
+                v4_bgp_ttl_security: NonNegativeInt | None = Field(v4_peer.ttl_security, exclude=True)
                 v4_bgp_is_passive: bool = Field(v4_peer.is_passive, exclude=True)
                 v4_bgp_send_default_route: bool = Field(v4_peer.send_default_route, exclude=True)
                 v4_bgp_add_v4_multicast: bool = Field(bool(IPFamily.V4MULTICAST in v4_peer.families), exclude=True)
@@ -299,6 +302,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
                 v6_bgp_bfd_enabled: bool = Field(v6_peer.bfd_enabled, exclude=True)
                 v6_bgp_multipath_enabled: bool = Field(v6_peer.multipath_enabled, exclude=True)
                 v6_bgp_prefix_limit: NonNegativeInt | None = Field(v6_peer.prefix_limit, exclude=True)
+                v6_bgp_ttl_security: NonNegativeInt | None = Field(v6_peer.ttl_security, exclude=True)
                 v6_bgp_is_passive: bool = Field(v6_peer.is_passive, exclude=True)
                 v6_bgp_send_default_route: bool = Field(v6_peer.send_default_route, exclude=True)
                 v6_bgp_add_v6_multicast: bool = Field(bool(IPFamily.V6MULTICAST in v6_peer.families), exclude=True)
@@ -323,6 +327,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
                         bfd_enabled=self.v4_bgp_bfd_enabled,
                         multipath_enabled=self.v4_bgp_multipath_enabled,
                         prefix_limit=self.v4_bgp_prefix_limit,
+                        ttl_security=self.v4_bgp_ttl_security,
                         is_passive=self.v4_bgp_is_passive,
                         send_default_route=self.v4_bgp_send_default_route,
                         add_v4_multicast=self.v4_bgp_add_v4_multicast,
@@ -348,6 +353,7 @@ def initial_input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
                         bfd_enabled=self.v6_bgp_bfd_enabled,
                         multipath_enabled=self.v6_bgp_multipath_enabled,
                         prefix_limit=self.v6_bgp_prefix_limit,
+                        ttl_security=self.v6_bgp_ttl_security,
                         is_passive=self.v6_bgp_is_passive,
                         send_default_route=self.v6_bgp_send_default_route,
                         add_v6_multicast=self.v6_bgp_add_v6_multicast,
diff --git a/gso/workflows/l3_core_service/base_validate_prefix_list.py b/gso/workflows/l3_core_service/base_validate_prefix_list.py
deleted file mode 100644
index 1771426c9fa5a701051f64b363c346ba3a282c84..0000000000000000000000000000000000000000
--- a/gso/workflows/l3_core_service/base_validate_prefix_list.py
+++ /dev/null
@@ -1,105 +0,0 @@
-"""Prefix Validation workflow for L3 Core Service subscription objects."""
-
-from typing import Any
-
-from orchestrator.config.assignee import Assignee
-from orchestrator.domain import SubscriptionModel
-from orchestrator.forms import SubmitFormPage
-from orchestrator.workflow import inputstep, step
-from pydantic import Field
-from pydantic_forms.types import FormGenerator, State, UUIDstr
-from pydantic_forms.validators import Label
-
-from gso.services.lso_client import LSOState
-from gso.services.partners import get_partner_by_id
-from gso.utils.shared_enums import Vendor
-
-
-@step("Prepare list of all Access Ports")
-def build_fqdn_list(subscription_id: UUIDstr) -> State:
-    """Build the list of all FQDNs in the access ports of L3 Core Service subscription, excluding Juniper devices."""
-    subscription = SubscriptionModel.from_subscription(subscription_id)
-    ap_list = subscription.l3_core.ap_list  # type: ignore[attr-defined]
-    ap_fqdn_list = [
-        ap.sbp.edge_port.node.router_fqdn for ap in ap_list if ap.sbp.edge_port.node.vendor != Vendor.JUNIPER
-    ]
-    return {"ap_fqdn_list": ap_fqdn_list, "subscription": subscription}
-
-
-@step("[DRY RUN] Validate Prefix-Lists")
-def validate_prefix_lists_dry(subscription: dict[str, Any], process_id: UUIDstr, ap_fqdn_list: list[str]) -> LSOState:
-    """Workflow step for running a playbook that validates prefix-lists in dry run mode."""
-    extra_vars = {
-        "subscription": subscription,
-        "partner_name": get_partner_by_id(subscription["customer_id"]).name,
-        "dry_run": True,
-        "verb": "deploy",
-        "object": "prefix_list",
-        "is_verification_workflow": "true",
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - Validate prefix-lists for {subscription["description"]}",
-    }
-
-    return {
-        "playbook_name": "gap_ansible/playbooks/validate_prefix_list.yaml",
-        "inventory": {"all": {"hosts": dict.fromkeys(ap_fqdn_list)}},
-        "extra_vars": extra_vars,
-    }
-
-
-@step("Evaluate validation of Prefix-Lists")
-def evaluate_result_has_diff(callback_result: dict) -> State:
-    """Evaluate the result of the playbook that validates prefix-lists."""
-    return {"callback_result": callback_result, "prefix_list_drift": bool(callback_result["return_code"] != 0)}
-
-
-@inputstep("Await operator confirmation", assignee=Assignee.SYSTEM)
-def await_operator() -> FormGenerator:
-    """Show a form for the operator to start redeploying the prefix list that has drifted."""
-
-    class AwaitOperatorForm(SubmitFormPage):
-        info_label_a: Label = Field("A drift has been detected for this prefix list!", exclude=True)
-        info_label_b: Label = Field("Please continue this workflow to redeploy the drifted prefix list.", exclude=True)
-
-    yield AwaitOperatorForm
-
-    return {}
-
-
-@step("[DRY RUN] Deploy Prefix-Lists")
-def deploy_prefix_lists_dry(subscription: dict[str, Any], process_id: UUIDstr, ap_fqdn_list: list[str]) -> LSOState:
-    """Workflow step for running a playbook that deploys prefix-lists in dry run mode."""
-    extra_vars = {
-        "subscription": subscription,
-        "partner_name": get_partner_by_id(subscription["customer_id"]).name,
-        "dry_run": True,
-        "verb": "deploy",
-        "object": "prefix_list",
-        "is_verification_workflow": "false",
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - Deploy prefix-lists for {subscription["description"]}",
-    }
-
-    return {
-        "playbook_name": "gap_ansible/playbooks/deploy_prefix_list.yaml",
-        "inventory": {"all": {"hosts": dict.fromkeys(ap_fqdn_list)}},
-        "extra_vars": extra_vars,
-    }
-
-
-@step("[REAL] Deploy Prefix-Lists")
-def deploy_prefix_lists_real(subscription: dict[str, Any], process_id: UUIDstr, ap_fqdn_list: list[str]) -> LSOState:
-    """Workflow step for running a playbook that deploys prefix-lists."""
-    extra_vars = {
-        "subscription": subscription,
-        "partner_name": get_partner_by_id(subscription["customer_id"]).name,
-        "dry_run": False,
-        "verb": "deploy",
-        "object": "prefix_list",
-        "is_verification_workflow": "false",
-        "commit_comment": f"GSO_PROCESS_ID: {process_id} - Deploy prefix-lists for {subscription["description"]}",
-    }
-
-    return {
-        "playbook_name": "gap_ansible/playbooks/deploy_prefix_list.yaml",
-        "inventory": {"all": {"hosts": dict.fromkeys(ap_fqdn_list)}},
-        "extra_vars": extra_vars,
-    }
diff --git a/gso/workflows/l3_core_service/geant_ip/validate_prefix_list.py b/gso/workflows/l3_core_service/geant_ip/validate_prefix_list.py
index 5f259b576889bbfcb801d7b77dce71413426a9d1..ec335abd7aa3f70ac054a5d6d518893c97a4a548 100644
--- a/gso/workflows/l3_core_service/geant_ip/validate_prefix_list.py
+++ b/gso/workflows/l3_core_service/geant_ip/validate_prefix_list.py
@@ -1,19 +1,111 @@
 """Prefix Validation workflow for GÉANT IP subscription objects."""
 
+from typing import Any
+
+from orchestrator.config.assignee import Assignee
+from orchestrator.domain import SubscriptionModel
+from orchestrator.forms import SubmitFormPage
 from orchestrator.targets import Target
-from orchestrator.workflow import StepList, begin, conditional, done, workflow
+from orchestrator.workflow import StepList, begin, conditional, done, inputstep, step, workflow
 from orchestrator.workflows.steps import resync, store_process_subscription, unsync
 from orchestrator.workflows.utils import wrap_modify_initial_input_form
+from pydantic import Field
+from pydantic_forms.types import FormGenerator, State, UUIDstr
+from pydantic_forms.validators import Label
 
-from gso.services.lso_client import anonymous_lso_interaction, lso_interaction
-from gso.workflows.l3_core_service.base_validate_prefix_list import (
-    await_operator,
-    build_fqdn_list,
-    deploy_prefix_lists_dry,
-    deploy_prefix_lists_real,
-    evaluate_result_has_diff,
-    validate_prefix_lists_dry,
-)
+from gso.services.lso_client import LSOState, anonymous_lso_interaction, lso_interaction
+from gso.services.partners import get_partner_by_id
+from gso.utils.shared_enums import Vendor
+
+
+@step("Prepare list of all Access Ports")
+def build_fqdn_list(subscription_id: UUIDstr) -> State:
+    """Build the list of all FQDNs in the access ports of L3 Core Service subscription, excluding Juniper devices."""
+    subscription = SubscriptionModel.from_subscription(subscription_id)
+    ap_list = subscription.l3_core.ap_list  # type: ignore[attr-defined]
+    ap_fqdn_list = [
+        ap.sbp.edge_port.node.router_fqdn for ap in ap_list if ap.sbp.edge_port.node.vendor != Vendor.JUNIPER
+    ]
+    return {"ap_fqdn_list": ap_fqdn_list, "subscription": subscription}
+
+
+@step("[DRY RUN] Validate Prefix-Lists")
+def validate_prefix_lists_dry(subscription: dict[str, Any], process_id: UUIDstr, ap_fqdn_list: list[str]) -> LSOState:
+    """Workflow step for running a playbook that validates prefix-lists in dry run mode."""
+    extra_vars = {
+        "subscription": subscription,
+        "partner_name": get_partner_by_id(subscription["customer_id"]).name,
+        "dry_run": True,
+        "verb": "deploy",
+        "object": "prefix_list",
+        "is_verification_workflow": "true",
+        "commit_comment": f"GSO_PROCESS_ID: {process_id} - Validate prefix-lists for {subscription["description"]}",
+    }
+
+    return {
+        "playbook_name": "gap_ansible/playbooks/validate_prefix_list.yaml",
+        "inventory": {"all": {"hosts": dict.fromkeys(ap_fqdn_list)}},
+        "extra_vars": extra_vars,
+    }
+
+
+@step("Evaluate validation of Prefix-Lists")
+def evaluate_result_has_diff(callback_result: dict) -> State:
+    """Evaluate the result of the playbook that validates prefix-lists."""
+    return {"callback_result": callback_result, "prefix_list_drift": bool(callback_result["return_code"] != 0)}
+
+
+@inputstep("Await operator confirmation", assignee=Assignee.SYSTEM)
+def await_operator() -> FormGenerator:
+    """Show a form for the operator to start redeploying the prefix list that has drifted."""
+
+    class AwaitOperatorForm(SubmitFormPage):
+        info_label_a: Label = Field("A drift has been detected for this prefix list!", exclude=True)
+        info_label_b: Label = Field("Please continue this workflow to redeploy the drifted prefix list.", exclude=True)
+
+    yield AwaitOperatorForm
+
+    return {}
+
+
+@step("[DRY RUN] Deploy Prefix-Lists")
+def deploy_prefix_lists_dry(subscription: dict[str, Any], process_id: UUIDstr, ap_fqdn_list: list[str]) -> LSOState:
+    """Workflow step for running a playbook that deploys prefix-lists in dry run mode."""
+    extra_vars = {
+        "subscription": subscription,
+        "partner_name": get_partner_by_id(subscription["customer_id"]).name,
+        "dry_run": True,
+        "verb": "deploy",
+        "object": "prefix_list",
+        "is_verification_workflow": "false",
+        "commit_comment": f"GSO_PROCESS_ID: {process_id} - Deploy prefix-lists for {subscription["description"]}",
+    }
+
+    return {
+        "playbook_name": "gap_ansible/playbooks/deploy_prefix_list.yaml",
+        "inventory": {"all": {"hosts": dict.fromkeys(ap_fqdn_list)}},
+        "extra_vars": extra_vars,
+    }
+
+
+@step("[REAL] Deploy Prefix-Lists")
+def deploy_prefix_lists_real(subscription: dict[str, Any], process_id: UUIDstr, ap_fqdn_list: list[str]) -> LSOState:
+    """Workflow step for running a playbook that deploys prefix-lists."""
+    extra_vars = {
+        "subscription": subscription,
+        "partner_name": get_partner_by_id(subscription["customer_id"]).name,
+        "dry_run": False,
+        "verb": "deploy",
+        "object": "prefix_list",
+        "is_verification_workflow": "false",
+        "commit_comment": f"GSO_PROCESS_ID: {process_id} - Deploy prefix-lists for {subscription["description"]}",
+    }
+
+    return {
+        "playbook_name": "gap_ansible/playbooks/deploy_prefix_list.yaml",
+        "inventory": {"all": {"hosts": dict.fromkeys(ap_fqdn_list)}},
+        "extra_vars": extra_vars,
+    }
 
 
 @workflow(
diff --git a/gso/workflows/router/validate_router.py b/gso/workflows/router/validate_router.py
index 675def732c33824ac386713707303b5968afef9d..38f6c4b6e9269ff482abc542271ba256deb4fd62 100644
--- a/gso/workflows/router/validate_router.py
+++ b/gso/workflows/router/validate_router.py
@@ -17,7 +17,7 @@ from gso.services.librenms_client import LibreNMSClient
 from gso.services.lso_client import LSOState, anonymous_lso_interaction
 from gso.services.netbox_client import NetboxClient
 from gso.services.subscriptions import get_active_layer_3_services_on_router, get_active_vrfs_linked_to_router
-from gso.settings import load_oss_params
+from gso.settings import EnvironmentEnum, load_oss_params
 from gso.utils.helpers import generate_inventory_for_routers
 from gso.utils.shared_enums import Vendor
 
@@ -148,7 +148,7 @@ def check_kentik_entry_exists(subscription: Router) -> None:
     license on it. This is because there can be multiple, valid, non-archiving licenses for devices.
 
     Raises:
-        ProcessFailureError when a Kentik device is missing, or configured incorrectly.
+        ProcessFailureError: when a Kentik device is missing, or configured incorrectly.
     """
     client = KentikClient()
 
@@ -159,9 +159,15 @@ def check_kentik_entry_exists(subscription: Router) -> None:
             message="Device not found in Kentik", details={"device": subscription.router.router_fqdn}
         )
 
+    oss_params = load_oss_params()
+
     #  If there are active layer 3 services, check the license type. It may not be the placeholder or archiving license.
-    if bool(get_active_layer_3_services_on_router(subscription.subscription_id)):
-        kentik_params = load_oss_params().KENTIK
+    #  This check is only performed in a production environment
+    if (
+        bool(get_active_layer_3_services_on_router(subscription.subscription_id))
+        and oss_params.GENERAL.environment == EnvironmentEnum.PRODUCTION
+    ):
+        kentik_params = oss_params.KENTIK
         archive_plan = client.get_plan_by_name(kentik_params.archive_license_key)
         if any(device["device_name"] == subscription.router.router_fqdn for device in archive_plan["devices"]):
             raise ProcessFailureError(
diff --git a/setup.py b/setup.py
index 44b4f9e5879d24193991457627c9cbb5ae48e788..3bd22e6b5e166aeaee0dffad210c82f73a15cf92 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
 
 setup(
     name="geant-service-orchestrator",
-    version="3.0",
+    version="3.1",
     author="GÉANT Orchestration and Automation Team",
     author_email="goat@geant.org",
     description="GÉANT Service Orchestrator",
diff --git a/test/conftest.py b/test/conftest.py
index 2d2c1a784d6d89b546a13d4c691968f05fcb1484..076a485e2b5b868f7be7498762f6531885bec920 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -12,7 +12,7 @@ from alembic.config import Config
 from faker import Faker
 from faker.providers import BaseProvider
 from oauth2_lib.settings import oauth2lib_settings
-from orchestrator import app_settings
+from orchestrator import app_settings, step
 from orchestrator.db import (
     Database,
     ProductBlockTable,
@@ -26,7 +26,7 @@ from orchestrator.db.database import ENGINE_ARGUMENTS, SESSION_ARGUMENTS, BaseMo
 from orchestrator.domain import SUBSCRIPTION_MODEL_REGISTRY, SubscriptionModel
 from orchestrator.domain.base import ProductBlockModel
 from orchestrator.types import SubscriptionLifecycle
-from pydantic_forms.types import strEnum
+from pydantic_forms.types import UUIDstr, strEnum
 from sqlalchemy import create_engine, select, text
 from sqlalchemy.engine import make_url
 from sqlalchemy.orm import scoped_session, sessionmaker
@@ -606,3 +606,20 @@ def _no_mail(monkeypatch):
         logger.info(email)
 
     monkeypatch.setattr(gso.services.mailer, "send_mail", send_mail)
+
+
+@pytest.fixture(autouse=True)
+def _no_lso_interactions(monkeypatch):
+    """Remove all external LSO calls."""
+
+    @step("Mocked playbook execution")
+    def _execute_playbook(
+        playbook_name: str, callback_route: str, inventory: dict, extra_vars: dict, process_id: UUIDstr
+    ) -> None:
+        assert playbook_name
+        assert callback_route
+        assert inventory
+        assert extra_vars
+        assert process_id
+
+    monkeypatch.setattr(gso.services.lso_client, "_execute_playbook", _execute_playbook)
diff --git a/test/fixtures/l3_core_service_fixtures.py b/test/fixtures/l3_core_service_fixtures.py
index 04e9c175f48585a42f4c48e4687f00757ad7b0e0..d23bc42978c325220fa304782f6192841b25df7c 100644
--- a/test/fixtures/l3_core_service_fixtures.py
+++ b/test/fixtures/l3_core_service_fixtures.py
@@ -62,6 +62,7 @@ def bgp_session_subscription_factory(faker):
         has_custom_policies: bool = False,
         multipath_enabled: bool | None = True,
         prefix_limit: NonNegativeInt | None = None,
+        ttl_security: NonNegativeInt | None = None,
         send_default_route: bool | None = True,
         is_passive: bool | None = False,
         rtbh_enabled: bool | None = False,
@@ -77,6 +78,7 @@ def bgp_session_subscription_factory(faker):
             authentication_key=authentication_key or faker.password(),
             multipath_enabled=multipath_enabled,
             prefix_limit=prefix_limit,
+            ttl_security=ttl_security,
             send_default_route=send_default_route,
             is_multi_hop=is_multi_hop,
             rtbh_enabled=rtbh_enabled,
diff --git a/test/services/test_lso_client.py b/test/services/test_lso_client.py
index 2f52072a723c8656f79a2ea5abb0ee6127920cc7..78af95fc212a205f906ddb8e34d1bf5e5fec112c 100644
--- a/test/services/test_lso_client.py
+++ b/test/services/test_lso_client.py
@@ -4,7 +4,8 @@ from gso.services.lso_client import _execute_playbook
 
 
 @patch("gso.services.lso_client.requests.post")
-def test_replace_unicode_in_lso_call_success(mock_post):
+def test_replace_unicode_in_lso_call_success(mock_post, faker):
+    mocked_uuid = faker.uuid4()
     extra_vars = {
         "deployment_description": "I am going to deploy the best GÉANT service EVER!!",
         "email": "goat@géant.org",
@@ -19,10 +20,11 @@ def test_replace_unicode_in_lso_call_success(mock_post):
             "deployment_description": "I am going to deploy the best GEANT service EVER!!",
             "email": "goat@geant.org",
             "translations": {"ja": "zieantonosugoinasa-bisuwodepuroisuru"},
+            "gso_process_id": mocked_uuid,
         },
     }
 
     execute_playbook = _execute_playbook.__wrapped__
-    execute_playbook("playbook.yaml", "/api/callback_route", {}, extra_vars)
+    execute_playbook("playbook.yaml", "/api/callback_route", {}, extra_vars, mocked_uuid)
 
     mock_post.assert_called_once_with("https://localhost:44444/api/playbook", json=expected_parameters, timeout=10)
diff --git a/test/workflows/edge_port/test_create_edge_port.py b/test/workflows/edge_port/test_create_edge_port.py
index b907a4138ae89ea52c335b849edd087326775641..b73b9fe0af72b099e93e1e98b779346e11c48c61 100644
--- a/test/workflows/edge_port/test_create_edge_port.py
+++ b/test/workflows/edge_port/test_create_edge_port.py
@@ -87,9 +87,7 @@ def input_form_wizard_data(request, router_subscription_factory, partner_factory
 
 @pytest.mark.workflow()
 @pytest.mark.parametrize("router_vendor", [*Vendor.values()])
-@patch("gso.services.lso_client._send_request")
 def test_successful_edge_port_creation(
-    mock_execute_playbook,
     router_vendor,
     input_form_wizard_data,
     faker,
@@ -119,13 +117,10 @@ def test_successful_edge_port_creation(
         == f"Edge Port {initial_data[2]["name"]} on {router_fqdn}, GAAR, {subscription.edge_port.ga_id}"
     )
     assert len(subscription.edge_port.edge_port_ae_members) == 2
-    assert mock_execute_playbook.call_count == 4
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_successful_edge_port_creation_with_auto_ga_id_creation(
-    mock_execute_playbook,
     input_form_wizard_data,
     faker,
     _netbox_client_mock,  # noqa: PT019
@@ -150,7 +145,6 @@ def test_successful_edge_port_creation_with_auto_ga_id_creation(
 
     assert subscription.status == "active"
     assert subscription.edge_port.ga_id.startswith("GA-5000")
-    assert mock_execute_playbook.call_count == 4
 
 
 def test_edge_port_creation_with_invalid_input(
@@ -173,9 +167,7 @@ def test_edge_port_creation_with_invalid_input(
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_edge_port_creation_with_existing_ga_id(
-    mock_execute_playbook,
     input_form_wizard_data,
     faker,
     _netbox_client_mock,  # noqa: PT019
diff --git a/test/workflows/edge_port/test_migrate_edge_port.py b/test/workflows/edge_port/test_migrate_edge_port.py
index 821e7e82b9c8e071008c706ab736e9d164ac26be..85ab31cfc826bacd30cde8523583d46a35f56341 100644
--- a/test/workflows/edge_port/test_migrate_edge_port.py
+++ b/test/workflows/edge_port/test_migrate_edge_port.py
@@ -75,9 +75,7 @@ def input_form_wizard_data(request, router_subscription_factory, partner, faker)
 
 @pytest.mark.workflow()
 @patch("gso.tasks.start_process.start_process_task.apply_async")
-@patch("gso.services.lso_client._send_request")
 def test_successful_edge_port_migration(
-    mock_execute_playbook,
     start_process_task_apply_async,
     input_form_wizard_data,
     faker,
@@ -128,4 +126,3 @@ def test_successful_edge_port_migration(
     assert subscription.edge_port.ga_id is not None
     assert subscription.description == f"Edge Port lag-21 on {router_fqdn}, GAAR, {subscription.edge_port.ga_id}"
     assert len(subscription.edge_port.edge_port_ae_members) == 2
-    assert mock_execute_playbook.call_count == 4
diff --git a/test/workflows/edge_port/test_modify_edge_port.py b/test/workflows/edge_port/test_modify_edge_port.py
index 0d71e92cbc07513f1026bc06924c778ed4800ded..987344969177779c2b321d2a69716ce11a1c563a 100644
--- a/test/workflows/edge_port/test_modify_edge_port.py
+++ b/test/workflows/edge_port/test_modify_edge_port.py
@@ -56,7 +56,6 @@ def test_modify_edge_port_with_invalid_ga_id(
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_available_interfaces")
 @patch("gso.services.netbox_client.NetboxClient.attach_interface_to_lag")
 @patch("gso.services.netbox_client.NetboxClient.reserve_interface")
@@ -72,7 +71,6 @@ def test_modify_edge_port_with_changing_capacity(
     mocked_reserve_interface,
     mocked_attach_interface_to_lag,
     mocked_get_available_interfaces,
-    mocked_execute_playbook,
     input_form_wizard_data,
     faker,
 ):
@@ -99,7 +97,6 @@ def test_modify_edge_port_with_changing_capacity(
     subscription = EdgePort.from_subscription(subscription_id)
 
     assert subscription.status == "active"
-    assert mocked_execute_playbook.call_count == 2
 
     # The number of members have been changed from 2 to 1
     assert mocked_reserve_interface.call_count == 1
@@ -132,7 +129,6 @@ def input_form_wizard_without_changing_capacity(request, faker, edge_port_subscr
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_available_interfaces")
 @patch("gso.services.netbox_client.NetboxClient.attach_interface_to_lag")
 @patch("gso.services.netbox_client.NetboxClient.reserve_interface")
@@ -148,7 +144,6 @@ def test_modify_edge_port_without_changing_capacity(
     mocked_reserve_interface,
     mocked_attach_interface_to_lag,
     mocked_get_available_interfaces,
-    mocked_execute_playbook,
     input_form_wizard_without_changing_capacity,
     faker,
 ):
@@ -173,7 +168,6 @@ def test_modify_edge_port_without_changing_capacity(
     assert subscription.status == "active"
 
     # The capacity has not been changed so the following methods should not be called
-    assert mocked_execute_playbook.call_count == 0
     assert mocked_reserve_interface.call_count == 0
     assert mocked_attach_interface_to_lag.call_count == 0
     assert mocked_free_interface.call_count == 0
diff --git a/test/workflows/edge_port/test_terminate_edge_port.py b/test/workflows/edge_port/test_terminate_edge_port.py
index 58c7d087208913006c52988d4b7cbf87330ff033..d399dd377d04093e4ebf208219cc00b43a623c6d 100644
--- a/test/workflows/edge_port/test_terminate_edge_port.py
+++ b/test/workflows/edge_port/test_terminate_edge_port.py
@@ -13,13 +13,11 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.delete_interface")
 @patch("gso.services.netbox_client.NetboxClient.free_interface")
 def test_successful_edge_port_termination(
     mocked_free_interface,
     mocked_delete_interface,
-    mock_execute_playbook,
     edge_port_subscription_factory,
     faker,
 ):
@@ -52,4 +50,3 @@ def test_successful_edge_port_termination(
     subscription = EdgePort.from_subscription(subscription_id)
 
     assert subscription.status == "terminated"
-    assert mock_execute_playbook.call_count == 2
diff --git a/test/workflows/edge_port/test_validate_edge_port.py b/test/workflows/edge_port/test_validate_edge_port.py
index d6ce39e05b49f5017a10364961191fd6a24486e9..92ee9454d08fc55520c20837c20c03e22298c6a6 100644
--- a/test/workflows/edge_port/test_validate_edge_port.py
+++ b/test/workflows/edge_port/test_validate_edge_port.py
@@ -13,11 +13,9 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_interface_by_name_and_device")
 def test_validate_edge_port_success(
     mock_get_interface_by_name_and_device,
-    mock_execute_playbook,
     edge_port_subscription_factory,
     faker,
 ):
@@ -56,6 +54,6 @@ def test_validate_edge_port_success(
     assert_complete(result)
     subscription = EdgePort.from_subscription(subscription_id)
     assert subscription.status == "active"
-    assert mock_execute_playbook.call_count == 1
+
     # One time for getting the LAG and two times for getting the interfaces
     assert mock_get_interface_by_name_and_device.call_count == 3
diff --git a/test/workflows/iptrunk/test_create_iptrunk.py b/test/workflows/iptrunk/test_create_iptrunk.py
index 861c6d325cd878ccb8d2624561f6e426d270117d..95522cfe16af44c6b135d3cb509b9b33f29e0e07 100644
--- a/test/workflows/iptrunk/test_create_iptrunk.py
+++ b/test/workflows/iptrunk/test_create_iptrunk.py
@@ -100,7 +100,6 @@ def input_form_wizard_data(request, router_subscription_factory, faker):
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v6_network")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v4_network")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.create_host_by_ip")
@@ -114,7 +113,6 @@ def test_successful_iptrunk_creation_with_standard_lso_result(
     mock_create_host,
     mock_allocate_v4_network,
     mock_allocate_v6_network,
-    mock_execute_playbook,
     input_form_wizard_data,
     faker,
     _netbox_client_mock,  # noqa: PT019
@@ -154,14 +152,12 @@ def test_successful_iptrunk_creation_with_standard_lso_result(
         f"{subscription.iptrunk.gs_id}"
     )
 
-    assert mock_execute_playbook.call_count == 6
     #  We search for 6 hosts in total, 2 in a /31 and 4 in a /126
     assert mock_find_host_by_ip.call_count == 6
     assert mock_ping.call_count == 6
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v6_network")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v4_network")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.find_host_by_ip")
@@ -171,7 +167,6 @@ def test_iptrunk_creation_fails_when_lso_return_code_is_one(
     mock_find_host_by_ip,
     mock_allocate_v4_network,
     mock_allocate_v6_network,
-    mock_execute_playbook,
     input_form_wizard_data,
     faker,
     _netbox_client_mock,  # noqa: PT019
@@ -189,14 +184,12 @@ def test_iptrunk_creation_fails_when_lso_return_code_is_one(
 
     assert_lso_interaction_failure(result, process_stat, step_log)
 
-    assert mock_execute_playbook.call_count == 2
     assert mock_find_host_by_ip.call_count == 6
     assert mock_ping.call_count == 6
 
 
 @pytest.mark.parametrize("input_form_wizard_data", [Vendor.JUNIPER], indirect=True)
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v6_network")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.allocate_v4_network")
 @patch("gso.workflows.iptrunk.create_iptrunk.infoblox.create_host_by_ip")
@@ -210,7 +203,6 @@ def test_successful_iptrunk_creation_with_juniper_interface_names(
     mock_create_host,
     mock_allocate_v4_network,
     mock_allocate_v6_network,
-    mock_execute_playbook,
     input_form_wizard_data,
     faker,
     _netbox_client_mock,  # noqa: PT019
@@ -233,7 +225,7 @@ def test_successful_iptrunk_creation_with_juniper_interface_names(
     result, step_log = resume_suspended_workflow(result, process_stat, step_log, input_data=USER_CONFIRM_EMPTY_FORM)
 
     assert_complete(result)
-    assert mock_execute_playbook.call_count == 6
+
     assert mock_find_host_by_ip.call_count == 6
     assert mock_ping.call_count == 6
 
diff --git a/test/workflows/iptrunk/test_deploy_twamp.py b/test/workflows/iptrunk/test_deploy_twamp.py
index 7791940fc60458a6c9eadb3e5c5fef0125c2dd5a..d43d213d971d9e7a90f7aff08d69bf9fcbaf04de 100644
--- a/test/workflows/iptrunk/test_deploy_twamp.py
+++ b/test/workflows/iptrunk/test_deploy_twamp.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 
 from gso.products.product_types.iptrunk import Iptrunk
@@ -12,9 +10,7 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_iptrunk_deploy_twamp_success(
-    mock_execute_playbook,
     iptrunk_subscription_factory,
     faker,
 ):
@@ -35,4 +31,3 @@ def test_iptrunk_deploy_twamp_success(
     subscription = Iptrunk.from_subscription(subscription_id)
 
     assert subscription.status == "active"
-    assert mock_execute_playbook.call_count == 3
diff --git a/test/workflows/iptrunk/test_migrate_iptrunk.py b/test/workflows/iptrunk/test_migrate_iptrunk.py
index 8054dfba1b9341dd41dad2ec47dae8c7661a79e8..d2bd637b248bdda453d6a1f68685562a4dcacf7c 100644
--- a/test/workflows/iptrunk/test_migrate_iptrunk.py
+++ b/test/workflows/iptrunk/test_migrate_iptrunk.py
@@ -111,7 +111,6 @@ def interface_lists_are_equal(list1, list2):
 @pytest.mark.workflow()
 @patch("gso.services.infoblox.create_host_by_ip")
 @patch("gso.services.infoblox.delete_host_by_ip")
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_available_interfaces")
 @patch("gso.services.netbox_client.NetboxClient.get_available_lags")
 @patch("gso.services.netbox_client.NetboxClient.create_interface")
@@ -131,7 +130,6 @@ def test_migrate_iptrunk_success(  # noqa: PLR0915
     mocked_create_interface,
     mocked_get_available_lags,
     mocked_get_available_interfaces,
-    mock_execute_playbook,
     mock_delete_host_by_ip,
     mock_create_host_by_ip,
     migrate_form_input,
@@ -180,7 +178,7 @@ def test_migrate_iptrunk_success(  # noqa: PLR0915
     subscription = Iptrunk.from_subscription(subscription_id)
 
     assert subscription.status == "active"
-    assert mock_execute_playbook.call_count == (17 if restore_isis_metric else 16)
+
     assert mock_create_host_by_ip.call_count == 1
     assert mock_delete_host_by_ip.call_count == 1
 
diff --git a/test/workflows/iptrunk/test_modify_isis_metric.py b/test/workflows/iptrunk/test_modify_isis_metric.py
index 551ab0c2628e144013376093353babf2f8f6221d..6b1bc416c72cce9b68a3fbeff763511c781a24da 100644
--- a/test/workflows/iptrunk/test_modify_isis_metric.py
+++ b/test/workflows/iptrunk/test_modify_isis_metric.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 
 from gso.products.product_types.iptrunk import Iptrunk
@@ -12,9 +10,7 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_iptrunk_modify_isis_metric_success(
-    mock_provision_ip_trunk,
     iptrunk_subscription_factory,
     faker,
 ):
@@ -40,5 +36,4 @@ def test_iptrunk_modify_isis_metric_success(
     subscription = Iptrunk.from_subscription(subscription_id)
 
     assert subscription.status == "active"
-    assert mock_provision_ip_trunk.call_count == 2
     assert subscription.iptrunk.iptrunk_isis_metric == new_isis_metric
diff --git a/test/workflows/iptrunk/test_modify_trunk_interface.py b/test/workflows/iptrunk/test_modify_trunk_interface.py
index e636c2cc3db61f6b4adf5041f7c125a21b42ef70..4b0f2577208fc5b001dbc2fa90865596445a7be1 100644
--- a/test/workflows/iptrunk/test_modify_trunk_interface.py
+++ b/test/workflows/iptrunk/test_modify_trunk_interface.py
@@ -92,7 +92,6 @@ def input_form_iptrunk_data(
     indirect=True,
 )
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_available_interfaces")
 @patch("gso.services.netbox_client.NetboxClient.attach_interface_to_lag")
 @patch("gso.services.netbox_client.NetboxClient.reserve_interface")
@@ -106,7 +105,6 @@ def test_iptrunk_modify_trunk_interface_success(
     mocked_reserve_interface,
     mocked_attach_interface_to_lag,
     mocked_get_available_interfaces,
-    mock_provision_ip_trunk,
     input_form_iptrunk_data,
     faker,
 ):
@@ -134,7 +132,6 @@ def test_iptrunk_modify_trunk_interface_success(
     subscription = Iptrunk.from_subscription(subscription_id)
 
     assert subscription.status == "active"
-    assert mock_provision_ip_trunk.call_count == lso_interaction_count
     # Assert all Netbox calls have been made
     new_sid = input_form_iptrunk_data[1]["gs_id"]
     new_side_a_gid = input_form_iptrunk_data[3]["side_a_ga_id"]
diff --git a/test/workflows/iptrunk/test_terminate_iptrunk.py b/test/workflows/iptrunk/test_terminate_iptrunk.py
index 14c6c5298d16e58b1dba9f9b97570d56af2e9120..6ce271a1a03e8c273b7ea196b29348f44c332072 100644
--- a/test/workflows/iptrunk/test_terminate_iptrunk.py
+++ b/test/workflows/iptrunk/test_terminate_iptrunk.py
@@ -15,7 +15,6 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.iptrunk.terminate_iptrunk.infoblox.delete_network")
 @patch("gso.services.netbox_client.NetboxClient.delete_interface")
 @patch("gso.services.netbox_client.NetboxClient.free_interface")
@@ -23,7 +22,6 @@ def test_successful_iptrunk_termination(
     mocked_free_interface,
     mocked_delete_interface,
     mock_infoblox_delete_network,
-    mock_execute_playbook,
     iptrunk_subscription_factory,
     faker,
     router_subscription_factory,
@@ -62,6 +60,6 @@ def test_successful_iptrunk_termination(
     subscription = Iptrunk.from_subscription(subscription_id)
 
     assert subscription.status == "terminated"
-    assert mock_execute_playbook.call_count == 3
+
     assert mock_infoblox_delete_network.call_count == 2
     assert subscription.iptrunk.iptrunk_isis_metric == oss_params.GENERAL.isis_high_metric
diff --git a/test/workflows/iptrunk/test_validate_iptrunk.py b/test/workflows/iptrunk/test_validate_iptrunk.py
index a6460cb3a59a823f5812d0fcf71120db907edd5f..e192980e779f08c3cac71abbc1c6298f51b76932 100644
--- a/test/workflows/iptrunk/test_validate_iptrunk.py
+++ b/test/workflows/iptrunk/test_validate_iptrunk.py
@@ -45,11 +45,9 @@ def _mocked_netbox_client():
 @patch("gso.services.infoblox.find_network_by_cidr")
 @patch("gso.services.infoblox.find_v6_host_by_fqdn")
 @patch("gso.services.infoblox.find_host_by_fqdn")
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_interface_by_name_and_device")
 def test_validate_iptrunk_success(
     mock_get_interface_by_name,
-    mock_validate_iptrunk,
     mock_find_host_by_fqdn,
     mock_find_v6_host_by_fqdn,
     mock_find_network_by_cidr,
@@ -191,7 +189,6 @@ def test_validate_iptrunk_success(
     subscription = Iptrunk.from_subscription(subscription_id)
 
     assert subscription.status == subscription_status
-    assert mock_validate_iptrunk.call_count == 3
     assert mock_find_host_by_fqdn.call_count == 2
     assert mock_find_v6_host_by_fqdn.call_count == 2
     assert mock_find_network_by_cidr.call_count == 2
@@ -203,11 +200,9 @@ def test_validate_iptrunk_success(
 @patch("gso.services.infoblox.find_network_by_cidr")
 @patch("gso.services.infoblox.find_v6_host_by_fqdn")
 @patch("gso.services.infoblox.find_host_by_fqdn")
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_interface_by_name_and_device")
 def test_validate_iptrunk_skip_legacy_trunks(
     mock_get_interface_by_name,
-    mock_validate_iptrunk,
     mock_find_host_by_fqdn,
     mock_find_v6_host_by_fqdn,
     mock_find_network_by_cidr,
@@ -235,7 +230,6 @@ def test_validate_iptrunk_skip_legacy_trunks(
 
     assert subscription.status == subscription_status
     assert mock_get_interface_by_name.call_count == 0
-    assert mock_validate_iptrunk.call_count == 0
     assert mock_find_host_by_fqdn.call_count == 0
     assert mock_find_v6_host_by_fqdn.call_count == 0
     assert mock_find_network_by_cidr.call_count == 0
diff --git a/test/workflows/l2_circuit/test_create_layer_2_circuit.py b/test/workflows/l2_circuit/test_create_layer_2_circuit.py
index 4d282f6f73f5f2df113a069c75a2f3126773c2d6..b892b5df4cd8dfeaf466b8fb4ddb2d04e675c271 100644
--- a/test/workflows/l2_circuit/test_create_layer_2_circuit.py
+++ b/test/workflows/l2_circuit/test_create_layer_2_circuit.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 from orchestrator.types import SubscriptionLifecycle
 
@@ -60,9 +58,7 @@ def layer_2_circuit_ethernet_input(
 
 @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES)
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_create_layer_2_circuit_success(
-    mock_lso_interaction,
     layer_2_circuit_service_type,
     layer_2_circuit_input,
     faker,
@@ -76,7 +72,7 @@ def test_create_layer_2_circuit_success(
     assert_complete(result)
     state = extract_state(result)
     subscription = Layer2Circuit.from_subscription(state["subscription_id"])
-    assert mock_lso_interaction.call_count == 2
+
     assert subscription.status == SubscriptionLifecycle.ACTIVE
     assert subscription.layer_2_circuit.virtual_circuit_id is not None
     assert len(subscription.layer_2_circuit.layer_2_circuit_sides) == 2
@@ -113,9 +109,7 @@ def test_create_layer_2_circuit_success(
 
 @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES)
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_create_layer_2_circuit_with_ethernet_type(
-    mock_lso_interaction,
     layer_2_circuit_service_type,
     layer_2_circuit_ethernet_input,
     faker,
@@ -129,7 +123,7 @@ def test_create_layer_2_circuit_with_ethernet_type(
     assert_complete(result)
     state = extract_state(result)
     subscription = Layer2Circuit.from_subscription(state["subscription_id"])
-    assert mock_lso_interaction.call_count == 2
+
     assert subscription.status == SubscriptionLifecycle.ACTIVE
     assert subscription.layer_2_circuit.virtual_circuit_id is not None
     assert len(subscription.layer_2_circuit.layer_2_circuit_sides) == 2
diff --git a/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py b/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py
index a0f05946cde87647941cb5421af0399a30ce0e47..7b66d9b3afd8fe186de844f1a5f89f0c591d9118 100644
--- a/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py
+++ b/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 
 from gso.products.product_types.edge_port import EdgePort
@@ -13,9 +11,7 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr
 @pytest.mark.parametrize("run_old_side_ansible", [False, True])
 @pytest.mark.parametrize("run_new_side_ansible", [False, True])
 @pytest.mark.parametrize("generate_new_vc_id", [False, True])
-@patch("gso.services.lso_client._send_request")
 def test_migrate_layer_2_circuit(
-    mock_lso_interaction,
     generate_new_vc_id,
     run_new_side_ansible,
     run_old_side_ansible,
@@ -64,7 +60,6 @@ def test_migrate_layer_2_circuit(
     subscription_id = state["subscription_id"]
     subscription = Layer2Circuit.from_subscription(subscription_id)
     assert subscription.status == "active"
-    assert mock_lso_interaction.call_count == lso_step_count
 
     replaced_edge_port = subscription.layer_2_circuit.layer_2_circuit_sides[1].sbp.edge_port
     assert replaced_edge_port.model_dump(exclude="edge_port_ae_members") == new_edge_port.edge_port.model_dump(
diff --git a/test/workflows/l2_circuit/test_modify_layer_2_circuit.py b/test/workflows/l2_circuit/test_modify_layer_2_circuit.py
index e4f4dcce33efeabe2dac11c54a41b014577ab0de..7637efc200f697236ecdc7e2931849b32ab28014 100644
--- a/test/workflows/l2_circuit/test_modify_layer_2_circuit.py
+++ b/test/workflows/l2_circuit/test_modify_layer_2_circuit.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 from orchestrator.types import SubscriptionLifecycle
 
@@ -11,9 +9,7 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr
 @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES)
 @pytest.mark.parametrize("run_ansible_steps", [False, True])
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_modify_layer_2_circuit_change_policer_bandwidth(
-    mock_lso_interaction,
     layer_2_circuit_service_type,
     run_ansible_steps,
     layer_2_circuit_subscription_factory,
@@ -48,7 +44,7 @@ def test_modify_layer_2_circuit_change_policer_bandwidth(
 
     subscription = Layer2Circuit.from_subscription(str(subscription.subscription_id))
     assert_complete(result)
-    assert mock_lso_interaction.call_count == lso_step_count
+
     assert subscription.status == SubscriptionLifecycle.ACTIVE
     assert subscription.layer_2_circuit.policer_enabled is False
     assert subscription.layer_2_circuit.bandwidth is None
@@ -70,9 +66,7 @@ def test_modify_layer_2_circuit_change_policer_bandwidth(
 @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES)
 @pytest.mark.parametrize("run_ansible_steps", [False, True])
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_modify_layer_2_circuit_change_circuit_type(
-    mock_lso_interaction,
     layer_2_circuit_service_type,
     run_ansible_steps,
     layer_2_circuit_subscription_factory,
@@ -105,7 +99,7 @@ def test_modify_layer_2_circuit_change_circuit_type(
     assert_complete(result)
     state = extract_state(result)
     subscription = Layer2Circuit.from_subscription(state["subscription_id"])
-    assert mock_lso_interaction.call_count == lso_step_count
+
     assert subscription.status == SubscriptionLifecycle.ACTIVE
     assert subscription.layer_2_circuit.vlan_range_lower_bound is None
     assert subscription.layer_2_circuit.vlan_range_upper_bound is None
diff --git a/test/workflows/l2_circuit/test_terminate_layer_2_circuit.py b/test/workflows/l2_circuit/test_terminate_layer_2_circuit.py
index 55deedededc9c3c43ef3ca56d6145508cbf7f5d4..eba60dafc6940d270f145585ea9a04b4086b54ac 100644
--- a/test/workflows/l2_circuit/test_terminate_layer_2_circuit.py
+++ b/test/workflows/l2_circuit/test_terminate_layer_2_circuit.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 
 from gso.products.product_types.layer_2_circuit import LAYER_2_CIRCUIT_SERVICE_TYPES, Layer2Circuit
@@ -9,9 +7,8 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr
 @pytest.mark.workflow()
 @pytest.mark.parametrize("layer_2_circuit_service_type", LAYER_2_CIRCUIT_SERVICE_TYPES)
 @pytest.mark.parametrize("run_ansible_steps", [True, False])
-@patch("gso.services.lso_client._send_request")
 def test_terminate_layer_2_circuit(
-    mock_lso_interaction, layer_2_circuit_service_type, run_ansible_steps, layer_2_circuit_subscription_factory, faker
+    layer_2_circuit_service_type, run_ansible_steps, layer_2_circuit_subscription_factory, faker
 ):
     subscription_id = str(
         layer_2_circuit_subscription_factory(layer_2_circuit_service_type=layer_2_circuit_service_type).subscription_id
@@ -33,4 +30,3 @@ def test_terminate_layer_2_circuit(
     subscription_id = state["subscription_id"]
     subscription = Layer2Circuit.from_subscription(subscription_id)
     assert subscription.status == "terminated"
-    assert mock_lso_interaction.call_count == lso_step_count
diff --git a/test/workflows/l3_core_service/test_create_l3_core_service.py b/test/workflows/l3_core_service/test_create_l3_core_service.py
index 20d307f4977b83c011b77e88e2b24eca8cf57de9..a8ee5bc6a27b090acfaf936010999fc8ab0be7fe 100644
--- a/test/workflows/l3_core_service/test_create_l3_core_service.py
+++ b/test/workflows/l3_core_service/test_create_l3_core_service.py
@@ -39,11 +39,9 @@ def base_bgp_peer_input(faker):
 
 @pytest.mark.parametrize("product_name", L3_PRODUCT_NAMES)
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.l3_core_service.base_create_l3_core_service.SharePointClient")
 def test_create_l3_core_service_success(
     mock_sharepoint_client,
-    mock_lso_client,
     product_name,
     faker,
     partner_factory,
@@ -108,7 +106,6 @@ def test_create_l3_core_service_success(
     subscription = SubscriptionModel.from_subscription(state["subscription_id"])
 
     assert subscription.product.name == product_name
-    assert mock_lso_client.call_count == lso_interaction_count + 1
     assert subscription.status == SubscriptionLifecycle.ACTIVE
     assert len(subscription.l3_core.ap_list) == 1
     assert (
diff --git a/test/workflows/l3_core_service/test_migrate_l3_core_service.py b/test/workflows/l3_core_service/test_migrate_l3_core_service.py
index 18c5682e777ccef18fc95e3a235b829e9814c7e6..eb1b292a90b769ffd091e1d677a91df16518803f 100644
--- a/test/workflows/l3_core_service/test_migrate_l3_core_service.py
+++ b/test/workflows/l3_core_service/test_migrate_l3_core_service.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 from orchestrator.domain import SubscriptionModel
 
@@ -19,9 +17,7 @@ from test.workflows import (
 
 @pytest.mark.workflow()
 @pytest.mark.parametrize("product_name", L3_PRODUCT_NAMES)
-@patch("gso.services.lso_client._send_request")
 def test_migrate_l3_core_service_success(
-    mock_execute_playbook,
     faker,
     edge_port_subscription_factory,
     partner_factory,
@@ -62,7 +58,7 @@ def test_migrate_l3_core_service_success(
     assert_complete(result)
     state = extract_state(result)
     subscription = SubscriptionModel.from_subscription(state["subscription_id"])
-    assert mock_execute_playbook.call_count == 11
+
     assert subscription.insync
     assert len(subscription.l3_core.ap_list) == 1
     assert str(subscription.l3_core.ap_list[0].sbp.edge_port.owner_subscription_id) == destination_edge_port
@@ -70,9 +66,7 @@ def test_migrate_l3_core_service_success(
 
 @pytest.mark.workflow()
 @pytest.mark.parametrize("product_name", L3_PRODUCT_NAMES)
-@patch("gso.services.lso_client._send_request")
 def test_migrate_l3_core_service_scoped_emission(
-    mock_execute_playbook,
     faker,
     edge_port_subscription_factory,
     access_port_factory,
@@ -139,7 +133,7 @@ def test_migrate_l3_core_service_scoped_emission(
     assert_complete(result)
     state = extract_state(result)
     subscription = SubscriptionModel.from_subscription(state["subscription_id"])
-    assert mock_execute_playbook.call_count == 11
+
     assert subscription.insync
     ap_list = subscription.l3_core.ap_list
     assert len(ap_list) == 5
diff --git a/test/workflows/l3_core_service/test_modify_l3_core_service.py b/test/workflows/l3_core_service/test_modify_l3_core_service.py
index 0b2a9f3f9377b3c2513f8db551d5c45fd860677c..93f8680b68dc20273030535499364f8a5a0e121f 100644
--- a/test/workflows/l3_core_service/test_modify_l3_core_service.py
+++ b/test/workflows/l3_core_service/test_modify_l3_core_service.py
@@ -68,7 +68,8 @@ def test_modify_l3_core_service_add_new_edge_port_success(
                 "authentication_key": faker.password(),
                 "peer_address": faker.ipv4(),
                 "bfd_enabled": False,
-                "prefix_limit": 1000,
+                "prefix_limit": faker.random_int(min=500, max=1000),
+                "ttl_security": faker.random_int(max=255),
             },
             "v6_bgp_peer": {
                 "authentication_key": faker.password(),
@@ -142,7 +143,8 @@ def sbp_input_form_data(faker):
             "v6_bgp_is_passive": True,
             "v6_bgp_peer_address": faker.ipv6(),
             "v6_bgp_add_v6_multicast": True,
-            "v6_bgp_prefix_limit": 3000,
+            "v6_bgp_prefix_limit": faker.random_int(min=2500, max=3000),
+            "v6_bgp_ttl_security": faker.random_int(max=255),
         }
 
     return _generate_form_data
diff --git a/test/workflows/l3_core_service/test_validate_l3_core_service.py b/test/workflows/l3_core_service/test_validate_l3_core_service.py
index ad6a06ca2ebf68737ca0e8a84173782a5d3f2caa..60192558b2d603895c765fb546c672a1b58b3648 100644
--- a/test/workflows/l3_core_service/test_validate_l3_core_service.py
+++ b/test/workflows/l3_core_service/test_validate_l3_core_service.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 from orchestrator.domain import SubscriptionModel
 
@@ -8,9 +6,8 @@ from test.workflows import assert_complete, assert_lso_success, extract_state, r
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @pytest.mark.parametrize("product_name", L3_PRODUCT_NAMES)
-def test_validate_l3_core_service(mock_lso_interaction, l3_core_service_subscription_factory, faker, product_name):
+def test_validate_l3_core_service(l3_core_service_subscription_factory, faker, product_name):
     subscription_id = str(l3_core_service_subscription_factory(product_name=product_name).subscription_id)
     initial_l3_core_service_data = [{"subscription_id": subscription_id}]
     result, process_stat, step_log = run_workflow(L3_VALIDATION_WF_MAP[product_name], initial_l3_core_service_data)
@@ -23,4 +20,3 @@ def test_validate_l3_core_service(mock_lso_interaction, l3_core_service_subscrip
     subscription = SubscriptionModel.from_subscription(subscription_id)
     assert subscription.status == "active"
     assert subscription.insync is True
-    assert mock_lso_interaction.call_count == 2
diff --git a/test/workflows/l3_core_service/test_validate_prefix_list.py b/test/workflows/l3_core_service/test_validate_prefix_list.py
index a2baecb6839c73125d52da4eda76ac84f9c4e389..42e945200def7af9a56e1fbe5e6c2b0326fd22bc 100644
--- a/test/workflows/l3_core_service/test_validate_prefix_list.py
+++ b/test/workflows/l3_core_service/test_validate_prefix_list.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 
 from gso.products.product_types.geant_ip import GeantIP
@@ -18,8 +16,7 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
-def test_validate_prefix_list_success(mock_lso_interaction, geant_ip_subscription_factory, faker):
+def test_validate_prefix_list_success(geant_ip_subscription_factory, faker):
     subscription_id = str(geant_ip_subscription_factory().subscription_id)
     initial_l3_core_service_data = [{"subscription_id": subscription_id}]
     # Run the workflow and extract results
@@ -36,13 +33,10 @@ def test_validate_prefix_list_success(mock_lso_interaction, geant_ip_subscriptio
     # Verify the subscription has no Juniper devices
     for ap in subscription.geant_ip.l3_core.ap_list:
         assert ap.sbp.edge_port.node.vendor != Vendor.JUNIPER
-    # Verify the number of LSO interactions
-    assert mock_lso_interaction.call_count == 1
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
-def test_validate_prefix_list_with_diff(mock_lso_interaction, geant_ip_subscription_factory, faker):
+def test_validate_prefix_list_with_diff(geant_ip_subscription_factory, faker):
     """Test case where playbook_has_diff qualifies and additional steps are executed."""
     subscription_id = str(geant_ip_subscription_factory().subscription_id)
     initial_l3_core_service_data = [{"subscription_id": subscription_id}]
@@ -68,13 +62,10 @@ def test_validate_prefix_list_with_diff(mock_lso_interaction, geant_ip_subscript
     subscription = GeantIP.from_subscription(subscription_id)
     assert subscription.status == "active"
     assert subscription.insync is True
-    # Verify the number of LSO interactions
-    assert mock_lso_interaction.call_count == 3  # One for validation and two for deployment
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
-def test_validate_prefix_list_without_diff(mock_lso_interaction, geant_ip_subscription_factory, faker):
+def test_validate_prefix_list_without_diff(geant_ip_subscription_factory, faker):
     """Test case where playbook_has_diff does not qualify and skips additional steps."""
     subscription_id = str(geant_ip_subscription_factory().subscription_id)
     initial_l3_core_service_data = [{"subscription_id": subscription_id}]
@@ -89,8 +80,6 @@ def test_validate_prefix_list_without_diff(mock_lso_interaction, geant_ip_subscr
     subscription = GeantIP.from_subscription(subscription_id)
     assert subscription.status == "active"
     assert subscription.insync is True
-    # Verify the number of LSO interactions
-    assert mock_lso_interaction.call_count == 1  # Only validation is performed
 
 
 @pytest.mark.workflow()
diff --git a/test/workflows/lan_switch_interconnect/test_validate_lan_switch_interconnect.py b/test/workflows/lan_switch_interconnect/test_validate_lan_switch_interconnect.py
index 18e67d17117179eee6ec25083af2f90b7688b534..db180c7d57de409b0d58dd43539a19f5cb5fd297 100644
--- a/test/workflows/lan_switch_interconnect/test_validate_lan_switch_interconnect.py
+++ b/test/workflows/lan_switch_interconnect/test_validate_lan_switch_interconnect.py
@@ -10,9 +10,8 @@ from test.workflows import assert_complete, assert_lso_success, extract_state, r
 @pytest.mark.workflow()
 @patch("gso.services.infoblox.find_host_by_fqdn")
 @patch("gso.services.infoblox.find_network_by_cidr")
-@patch("gso.services.lso_client._send_request")
 def test_validate_lan_switch_interconnect(
-    mock_lso_interaction, mock_find_network, mock_find_host, lan_switch_interconnect_subscription_factory, faker
+    mock_find_network, mock_find_host, lan_switch_interconnect_subscription_factory, faker
 ):
     subscription_id = str(lan_switch_interconnect_subscription_factory().subscription_id)
     mocked_netbox_reply = objects.HostRecord(
diff --git a/test/workflows/router/test_create_router.py b/test/workflows/router/test_create_router.py
index 67d317b1e7632111dc5c897ea2da08cd803e9bc9..8300a42bd9572dfe80b507ada904ce8825b3e4a2 100644
--- a/test/workflows/router/test_create_router.py
+++ b/test/workflows/router/test_create_router.py
@@ -38,7 +38,6 @@ def router_creation_input_form_data(site_subscription_factory, faker):
 
 @pytest.mark.workflow()
 @pytest.mark.parametrize("router_role", [RouterRole.P, RouterRole.PE])
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.router.create_router.NetboxClient.create_device")
 @patch("gso.workflows.router.create_router.infoblox.hostname_available")
 @patch("gso.workflows.router.create_router.infoblox.find_host_by_fqdn")
@@ -52,7 +51,6 @@ def test_create_nokia_router_success(
     mock_find_host_by_fqdn,
     mock_hostname_available,
     mock_netbox_create_device,
-    mock_provision_router,
     router_creation_input_form_data,
     router_role,
     faker,
@@ -113,7 +111,6 @@ def test_create_nokia_router_success(
     assert subscription.status == "provisioning"
     assert subscription.description == f"Router {mock_fqdn}"
 
-    assert mock_provision_router.call_count == 3
     assert mock_netbox_create_device.call_count == 1
     assert mock_find_host_by_fqdn.call_count == 1
     assert mock_sharepoint_client.call_count == 1
@@ -122,7 +119,6 @@ def test_create_nokia_router_success(
 
 @pytest.mark.workflow()
 @pytest.mark.parametrize("router_role", [RouterRole.P, RouterRole.PE])
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.router.create_router.NetboxClient.create_device")
 @patch("gso.workflows.router.create_router.infoblox.hostname_available")
 @patch("gso.workflows.router.create_router.infoblox.find_network_by_cidr")
@@ -140,7 +136,6 @@ def test_create_nokia_router_lso_failure(
     mock_find_network_by_cidr,
     mock_hostname_available,
     mock_netbox_create_device,
-    mock_provision_router,
     router_creation_input_form_data,
     router_role,
     faker,
@@ -198,7 +193,6 @@ def test_create_nokia_router_lso_failure(
     assert subscription.status == "initial"
     assert subscription.description == f"Router {mock_fqdn}"
 
-    assert mock_provision_router.call_count == 2
     assert mock_netbox_create_device.call_count == 0
     assert mock_find_host_by_fqdn.call_count == 0
     assert mock_find_network_by_cidr.call_count == 0
diff --git a/test/workflows/router/test_promote_p_to_pe.py b/test/workflows/router/test_promote_p_to_pe.py
index 46ab40b7fa7215de2b94bbfd3980c5bea0506268..3b510b36024075a0f6c82568eb9c290c5db20319 100644
--- a/test/workflows/router/test_promote_p_to_pe.py
+++ b/test/workflows/router/test_promote_p_to_pe.py
@@ -18,11 +18,9 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.utils.workflow_steps.KentikClient")
 def test_promote_p_to_pe_success(
     mock_kentik_client,
-    mock_execute_playbook,
     router_subscription_factory,
     faker,
 ):
@@ -45,7 +43,7 @@ def test_promote_p_to_pe_success(
         result, step_log = assert_lso_interaction_success(result, process_stat, step_log)
     state = extract_state(result)
     assert_complete(result)
-    assert mock_execute_playbook.call_count == 24
+
     assert state["subscription"]["router"]["router_role"] == RouterRole.PE
 
 
@@ -66,8 +64,7 @@ def test_promote_p_to_pe_juniper_router(router_subscription_factory, faker):
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
-def test_promote_p_to_pe_nokia_pe_router(mock_execute_playbook, router_subscription_factory, faker):
+def test_promote_p_to_pe_nokia_pe_router(router_subscription_factory, faker):
     """Test that the workflow does not run for a Nokia PE router since it is already a PE router."""
     router_id = str(
         router_subscription_factory(
diff --git a/test/workflows/router/test_redeploy_base_config.py b/test/workflows/router/test_redeploy_base_config.py
index 5106c59aa98105115434625dd3fe1a75bf4bc7a5..4dee5a5e9d18ed93cc08812f85f256db5174688c 100644
--- a/test/workflows/router/test_redeploy_base_config.py
+++ b/test/workflows/router/test_redeploy_base_config.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 
 from gso.products.product_types.router import Router
@@ -12,9 +10,7 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 def test_redeploy_base_config_success(
-    mock_provision_router,
     router_subscription_factory,
     faker,
 ):
@@ -35,4 +31,3 @@ def test_redeploy_base_config_success(
     subscription = Router.from_subscription(subscription_id)
 
     assert subscription.status == "active"
-    assert mock_provision_router.call_count == 2
diff --git a/test/workflows/router/test_terminate_router.py b/test/workflows/router/test_terminate_router.py
index a760472efae75808a1a613d031eafb1494e1e18f..a7303181ecbf3ab50106ed9627f539e96b1add6f 100644
--- a/test/workflows/router/test_terminate_router.py
+++ b/test/workflows/router/test_terminate_router.py
@@ -12,7 +12,6 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr
 @pytest.mark.parametrize("remove_configuration", [True, False])
 @pytest.mark.parametrize("update_ibgp_mesh", [True, False])
 @pytest.mark.parametrize("update_sdp_mesh", [True, False])
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.router.terminate_router.NetboxClient.delete_device")
 @patch("gso.workflows.router.terminate_router.infoblox.delete_host_by_ip")
 @patch("gso.workflows.router.terminate_router.KentikClient")
@@ -22,7 +21,6 @@ def test_terminate_pe_router_full_success(
     mock_kentik_client,
     mock_delete_host_by_ip,
     mock_delete_device,
-    mock_execute_playbook,
     remove_configuration,
     update_ibgp_mesh,
     update_sdp_mesh,
@@ -65,13 +63,11 @@ def test_terminate_pe_router_full_success(
     assert mock_delete_device.call_count == 1
     assert mock_delete_host_by_ip.call_count == 1
     assert mock_librenms_remove_device.call_count == 1
-    assert mock_execute_playbook.call_count == lso_interaction_count
 
 
 @pytest.mark.workflow()
 @pytest.mark.parametrize("remove_configuration", [True, False])
 @pytest.mark.parametrize("update_ibgp_mesh", [True, False])
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.router.terminate_router.NetboxClient.delete_device")
 @patch("gso.workflows.router.terminate_router.infoblox.delete_host_by_ip")
 @patch("gso.workflows.router.terminate_router.LibreNMSClient.remove_device")
@@ -79,7 +75,6 @@ def test_terminate_p_router_full_success(
     mock_librenms_remove_device,
     mock_delete_host_by_ip,
     mock_delete_device,
-    mock_execute_playbook,
     remove_configuration,
     update_ibgp_mesh,
     router_subscription_factory,
@@ -117,4 +112,3 @@ def test_terminate_p_router_full_success(
     assert mock_delete_device.call_count == 1
     assert mock_delete_host_by_ip.call_count == 1
     assert mock_librenms_remove_device.call_count == 1
-    assert mock_execute_playbook.call_count == lso_interaction_count
diff --git a/test/workflows/router/test_update_ibgp_mesh.py b/test/workflows/router/test_update_ibgp_mesh.py
index 2cd098b3986dbf2adc58e0a9bd209b0925b0d829..ca7ae4ee715200d30c3a5e18e110b707df88fa5d 100644
--- a/test/workflows/router/test_update_ibgp_mesh.py
+++ b/test/workflows/router/test_update_ibgp_mesh.py
@@ -21,13 +21,11 @@ from test.workflows import (
 @pytest.mark.parametrize("update_ibgp_mesh", [True, False])
 @pytest.mark.parametrize("update_sbp_mesh", [True, False])
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.workflows.router.update_ibgp_mesh.librenms_client.LibreNMSClient.add_device")
 @patch("gso.workflows.router.update_ibgp_mesh.librenms_client.LibreNMSClient.device_exists")
 def test_update_ibgp_mesh_success(
     mock_librenms_device_exists,
     mock_librenms_add_device,
-    mock_execute_playbook,
     update_sbp_mesh,
     update_ibgp_mesh,
     router_role,
@@ -80,7 +78,6 @@ def test_update_ibgp_mesh_success(
 
     state = extract_state(result)
 
-    assert mock_execute_playbook.call_count == callback_step_count
     assert mock_librenms_add_device.call_count == 1
     assert result.status == StepStatus.COMPLETE
     assert state["subscription"]["router"]["router_access_via_ts"] is False
diff --git a/test/workflows/router/test_validate_router.py b/test/workflows/router/test_validate_router.py
index 8e9397885733b9a836ee14f827e6d94c097d4017..c67aa4e741f9204aa8e85312a270fec38d6589a7 100644
--- a/test/workflows/router/test_validate_router.py
+++ b/test/workflows/router/test_validate_router.py
@@ -20,7 +20,6 @@ from test.workflows import (
 @pytest.mark.parametrize("router_role", [RouterRole.P, RouterRole.PE])
 @pytest.mark.workflow()
 @patch("gso.services.infoblox.find_host_by_fqdn")
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_device_by_name")
 @patch("gso.services.librenms_client.LibreNMSClient.validate_device")
 @patch("gso.services.kentik_client.KentikClient")
@@ -28,7 +27,6 @@ def test_validate_nokia_router_success(
     mock_kentik_client,
     mock_validate_librenms_device,
     mock_get_device_by_name,
-    mock_execute_playbook,
     mock_find_host_by_fqdn,
     router_subscription_factory,
     faker,
@@ -76,7 +74,7 @@ def test_validate_nokia_router_success(
     subscription = Router.from_subscription(subscription_id)
 
     assert subscription.status == router_state
-    assert mock_execute_playbook.call_count == lso_execution_count
+
     assert mock_find_host_by_fqdn.call_count == 1
     assert mock_get_device_by_name.call_count == 1
     assert mock_validate_librenms_device.call_count == 1
diff --git a/test/workflows/switch/test_create_switch.py b/test/workflows/switch/test_create_switch.py
index a6e02d83cbc2f816a48c9b494ae4d64cbaf41a99..137ff7a66b32685473def2ad432c8b4c3acfa72c 100644
--- a/test/workflows/switch/test_create_switch.py
+++ b/test/workflows/switch/test_create_switch.py
@@ -20,12 +20,9 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.infoblox.hostname_available")
 @patch("gso.services.sharepoint.SharePointClient")
-def test_create_switch_success(
-    mock_sharepoint_client, mock_hostname_available, mock_execute_playbook, faker, site_subscription_factory
-):
+def test_create_switch_success(mock_sharepoint_client, mock_hostname_available, faker, site_subscription_factory):
     product_id = get_product_id_by_name(ProductName.SWITCH)
     initial_form_input = [
         {"product": product_id},
@@ -63,4 +60,3 @@ def test_create_switch_success(
     subscription_id = state["subscription_id"]
     subscription = Switch.from_subscription(subscription_id)
     assert subscription.status == "provisioning"
-    assert mock_execute_playbook.call_count == 3
diff --git a/test/workflows/switch/test_validate_switch.py b/test/workflows/switch/test_validate_switch.py
index 0e5a3b1349621dcc40af9a4d9f1ce4c588d35e44..8b9c57693a70b29b07573706ebf70c966bd76cd0 100644
--- a/test/workflows/switch/test_validate_switch.py
+++ b/test/workflows/switch/test_validate_switch.py
@@ -12,11 +12,9 @@ from test.workflows import (
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
 @patch("gso.services.netbox_client.NetboxClient.get_device_by_name")
 def test_validate_switch_success(
     mock_get_device_by_name,
-    mock_execute_playbook,
     switch_subscription_factory,
     faker,
     geant_partner,
@@ -33,5 +31,5 @@ def test_validate_switch_success(
     subscription = Switch.from_subscription(state["subscription_id"])
 
     assert subscription.status == "active"
-    assert mock_execute_playbook.call_count == 1
+
     assert mock_get_device_by_name.call_count == 1
diff --git a/test/workflows/vrf/test_modify_vrf_router_list.py b/test/workflows/vrf/test_modify_vrf_router_list.py
index 2dbcd9ef1b3f7ee6423ca8fc83ff4d924045fa3d..47136c1f860145ed0a3036f036e98ba0e78f1df1 100644
--- a/test/workflows/vrf/test_modify_vrf_router_list.py
+++ b/test/workflows/vrf/test_modify_vrf_router_list.py
@@ -1,5 +1,4 @@
 import uuid
-from unittest.mock import patch
 
 import pytest
 from pydantic_forms.exceptions import FormValidationError
@@ -9,10 +8,7 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
-def test_modify_vrf_router_list_add_a_router(
-    mock_lso_call, vrf_subscription_factory, router_subscription_factory, faker
-):
+def test_modify_vrf_router_list_add_a_router(vrf_subscription_factory, router_subscription_factory, faker):
     subscription_id = str(vrf_subscription_factory().subscription_id)
     initial_vrf_data = [
         {"subscription_id": subscription_id},
@@ -30,14 +26,10 @@ def test_modify_vrf_router_list_add_a_router(
     subscription = VRF.from_subscription(subscription_id)
     assert subscription.status == "active"
     assert len(subscription.vrf.vrf_router_list) == 1
-    assert mock_lso_call.call_count == 2
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
-def test_modify_vrf_router_list_remove_router(
-    mock_lso_call, vrf_subscription_factory, router_subscription_factory, faker
-):
+def test_modify_vrf_router_list_remove_router(vrf_subscription_factory, router_subscription_factory, faker):
     old_router = router_subscription_factory()
     subscription_id = str(vrf_subscription_factory(vrf_router_list=[old_router]).subscription_id)
     initial_vrf_data = [
@@ -56,7 +48,6 @@ def test_modify_vrf_router_list_remove_router(
     subscription = VRF.from_subscription(subscription_id)
     assert subscription.status == "active"
     assert len(subscription.vrf.vrf_router_list) == 0
-    assert mock_lso_call.call_count == 2
 
 
 @pytest.mark.workflow()
diff --git a/test/workflows/vrf/test_redeploy_vrf.py b/test/workflows/vrf/test_redeploy_vrf.py
index cb1d7f2e97bebe2bf9040add81d0201d544c0a7d..effabeb081e5584a47f3a7c1e715f7b4df9d7414 100644
--- a/test/workflows/vrf/test_redeploy_vrf.py
+++ b/test/workflows/vrf/test_redeploy_vrf.py
@@ -1,5 +1,3 @@
-from unittest.mock import patch
-
 import pytest
 
 from gso.products.product_types.vrf import VRF
@@ -7,8 +5,7 @@ from test.workflows import assert_complete, assert_lso_interaction_success, extr
 
 
 @pytest.mark.workflow()
-@patch("gso.services.lso_client._send_request")
-def test_redeploy_vrf(mock_lso_call, vrf_subscription_factory, router_subscription_factory, faker):
+def test_redeploy_vrf(vrf_subscription_factory, router_subscription_factory, faker):
     router_a = router_subscription_factory()
     router_b = router_subscription_factory()
     subscription_id = str(vrf_subscription_factory(vrf_router_list=[router_a, router_b]).subscription_id)
@@ -26,4 +23,3 @@ def test_redeploy_vrf(mock_lso_call, vrf_subscription_factory, router_subscripti
     subscription_id = state["subscription_id"]
     subscription = VRF.from_subscription(subscription_id)
     assert subscription.status == "active"
-    assert mock_lso_call.call_count == 2