diff --git a/activate_account_project/settings/base.py b/activate_account_project/settings/base.py
index f8493105007a1b64fae994591502d8b3f78cfaa3..87c8ef93b350ff3fa19fa254dce24c9dcebda14f 100644
--- a/activate_account_project/settings/base.py
+++ b/activate_account_project/settings/base.py
@@ -17,7 +17,7 @@ DATABASES = {
     },
 }
 
-DATA_MANAGER_ENABLED = False
+INTERNAL_API_ENABLED = False
 DATA_MANAGER_READ_ONLY = True
 FAKE_RESET_TOKEN_IF_MISSING = False
 
@@ -43,7 +43,7 @@ externalsettings.load_external_settings(
         "EMAIL_HOST_PASSWORD",
         "EMAIL_HOST_USER",
         "EMAIL_PORT",
-        "DATA_MANAGER_ENABLED",
+        "INTERNAL_API_ENABLED",
         "DATA_MANAGER_READ_ONLY",
         "FAKE_RESET_TOKEN_IF_MISSING",
     ],
diff --git a/activate_account_project/urls.py b/activate_account_project/urls.py
index 1cbdda3882128b5dd5313f285db0ad148f57f854..7a996ccec22cd1fd97fb14d0dbabeaca707fcd83 100644
--- a/activate_account_project/urls.py
+++ b/activate_account_project/urls.py
@@ -33,7 +33,7 @@ urlpatterns = [
         lambda request: HttpResponse("ok", content_type="text/plain"),
         name="healthy",
     ),
-    path("token/", include("authentication.urls")),
+    path("", include("authentication.urls")),
     # You'll also need to update api/tests/test_versions_view.py
     # Include the base API urls - which gives a view of the available API versions
     path("", include("api.urls")),
@@ -42,7 +42,7 @@ urlpatterns = [
     path("v1alpha1/", include(("api.v1alpha.urls", "v1alpha1"), namespace="v1alpha1")),
 ]
 
