diff --git a/Changelog.md b/Changelog.md
index 5d26dcf751d10574727b67aae2a73f24f994b473..d151d640e871746771be86027194f79b037f8dcb 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,5 +1,21 @@
 # Changelog
 
+## [2.47] - 2025-04-15
+- Make generation of new virtual circuit ID optional in layer 2 circuit migration workflow
+- Add REST API endpoint for getting the list of available versions
+
+## [2.46] - 2025-04-08
+- Integrated a new l2circuit migration workflow within the database.
+- Enhancements to Layer 2 Circuit Workflows
+- Fixed a bug in the prefix list validation logic when an FQDN list is unexpectedly empty.
+- Code Improvements and Utility Updates
+- Added SDP steps to the test_terminate_router to ensure proper execution.
+- Reworked SDP functions within workflow_steps for improved process clarity.
+- Integrated additional SDP steps in the terminate_router process.
+- Adjusted SDP steps in the promote_p_to_pe workflow.
+- Updated SDP steps within the update_ibgp_mesh workflow.
+
+
 ## [2.45] - 2025-04-02
 - Add email notifications to Kentik-related steps in workflows.
 - Improve Kentik license handling in Router termination workflow.
diff --git a/gso/api/v1/__init__.py b/gso/api/v1/__init__.py
index 8772f54efc9ece49a95f43b3df3cdde92269b58f..e2493364c7349d5223c01585999967de6d6d59d3 100644
--- a/gso/api/v1/__init__.py
+++ b/gso/api/v1/__init__.py
@@ -4,8 +4,10 @@ from fastapi import APIRouter
 
 from gso.api.v1.network import router as network_router
 from gso.api.v1.subscriptions import router as subscriptions_router
+from gso.api.v1.version import router as version_router
 
 router = APIRouter()
 
 router.include_router(subscriptions_router)
 router.include_router(network_router)
+router.include_router(version_router)
diff --git a/gso/api/v1/version.py b/gso/api/v1/version.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe9f8c7f14f46a983e83b6a962c9dbfc09e14d2c
--- /dev/null
+++ b/gso/api/v1/version.py
@@ -0,0 +1,19 @@
+"""API for getting the version of the orchestrator."""
+
+from fastapi import APIRouter
+from orchestrator.graphql.resolvers.version import VERSIONS
+from starlette import status
+
+router = APIRouter(prefix="/version", tags=["Version"])
+
+
+@router.get("/", status_code=status.HTTP_200_OK)
+def version() -> dict[str, str]:
+    """Get the version of deployed services."""
+    version_dict = {}
+    for item in VERSIONS:
+        if ":" in item:
+            key, value = item.split(":", 1)
+            version_dict[key.strip()] = value.strip()
+
+    return version_dict
diff --git a/gso/workflows/l2_circuit/migrate_layer_2_circuit.py b/gso/workflows/l2_circuit/migrate_layer_2_circuit.py
index 70a91e5aaaf24c274ca510bb9121e3b2ac37a882..661e27d32a00589c87d33ec0c199d4fcb154c0f3 100644
--- a/gso/workflows/l2_circuit/migrate_layer_2_circuit.py
+++ b/gso/workflows/l2_circuit/migrate_layer_2_circuit.py
@@ -87,6 +87,7 @@ def input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
         model_config = ConfigDict(title="Migrating Layer 2 Circuit")
 
         new_edge_port: active_edge_port_selector(partner_id=replace_side_partner.partner_id)  # type: ignore[valid-type]
+        generate_new_vc_id: bool = False
 
     user_input = yield SelectNewEdgePortForm
 
@@ -98,11 +99,17 @@ def input_form_generator(subscription_id: UUIDstr) -> FormGenerator:
         "subscription_id": subscription_id,
         "old_edge_port": initial_user_input.replace_side,
         "new_edge_port": user_input.new_edge_port,
+        "generate_new_vc_id": user_input.generate_new_vc_id,
     }
 
 
 @step("Update subscription model")
