diff --git a/greg/api/serializers/organizational_unit.py b/greg/api/serializers/organizational_unit.py
index 3e9420ae0ac75fc6c6f3050fbcaf86f901111425..3c4acd7cd32f409376a9faa54ae012e03c48242a 100644
--- a/greg/api/serializers/organizational_unit.py
+++ b/greg/api/serializers/organizational_unit.py
@@ -1,8 +1,8 @@
-from rest_framework.serializers import ModelSerializer, CharField
+from rest_framework.serializers import ModelSerializer
 
 from greg.api.serializers.ouidentifier import OuIdentifierSerializer
 
-from greg.models import OrganizationalUnit
+from greg.models import OrganizationalUnit, SponsorOrganizationalUnit
 
 
 class OrganizationalUnitSerializer(ModelSerializer):
@@ -24,19 +24,14 @@ class OrganizationalUnitSerializer(ModelSerializer):
 
 
 class SponsorOrgUnitsSerializer(ModelSerializer):
-    nb = CharField(source="name_nb")
-    en = CharField(source="name_en")
-
     class Meta:
-        model = OrganizationalUnit
+        model = SponsorOrganizationalUnit
         fields = [
             "id",
-            "nb",
-            "en",
-            "orgreg_id",
-            "identifier_1",
-            "identifier_2",
-            "acronym_nob",
-            "acronym_nno",
-            "acronym_eng",
+            "sponsor",
+            "organizational_unit",
+            "hierarchical_access",
+            "automatic",
+            "source",
         ]
+        read_only_fields = ["sponsor", "organizational_unit"]
diff --git a/greg/api/urls.py b/greg/api/urls.py
index 492f3a22e8e6a46ed3739c321d3452010f8c43bf..2e721797ed19d75ac9d684b1e0747c1dc5d5b965 100644
--- a/greg/api/urls.py
+++ b/greg/api/urls.py
@@ -72,9 +72,16 @@ urlpatterns += [
         SponsorGuestsViewSet.as_view({"get": "list"}),
         name="sponsor_guests-list",
     ),