-if settings.DATA_MANAGER_ENABLED:
+if settings.INTERNAL_API_ENABLED:
     urlpatterns += [
         path(
             "data-manager-api/",
diff --git a/authentication/serializers.py b/authentication/serializers.py
index 8e338840762c6caa7dfd5a4c1e57eacdb2ee4d6b..b24e979d88fe6e42c8f0815d9d8b1ba067df603c 100644
--- a/authentication/serializers.py
+++ b/authentication/serializers.py
@@ -171,6 +171,12 @@ class TokenErrorSerializer(serializers.Serializer):
     error_uri = serializers.URLField(required=False)
 
 
+class LockoutSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = Lockout
+        fields = ("id", "identity_key", "date_of_birth", "attempts", "lockout_until")
+
+
 class EmptySerializer(serializers.Serializer):
     """
     Defines an empty response.
diff --git a/authentication/tests/test_lockout.py b/authentication/tests/test_lockout.py
index 1efd35d003ecaae38b839440801a8f6ffaf8bad8..ad9eb59204d04b7bb7cc85df394fc3d23735639e 100644
--- a/authentication/tests/test_lockout.py
+++ b/authentication/tests/test_lockout.py
@@ -1,6 +1,8 @@
 from datetime import timedelta
+from urllib.parse import urlencode
 
 import pytest
+from django.urls import reverse
 from django.utils import timezone
 from freezegun import freeze_time
 
@@ -12,7 +14,9 @@ from authentication.constants import (
     SESSION_GRANT_TYPE,
 )
 from authentication.errors import InvalidGrantError
-from authentication.serializers import TokenRequestSerializer
+from authentication.serializers import LockoutSerializer, TokenRequestSerializer
+
+pytestmark = pytest.mark.django_db
 
 
 def _build_data(identity_field, identity_value, identifier):
@@ -26,7 +30,6 @@ def _build_data(identity_field, identity_value, identifier):
 
 
 @pytest.mark.parametrize("identity_field", ["crsid", "last_name"])
-@pytest.mark.django_db
 def test_lockout_existing_active(identity_field):
     account = AccountFactory(account_identifier=True)
     identifier = account.account_identifier.first()
@@ -47,7 +50,6 @@ def test_lockout_existing_active(identity_field):
 
 
 @pytest.mark.parametrize("identity_field", ["crsid", "last_name"])
-@pytest.mark.django_db
 def test_lockout_created_on_invalid_credentials(identity_field):
     account = AccountFactory(account_identifier=True)
     identifier = account.account_identifier.first()
@@ -69,7 +71,6 @@ def test_lockout_created_on_invalid_credentials(identity_field):
 
 
 @pytest.mark.parametrize("identity_field", ["crsid", "last_name"])
-@pytest.mark.django_db
 def test_successful_login_clears_lockout(identity_field):
     account = AccountFactory(account_identifier=True)
     identifier = account.account_identifier.first()
@@ -96,7 +97,6 @@ def test_successful_login_clears_lockout(identity_field):
 
 
 @pytest.mark.parametrize("identity_field", ["crsid", "last_name"])
-@pytest.mark.django_db
 def test_exponential_backoff_lockout(identity_field):
     with freeze_time("2025-01-01 00:00:00") as frozen_datetime:
         account = AccountFactory(account_identifier=True)
@@ -131,3 +131,65 @@ def test_exponential_backoff_lockout(identity_field):
         expected_duration = LOCKOUT_INITIAL_SECONDS * (2 ** (lockout.attempts - LOCKOUT_ATTEMPTS))
         expected_lockout_time = timezone.now() + timedelta(seconds=expected_duration)
         assert (lockout.lockout_until - expected_lockout_time).total_seconds() == 0
+
+
+@pytest.mark.parametrize("identity_field", ["crsid", "last_name"])
+@freeze_time("2025-01-01 00:00:00")
+def test_lockout_clear_from_api_endpoint_flow(identity_field, api_client):
+    account = AccountFactory(account_identifier=True)
+    identifier = account.account_identifier.first()
+    identity_value = account.crsid if identity_field == "crsid" else identifier.last_name
+
+    data = _build_data(identity_field, identity_value, identifier)
+    wrong_data = {
+        **data,
+        "code": "wrong-code",
+    }
+
+    # Fail LOCK_ATTEMPTS times
+    for _ in range(LOCKOUT_ATTEMPTS):
+        response = api_client.post(
+            reverse("knox_login"),
+            data=urlencode(wrong_data),
+            content_type="application/x-www-form-urlencoded",
+        )
+
+        assert response.status_code == 400
+
+    lockout_kwargs = {
+        "identity_key": identity_value,
+        "date_of_birth": identifier.date_of_birth,
+    }
+
+    # Confirm account is locked out
+    assert Lockout.objects.filter(**lockout_kwargs).exists()
+
+    response = api_client.post(
+        reverse("knox_login"),
+        data=urlencode(data),
+        content_type="application/x-www-form-urlencoded",
+    )
+
+    assert response.status_code == 400
+
+    lockout = Lockout.objects.get(**lockout_kwargs)
+
+    response = api_client.get(reverse("lockout-list"))
+    assert response.status_code == 200
+    assert response.data == LockoutSerializer([lockout], many=True).data
+
+    # Now remove the lockout
+    response = api_client.delete(reverse("lockout-detail", args=[lockout.id]))
+    assert response.status_code == 204
+
+    # And confirm it's gone
+    assert not Lockout.objects.filter(**lockout_kwargs).exists()
+
+    # And that we can login again
+    response = api_client.post(
+        reverse("knox_login"),
+        data=urlencode(data),
+        content_type="application/x-www-form-urlencoded",
+    )
+
+    assert response.status_code == 200
diff --git a/authentication/urls.py b/authentication/urls.py
index 47b320c8b2d67c73d15c1c8ce9d40c1f85fe7cfa..3905ffc5fb6943801989440c4e52b6bc63d0d5d6 100644
--- a/authentication/urls.py
+++ b/authentication/urls.py
@@ -1,9 +1,16 @@
+from django.conf import settings
 from django.urls import path
+from rest_framework import routers
 
-from .views import LoginView, LogoutAllView, LogoutView
+from .views import LockoutViewSet, LoginView, LogoutAllView, LogoutView
 
 urlpatterns = [
-    path("", LoginView.as_view(), name="knox_login"),
-    path("revoke/", LogoutView.as_view(), name="knox_logout"),
-    path("revoke/all/", LogoutAllView.as_view(), name="knox_logoutall"),
+    path("token/", LoginView.as_view(), name="knox_login"),
+    path("token/revoke/", LogoutView.as_view(), name="knox_logout"),
+    path("token/revoke/all/", LogoutAllView.as_view(), name="knox_logoutall"),
 ]
+
+if settings.INTERNAL_API_ENABLED:
+    router = routers.SimpleRouter()
+    router.register("lockout", LockoutViewSet, basename="lockout")
+    urlpatterns += router.urls
diff --git a/authentication/views.py b/authentication/views.py
index 6cc548b8d899e1d8938ec8cc66835b4e5e44e022..61cc1aa61a3cce1af7e6385ce731adcc176e3f11 100644
--- a/authentication/views.py
+++ b/authentication/views.py
@@ -1,11 +1,21 @@
 from drf_spectacular.utils import OpenApiResponse, extend_schema
 from knox.views import LoginView as KnoxLoginView
-from rest_framework import parsers, renderers, serializers, status, views
+from rest_framework import (
+    mixins,
+    parsers,
+    renderers,
+    serializers,
+    status,
+    views,
+    viewsets,
+)
 from rest_framework.response import Response
 
+from activate_account.models import Lockout
 from authentication.errors import OAuth2Error
 from authentication.serializers import (
     EmptySerializer,
+    LockoutSerializer,
     TokenErrorSerializer,
     TokenRequestSerializer,
     TokenResponseSerializer,
@@ -154,3 +164,16 @@ class LogoutAllView(views.APIView):
     def post(self, request, format=None):
         request.user.auth_token_set.all().delete()
         return self.get_post_response(request)
+
+
+class LockoutViewSet(
+    mixins.RetrieveModelMixin,
+    mixins.DestroyModelMixin,
+    mixins.ListModelMixin,
+    viewsets.GenericViewSet,
+):
+    permission_classes = ()
+    authentication_classes = ()
+    queryset = Lockout.objects.all()
+    serializer_class = LockoutSerializer
+    versioning_class = None
diff --git a/docker-compose.yml b/docker-compose.yml
index 954a6a4cd0c3a1f49f643cadd9857217a1b67c2c..3540665453615333a9ecfadef85a6da966841142 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -11,7 +11,7 @@ x-django-application-environment: &django-application-environment
   # disabled and one instance that is internal and has these endpoints enabled. In local
   # development we simplify the setup and just run one instance with all endpoints, internal and
   # external.
-  EXTERNAL_SETTING_DATA_MANAGER_ENABLED: "1"
+  EXTERNAL_SETTING_INTERNAL_API_ENABLED: "1"
   EXTERNAL_SETTING_DATA_MANAGER_READ_ONLY: "0"
   # Connect to mock password app reset token request endpoint
   EXTERNAL_SETTING_PASSWORD_APP_RESET_TOKEN_URL: "http://mock-password-app:8010/acc-reset-token"
diff --git a/pyproject.toml b/pyproject.toml
index 005bccd37fe482b32ed49327487f3895a9fc03cb..e9a31cb1be01755807295e5f0a82056e4708f78f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -147,7 +147,7 @@ env = [
   "DJANGO_SETTINGS_MODULE=activate_account_project.settings.testing",
   "D:R:EXTERNAL_SETTING_DATABASES={\"default\":{}}",
   "D:EXTERNAL_SETTING_SECRET_KEY=fake-secret-key",
-  "D:EXTERNAL_SETTING_DATA_MANAGER_ENABLED=1",
+  "D:EXTERNAL_SETTING_INTERNAL_API_ENABLED=1",
   "D:EXTERNAL_SETTING_DATA_MANAGER_READ_ONLY=0",
   "D:EXTERNAL_SETTING_PASSWORD_APP_RESET_TOKEN_URL=http://placeholder/",
   "D:EXTERNAL_SETTING_PASSWORD_APP_TOKEN=fake",