-def update_subscription_model(subscription: Layer2Circuit, old_edge_port: UUIDstr, new_edge_port: UUIDstr) -> State:
+def update_subscription_model(
+    subscription: Layer2Circuit,
+    old_edge_port: UUIDstr,
+    new_edge_port: UUIDstr,
+    generate_new_vc_id: bool,  # noqa: FBT001
+) -> State:
     """Replace the old Edge Port with the newly selected one in the subscription model."""
     replace_index = (
         0
@@ -114,12 +121,12 @@ def update_subscription_model(subscription: Layer2Circuit, old_edge_port: UUIDst
         new_edge_port
     ).edge_port
 
-    vc_id = generate_unique_vc_id(l2c_type=subscription.layer_2_circuit.layer_2_circuit_type)
-    if not vc_id:
-        msg = "Failed to generate unique Virtual Circuit ID."
-        raise ProcessFailureError(msg)
-
-    subscription.layer_2_circuit.virtual_circuit_id = vc_id
+    if generate_new_vc_id:
+        vc_id = generate_unique_vc_id(l2c_type=subscription.layer_2_circuit.layer_2_circuit_type)
+        if not vc_id:
+            msg = "Failed to generate unique Virtual Circuit ID."
+            raise ProcessFailureError(msg)
+        subscription.layer_2_circuit.virtual_circuit_id = vc_id
 
     return {"subscription": subscription}
 
diff --git a/setup.py b/setup.py
index fb8eab0f1e24782746e85d98d123c871fb79fc2f..f6a1d79b7d6a3f5dc76ec0522547dd1dfe148002 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,7 @@ from setuptools import find_packages, setup
 
 setup(
     name="geant-service-orchestrator",
-    version="2.46",
+    version="2.47",
     author="GÉANT Orchestration and Automation Team",
     author_email="goat@geant.org",
     description="GÉANT Service Orchestrator",
diff --git a/test/__init__.py b/test/__init__.py
index d9001c9314bacef63647c108731562e2f4194f99..433e89b0fcb66b0730237cc78cded4048140751c 100644
--- a/test/__init__.py
+++ b/test/__init__.py
@@ -1,4 +1,3 @@
-import os
 from uuid import uuid4
 
 LSO_RESULT_SUCCESS = {
@@ -20,5 +19,3 @@ LSO_RESULT_FAILURE = {
 }
 
 USER_CONFIRM_EMPTY_FORM = [{}]
-
-os.environ["TESTING"] = "true"
diff --git a/test/api/test_version.py b/test/api/test_version.py
new file mode 100644
index 0000000000000000000000000000000000000000..ffcf7acb118fccdf06e4a06430496d435a0ae494
--- /dev/null
+++ b/test/api/test_version.py
@@ -0,0 +1,21 @@
+from importlib import metadata
+
+
+def test_version_endpoint(test_client, monkeypatch):
+    """
+    Test that the /version endpoint returns the correct versions:
+    """
+    response = test_client.get("api/v1/version")
+
+    assert response.status_code == 200
+
+    data = response.json()
+
+    assert data == {
+        "GAP Ansible collection": "Unknown",
+        "GÉANT Service Orchestrator": metadata.version("geant-service-orchestrator"),
+        "GÉANT Service Orchestrator GUI": "Unknown",
+        "LSO": "Unknown",
+        "Moodi Ansible collection": "Unknown",
+        "orchestrator-core": "3.1.1",
+    }
diff --git a/test/conftest.py b/test/conftest.py
index 2c015bd1b54c0467322e716daa6fb3dbf53c8c5e..926cd183b0b50593f65b390d8a357eb73e337fd6 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -54,13 +54,16 @@ class UseJuniperSide(strEnum):
 
 def pytest_configure(config):
     """Set an environment variable before loading any test modules."""
-    config_filename = "gso/oss-params-example.json"
-    os.environ["OSS_PARAMS_FILENAME"] = config_filename
+    # Set environment variables for the test session
+    os.environ["OSS_PARAMS_FILENAME"] = "gso/oss-params-example.json"
+    os.environ["TESTING"] = "true"
 
+    # Register finalizers to clean up after tests are done
+    def cleanup() -> None:
+        del os.environ["OSS_PARAMS_FILENAME"]
+        del os.environ["TESTING"]
 
-def pytest_unconfigure(config):
-    """Clean up the environment variable after all tests."""
-    os.environ.pop("OSS_PARAMS_FILENAME", None)
+    pytest.session_cleanup = cleanup
 
 
 class FakerProvider(BaseProvider):
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 9c016cd28a5abbbd1a3d9cfd8572eeb78c5fedff..a0f05946cde87647941cb5421af0399a30ce0e47 100644
--- a/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py
+++ b/test/workflows/l2_circuit/test_migrate_layer_2_circuit.py
@@ -12,9 +12,11 @@ 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_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,
     layer_2_circuit_service_type,
@@ -31,6 +33,7 @@ def test_migrate_layer_2_circuit(
     )
     new_edge_port = edge_port_subscription_factory(node=side_b_router.router)
 
+    old_vc_id = subscription.layer_2_circuit.virtual_circuit_id
     initial_layer_2_circuit_data = [
         {"subscription_id": subscription.subscription_id},
         {
@@ -40,7 +43,10 @@ def test_migrate_layer_2_circuit(
             "run_old_side_ansible": run_old_side_ansible,
             "run_new_side_ansible": run_new_side_ansible,
         },
-        {"new_edge_port": new_edge_port.subscription_id},
+        {
+            "new_edge_port": new_edge_port.subscription_id,
+            "generate_new_vc_id": generate_new_vc_id,
+        },
     ]
 
     result, process_stat, step_log = run_workflow("migrate_layer_2_circuit", initial_layer_2_circuit_data)
@@ -70,3 +76,4 @@ def test_migrate_layer_2_circuit(
     assert replaced_edge_port.edge_port_ae_members[1].model_dump(
         exclude="owner_subscription_id"
     ) == new_edge_port.edge_port.edge_port_ae_members[1].model_dump(exclude="owner_subscription_id")
+    assert (old_vc_id == subscription.layer_2_circuit.virtual_circuit_id) is not generate_new_vc_id