+    re_path(
+        r"^sponsors/(?P<sponsor_id>[0-9]+)/orgunits$",
+        SponsorOrgunitLinkView.as_view({"get": "list"}),
+        name="sponsor_orgunit-list",
+    ),
     re_path(
         r"^sponsors/(?P<sponsor_id>[0-9]+)/orgunit/(?P<orgunit_id>[0-9]+)$",
-        SponsorOrgunitLinkView.as_view({"post": "create", "delete": "destroy"}),
+        SponsorOrgunitLinkView.as_view(
+            {"post": "create", "delete": "destroy", "get": "retrieve"}
+        ),
         name="sponsor_orgunit-detail",
     ),
     re_path(
diff --git a/greg/api/views/sponsor.py b/greg/api/views/sponsor.py
index 8c7a337f6c1ecdd17fb49ee5631bf5efc94170b1..755ee5283af533331134252d39a8cffb9ec3c5f1 100644
--- a/greg/api/views/sponsor.py
+++ b/greg/api/views/sponsor.py
@@ -9,9 +9,9 @@ from rest_framework.viewsets import GenericViewSet, ModelViewSet
 
 from greg.api.pagination import PrimaryKeyCursorPagination
 from greg.api.serializers import PersonSerializer
-from greg.api.serializers.organizational_unit import OrganizationalUnitSerializer
+from greg.api.serializers.organizational_unit import SponsorOrgUnitsSerializer
 from greg.api.serializers.sponsor import SponsorSerializer
-from greg.models import Sponsor, Person, OrganizationalUnit
+from greg.models import Sponsor, Person, OrganizationalUnit, SponsorOrganizationalUnit
 
 logger = logging.getLogger(__name__)
 
@@ -73,8 +73,8 @@ class SponsorOrgunitLinkView(
 ):
     """Endpoint that allows manipulation of links between a sponsor and the units he is attached to"""
 
-    queryset = OrganizationalUnit.objects.all().order_by("id")
-    serializer_class = OrganizationalUnitSerializer
+    queryset = SponsorOrganizationalUnit.objects.all().order_by("id")
+    serializer_class = SponsorOrgUnitsSerializer
     pagination_class = PrimaryKeyCursorPagination
     permission_classes = (permissions.IsAdminUser,)
     # This is set so that the orgunit_id parameter in the path of the URL is used for looking up objects
@@ -82,14 +82,36 @@ class SponsorOrgunitLinkView(
 
     def create(self, request, *args, **kwargs):
         (sponsor_id, orgunit_id) = self._extract_sponsor_and_orgunit(kwargs)
-        # Default to false if hierarchical_access is not specified
+        sponsor_orgunit = self.queryset.filter(
+            sponsor__id=sponsor_id, organizational_unit__id=orgunit_id
+        )
+        # Set default values if fields are not given
         hierarchical_access = request.data.get("hierarchical_access", "False")
-        sponsor = Sponsor.objects.get(id=sponsor_id)
-        sponsor.units.add(
-            orgunit_id, through_defaults={"hierarchical_access": hierarchical_access}
+        source = request.data.get("source", "")
+        automatic = request.data.get("automatic", "False")
+
+        if sponsor_orgunit:
+            sponsor_orgunit.update(
+                hierarchical_access=hierarchical_access,
+                automatic=automatic,
+                source=source,
+            )
+            serializer = self.serializer_class(sponsor_orgunit, many=True)
+            return Response(serializer.data)
+
+        SponsorOrganizationalUnit.objects.create(
+            sponsor=Sponsor.objects.get(id=kwargs["sponsor_id"]),
+            organizational_unit=OrganizationalUnit.objects.get(id=kwargs["orgunit_id"]),
+            hierarchical_access=hierarchical_access,
+            automatic=automatic,
+            source=source,
         )
 
-        return Response(status=status.HTTP_204_NO_CONTENT)
+        sponsor_orgunit = self.queryset.filter(
+            sponsor__id=sponsor_id, organizational_unit__id=orgunit_id
+        )
+        serializer = self.serializer_class(sponsor_orgunit, many=True)
+        return Response(serializer.data)
 
     def destroy(self, request, *args, **kwargs):
         """Overridden because a delete at this endpoint should not attempt to delete the organizational unit,
@@ -100,6 +122,22 @@ class SponsorOrgunitLinkView(
 
         return Response(status=status.HTTP_204_NO_CONTENT)
 
+    def list(self, request, *args, **kwargs):
+        """Lists all SponsorOrganizationalUnit objects connected to the sponsor"""
+        sponsor_id = kwargs["sponsor_id"]
+        all_units = self.queryset.filter(sponsor__id=sponsor_id).all()
+        serializer = self.serializer_class(all_units, many=True)
+        return Response(serializer.data)
+
+    def retrieve(self, request, *args, **kwargs):
+        """Returns a given SponsorOrganizationalUnit object"""
+        (sponsor_id, orgunit_id) = self._extract_sponsor_and_orgunit(kwargs)
+        unit = self.queryset.filter(
+            sponsor__id=sponsor_id, organizational_unit__id=orgunit_id
+        )
+        serializer = self.serializer_class(unit, many=True)
+        return Response(serializer.data)
+
     def _extract_sponsor_and_orgunit(self, request_data):
         sponsor_id = request_data["sponsor_id"]
         orgunit_id = request_data["orgunit_id"]
diff --git a/greg/tests/api/test_sponsor.py b/greg/tests/api/test_sponsor.py
index 5b48fc5a686b3d77d88a5092650114a9ed576669..c0ae4d00c9088aa4a343a8050d8d24935188cc14 100644
--- a/greg/tests/api/test_sponsor.py
+++ b/greg/tests/api/test_sponsor.py
@@ -81,7 +81,7 @@ def test_add_sponsor_with_unit(client, unit_foo: OrganizationalUnit):
         kwargs={"sponsor_id": sponsor_id, "orgunit_id": unit_foo.id},
     )
     response = client.post(create_sponsor_link_url, data=data)
-    assert response.status_code == status.HTTP_204_NO_CONTENT
+    assert response.status_code == status.HTTP_200_OK
 
     sponsor_lookup_response = client.get(sponsor_url, kwargs={"id": sponsor_id})
     sponsor_lookup_response_body = sponsor_lookup_response.json()
@@ -106,7 +106,7 @@ def test_remove_sponsor_orgunit_link(
         kwargs={"sponsor_id": sponsor_guy.id, "orgunit_id": unit_foo.id},
     )
     response = client.post(sponsor_orgunit_url, data=data)
-    assert response.status_code == status.HTTP_204_NO_CONTENT
+    assert response.status_code == status.HTTP_200_OK
 
     response_get = client.get(sponsor_detail_url).json()
 
@@ -174,7 +174,9 @@ def test_add_sponsor_unit_link_with_no_access_parameter(
         kwargs={"sponsor_id": sponsor_id, "orgunit_id": unit_foo.id},
     )
     response = client.post(create_sponsor_link_url)
-    assert response.status_code == status.HTTP_204_NO_CONTENT
+    assert response.status_code == status.HTTP_200_OK
+    response_body = response.json()
+    assert len(response_body) == 1
 
     # Check that the unit is attached to the sponsor
     sponsor_lookup_response = client.get(sponsor_url, kwargs={"id": sponsor_id})
@@ -189,3 +191,104 @@ def test_add_sponsor_unit_link_with_no_access_parameter(
         sponsor_id=sponsor_id, organizational_unit_id=unit_foo.id
     ).get()
     assert not sponsor_organization_unit.hierarchical_access
+
+
+@pytest.mark.django_db
+def test_retrieve_sponsor_orgunit(
+    client,
+    sponsor_guy: Sponsor,
+    unit_foo: OrganizationalUnit,
+    sponsor_org_unit: SponsorOrganizationalUnit,
+):
+    url = reverse(
+        "v1:sponsor_orgunit-detail",
+        kwargs={"sponsor_id": sponsor_guy.id, "orgunit_id": unit_foo.id},
+    )
+    sponsor_unit = client.get(url).json()
+
+    assert len(sponsor_unit) == 1
+
+
+@pytest.mark.django_db
+def test_no_sponsor_orgunit_exists(
+    client,
+    sponsor_foo: Sponsor,
+    unit_foo: OrganizationalUnit,
+):
+    url = reverse(
+        "v1:sponsor_orgunit-detail",
+        kwargs={"sponsor_id": sponsor_foo.id, "orgunit_id": unit_foo.id},
+    )
+    sponsor_unit = client.get(url).json()
+
+    assert len(sponsor_unit) == 0
+
+
+@pytest.mark.django_db
+def test_list_all_sponsor_orgunits(
+    client,
+    sponsor_guy: Sponsor,
+    sponsor_org_unit: SponsorOrganizationalUnit,
+    sponsor_org_unit_guy: SponsorOrganizationalUnit,
+):
+    url = reverse("v1:sponsor_orgunit-list", kwargs={"sponsor_id": sponsor_guy.id})
+
+    sponsor_units = client.get(url).json()
+
+    assert len(sponsor_units) == 2
+
+
+@pytest.mark.django_db
+def test_update_sponsor_orgunit(
+    client,
+    sponsor_guy: Sponsor,
+    unit_foo: OrganizationalUnit,
+    sponsor_org_unit: SponsorOrganizationalUnit,
+):
+    data = {
+        "hierarchical_access": True,
+        "automatic": False,
+        "source": "test",
+    }
+    url = reverse(
+        "v1:sponsor_orgunit-detail",
+        kwargs={"sponsor_id": sponsor_guy.id, "orgunit_id": unit_foo.id},
+    )
+    assert sponsor_org_unit.hierarchical_access is False
+    response_data = client.post(url, data=data).json()[0]
+
+    assert response_data["hierarchical_access"] == data["hierarchical_access"]
+    assert response_data["automatic"] == data["automatic"]
+    assert response_data["source"] == data["source"]
+
+
+@pytest.mark.django_db
+def test_create_new_sponsor_orgunit(
+    client,
+    sponsor_foo: Sponsor,
+    unit_foo: OrganizationalUnit,
+):
+    data = {
+        "hierarchical_access": True,
+        "automatic": False,
+        "source": "test",
+    }
+    get_url = reverse(
+        "v1:sponsor_orgunit-detail",
+        kwargs={"sponsor_id": sponsor_foo.id, "orgunit_id": unit_foo.id},
+    )
+    sponsor_unit = client.get(get_url).json()
+    assert len(sponsor_unit) == 0
+
+    post_url = reverse(
+        "v1:sponsor_orgunit-detail",
+        kwargs={"sponsor_id": sponsor_foo.id, "orgunit_id": unit_foo.id},
+    )
+
+    response_data = client.post(post_url, data=data).json()
+    assert len(response_data) == 1
+
+    response_data = response_data[0]
+    assert response_data["hierarchical_access"] == data["hierarchical_access"]
+    assert response_data["automatic"] == data["automatic"]
+    assert response_data["source"] == data["source"]
diff --git a/greg/tests/conftest.py b/greg/tests/conftest.py
index 1ceabf4b1b0e432c9cccc1bd1a8dd39c69bb176d..22f0ddff674a7c86721619384d01767d38006152 100644
--- a/greg/tests/conftest.py
+++ b/greg/tests/conftest.py
@@ -124,6 +124,17 @@ def sponsor_guy() -> Sponsor:
     return Sponsor.objects.get(id=sp.id)
 
 
+@pytest.fixture
+def sponsor_foo() -> Sponsor:
+    sp = Sponsor.objects.create(
+        feide_id="foo@example.org",
+        first_name="Sponsor",
+        last_name="Foo",
+        work_email="sponsor_foo@example.com",
+    )
+    return Sponsor.objects.get(id=sp.id)
+
+
 @pytest.fixture
 def person_foo_verified(person_foo, sponsor_guy) -> Identity:
     pi = Identity.objects.create(
@@ -281,6 +292,14 @@ def sponsor_org_unit(sponsor_guy, unit_foo):
     return SponsorOrganizationalUnit.objects.get(id=1)
 
 
+@pytest.fixture
+def sponsor_org_unit_guy(sponsor_guy, unit_foo2):
+    SponsorOrganizationalUnit.objects.create(
+        sponsor=sponsor_guy, organizational_unit=unit_foo2, hierarchical_access=False
+    )
+    return SponsorOrganizationalUnit.objects.get(id=2)
+
+
 @pytest.fixture
 def notification():
     Notification.objects.create(
diff --git a/gregui/api/views/ou.py b/gregui/api/views/ou.py
index a7dbe1e7c238c7776b79531b21e19a5b7989cd05..5081f8d40c7e35a05907fae8ff8debb54ac3483b 100644
--- a/gregui/api/views/ou.py
+++ b/gregui/api/views/ou.py
@@ -1,19 +1,39 @@
 from rest_framework import mixins
 from rest_framework.authentication import SessionAuthentication, BasicAuthentication
 from rest_framework.permissions import IsAuthenticated
+from rest_framework.serializers import CharField, ModelSerializer
 from rest_framework.viewsets import GenericViewSet
-from greg.api.serializers.organizational_unit import SponsorOrgUnitsSerializer
 
+from greg.models import OrganizationalUnit
 from greg.permissions import IsSponsor
 from gregui.models import GregUserProfile
 
 
+class OrgUnitsSerializer(ModelSerializer):
+    nb = CharField(source="name_nb")
+    en = CharField(source="name_en")
+
+    class Meta:
+        model = OrganizationalUnit
+        fields = [
+            "id",
+            "nb",
+            "en",
+            "orgreg_id",
+            "identifier_1",
+            "identifier_2",
+            "acronym_nob",
+            "acronym_nno",
+            "acronym_eng",
+        ]
+
+
 class OusViewSet(mixins.ListModelMixin, GenericViewSet):
     """Fetch Ous related to the authenticated sponsor."""
 
     authentication_classes = [SessionAuthentication, BasicAuthentication]
     permission_classes = [IsAuthenticated, IsSponsor]
-    serializer_class = SponsorOrgUnitsSerializer
+    serializer_class = OrgUnitsSerializer
 
     def get_queryset(self):
         sponsor = GregUserProfile.objects.get(user=self.request.user).sponsor