diff --git a/gregui/api/views/invitation.py b/gregui/api/views/invitation.py
index 52e2e60586dc46a45bef0533e695eed0b300ee1d..aa2dd0698a66b70d5cd73020ae3f8e19ccf0fdff 100644
--- a/gregui/api/views/invitation.py
+++ b/gregui/api/views/invitation.py
@@ -91,7 +91,7 @@ class InvitationView(CreateAPIView, DestroyAPIView):
             logger.warning(
                 f"Attempting to delete invitation for already registered guest with person ID {person_id}"
             )
-            return Response(status.HTTP_400_BAD_REQUEST)
+            return Response(status=status.HTTP_400_BAD_REQUEST)
 
         # Delete the person. The delete will cascade and all roles, identities and invitations will be removed.
         # It is OK to do this here since the person has not gone through the registration, so it is not
@@ -237,6 +237,7 @@ class InvitedGuestView(GenericAPIView):
 
         person = invite_link.invitation.role.person
         data = request.data
+        fnr = data.get("person") and data["person"].get("fnr")
 
         # If there is a Feide ID registered with the guest, assume that the name is also coming from there
         feide_id = self._get_identity_or_none(person, Identity.IdentityType.FEIDE_ID)
@@ -248,7 +249,7 @@ class InvitedGuestView(GenericAPIView):
         ):
             return Response(status=status.HTTP_400_BAD_REQUEST)
 
-        if self._verified_fnr_already_exists(person) and "fnr" in data:
+        if self._verified_fnr_already_exists(person) and fnr:
             # The user should not be allowed to change a verified fnr
             return Response(status=status.HTTP_400_BAD_REQUEST)
 
diff --git a/gregui/api/views/person.py b/gregui/api/views/person.py
index 8972a4679b727a0b96df890f422f50ee15e79de7..50ed292122d6e3b9fe71e715c8b9510475ebe926 100644
--- a/gregui/api/views/person.py
+++ b/gregui/api/views/person.py
@@ -56,7 +56,9 @@ class PersonView(APIView):
     def patch(self, request, id):
         person = Person.objects.get(id=id)
         # For now only the e-mail is allowed to be updated
-        email = request.data["email"]
+        email = request.data.get("email")
+        if not email:
+            return Response(status=status.HTTP_400_BAD_REQUEST)
         validate_email(email)
         # The following line will raise an exception if the e-mail is not valid
         create_identity_or_update(Identity.IdentityType.PRIVATE_EMAIL, email, person)
diff --git a/gregui/tests/api/test_invitation.py b/gregui/tests/api/test_invitation.py
index c63738805c13cf3d6fd726b2d7b415b30e9c4e55..a94f4daf9d98afefbb22e9429ec2e2dd3ddc5f8b 100644
--- a/gregui/tests/api/test_invitation.py
+++ b/gregui/tests/api/test_invitation.py
@@ -1,3 +1,5 @@
+import datetime
+from django.utils import timezone
 import pytest
 
 from rest_framework import status
@@ -8,14 +10,14 @@ from greg.models import InvitationLink, Person, Identity
 
 
 @pytest.mark.django_db
-def test_get_invite(client):
+def test_post_invite(client):
     """Forbid access with bad invitation link uuid"""
     response = client.post(reverse("gregui-v1:invite-verify"), data={"uuid": "baduuid"})
     assert response.status_code == status.HTTP_403_FORBIDDEN
 
 
 @pytest.mark.django_db
-def test_get_invite_ok(client, invitation_link):
+def test_post_invite_ok(client, invitation_link):
     """Access okay with valid invitation link"""
     response = client.post(
         reverse("gregui-v1:invite-verify"), data={"uuid": invitation_link.uuid}
@@ -24,7 +26,7 @@ def test_get_invite_ok(client, invitation_link):
 
 
 @pytest.mark.django_db
-def test_get_invite_expired(client, invitation_link_expired):
+def test_post_invite_expired(client, invitation_link_expired):
     """Forbid access with expired invite link"""
     response = client.post(
         reverse("gregui-v1:invite-verify"), data={"uuid": invitation_link_expired.uuid}
@@ -32,8 +34,22 @@ def test_get_invite_expired(client, invitation_link_expired):
     assert response.status_code == status.HTTP_403_FORBIDDEN
 
 
+@pytest.mark.django_db
+def test_post_missing_invite_id(client):
+    """Forbid access if no id provided."""
+    response = client.post(reverse("gregui-v1:invite-verify"))
+    assert response.status_code == status.HTTP_403_FORBIDDEN
+
+
 @pytest.mark.django_db
 def test_get_invited_info_no_session(client, invitation_link):
+    """Forbid access if invite expired after session was created."""
+    # get a session
+    client.post(reverse("gregui-v1:invite-verify"), data={"uuid": invitation_link.uuid})
+    # expire the invitation link
+    invitation_link.expire = timezone.now() - datetime.timedelta(days=1)
+    invitation_link.save()
+    # fail to get info because session has expired
     response = client.get(reverse("gregui-v1:invited-info"))
     assert response.status_code == status.HTTP_403_FORBIDDEN
 
@@ -336,3 +352,41 @@ def test_name_update_allowed_if_feide_identity_is_not_present(
     person.refresh_from_db()
     assert person.first_name == "Someone"
     assert person.last_name == "Test"
+
+
+@pytest.mark.django_db
+def test_post_info_fail_fnr_already_verified(client, invited_person_verified_nin):
+    """Ensure that an automatically verified fnr cannot be changed"""
+    person, invitation_link = invited_person_verified_nin
+    fnr = "10093720895"
+
+    session = client.session
+    session["invite_id"] = str(invitation_link.uuid)
+    session.save()
+
+    url = reverse("gregui-v1:invited-info")
+    data = {"person": {"mobile_phone": "+4797543992", "fnr": fnr}}
+    response = client.post(url, data, format="json")
+
+    # Verify rejection
+    assert response.status_code == status.HTTP_400_BAD_REQUEST
+    # Verify fnr was not changed
+    person.refresh_from_db()
+    assert person.fnr.value != fnr
+
+
+@pytest.mark.django_db
+def test_post_info_fail_unknown_field(client, invited_person_verified_nin):
+    """Ensure that including an unknown field gives bad request"""
+    _, invitation_link = invited_person_verified_nin
+
+    session = client.session
+    session["invite_id"] = str(invitation_link.uuid)
+    session.save()
+
+    url = reverse("gregui-v1:invited-info")
+    data = {"person": {"mobile_phone": "+4797543992", "badfield": "foo"}}
+    response = client.post(url, data, format="json")
+
+    # Verify rejection
+    assert response.status_code == status.HTTP_400_BAD_REQUEST
diff --git a/gregui/tests/api/test_invite_guest.py b/gregui/tests/api/test_invite_guest.py
index c3c4d42646bfe240ed5ad8bd6fe1b2a0d2309ff3..5a7f8ebfb5c081fe23c2c71206eb009eeda71324 100644
--- a/gregui/tests/api/test_invite_guest.py
+++ b/gregui/tests/api/test_invite_guest.py
@@ -82,6 +82,30 @@ def test_invite_cancel(client, invitation_link, invitation, role, log_in, user_s
     assert InvitationLink.objects.filter(invitation__id=invitation.id).count() == 0
 
 
+@pytest.mark.django_db
+def test_fail_delete_confirmed_invitation(
+    client, role, log_in, user_sponsor, sponsor_foo, invitation, invitation_link
+):
+    log_in(user_sponsor)
+
+    role = Role.objects.get(pk=role.id)
+    pe = Person.objects.get(pk=role.person_id)
+    pe.registration_completed_date = datetime.date.today()
+    pe.save()
+    assert pe.registration_completed_date
+    assert pe.is_registered
+
+    url = reverse("gregui-v1:invitation")
+    response = client.delete(f"{url}?person_id={str(pe.id)}")
+
+    assert response.status_code == status.HTTP_400_BAD_REQUEST
+
+    # The role, invitation and connected links should still exist
+    assert Role.objects.filter(id=role.id).count() == 1
+    assert Invitation.objects.filter(id=invitation.id).count() == 1
+    assert InvitationLink.objects.filter(invitation__id=invitation.id).count() == 1
+
+
 @pytest.mark.django_db
 def test_invite_resend_existing_invite_active(
     client,
@@ -162,3 +186,74 @@ def test_invite_resend_existing_invite_not_active(
     InvitationLink.objects.get(
         invitation__role__person_id=person_invited.id, expire__gt=timezone.now()
     )
+
+
+@pytest.mark.django_db
+def test_invite_resend_person_no_invites_fail(
+    client, log_in, user_sponsor, person_invited
+):
+    """Resending an invite for a person without invites should return bad request."""
+    log_in(user_sponsor)
+
+    url = reverse("gregui-v1:invite-resend", kwargs={"person_id": person_invited.id})
+    response = client.patch(url)
+    assert response.status_code == status.HTTP_400_BAD_REQUEST
+
+
+@pytest.mark.django_db
+def test_invite_resend_person_multiple_links_send_all(
+    client, log_in, user_sponsor, invited_person, registration_template, mocker
+):
+    """Resending an invite for a person with multiple working links should resend all of them."""
+    send_invite_mock_function = mocker.patch(
+        "gregui.api.views.invitation.send_invite_mail"
+    )
+    log_in(user_sponsor)
+    person, invitation = invited_person
+    invitation = Invitation.objects.filter(role__person_id=person.id).first()
+    InvitationLink.objects.create(
+        invitation=invitation, expire=timezone.now() + datetime.timedelta(days=1)
+    )
+    InvitationLink.objects.create(
+        invitation=invitation, expire=timezone.now() + datetime.timedelta(days=1)
+    )
+
+    invitation_links_for_person = InvitationLink.objects.filter(
+        invitation__role__person_id=person.id
+    )
+    assert invitation_links_for_person.count() == 3
+    url = reverse("gregui-v1:invite-resend", kwargs={"person_id": person.id})
+    response = client.patch(url)
+    assert response.status_code == status.HTTP_200_OK
+    assert send_invite_mock_function.call_count == 3
+
+
+@pytest.mark.django_db
+def test_invite_resend_person_multiple_expired_links_send_all(
+    client, log_in, user_sponsor, invited_person, registration_template, mocker
+):
+    """
+    Resending invites for a person with multiple invitations where all links are
+    expired should resend all of them.
+    """
+    send_invite_mock_function = mocker.patch(
+        "gregui.api.views.invitation.send_invite_mail"
+    )
+
+    log_in(user_sponsor)
+    # Expire invitation link
+    person, invitation = invited_person
+    invitation = Invitation.objects.filter(role__person_id=person.id).first()
+    link = InvitationLink.objects.get(invitation=invitation)
+    link.expire = timezone.now() - datetime.timedelta(days=1)
+    link.save()
+    # Make another invitation with an expired link
+    inv2 = Invitation.objects.create(role=invitation.role)
+    InvitationLink.objects.create(
+        invitation=inv2, expire=timezone.now() - datetime.timedelta(days=1)
+    )
+    # Resend request should trigger creation of new links for both invitations
+    url = reverse("gregui-v1:invite-resend", kwargs={"person_id": person.id})
+    response = client.patch(url)
+    assert response.status_code == status.HTTP_200_OK
+    assert send_invite_mock_function.call_count == 2
diff --git a/gregui/tests/api/test_person.py b/gregui/tests/api/test_person.py
new file mode 100644
index 0000000000000000000000000000000000000000..4afb1f771111df9a3266ae98622b9b05d934a824
--- /dev/null
+++ b/gregui/tests/api/test_person.py
@@ -0,0 +1,44 @@
+import pytest
+from rest_framework import status
+from rest_framework.reverse import reverse
+
+
+@pytest.mark.django_db
+def test_get_person_fail(client):
+    """Anonymous user cannot get person info"""
+    url = reverse("gregui-v1:person-get", kwargs={"id": 1})
+    response = client.get(url)
+    assert response.status_code == status.HTTP_403_FORBIDDEN
+
+
+@pytest.mark.django_db
+def test_get_person(client, log_in, user_sponsor, invited_person):
+    """Logged in sponsor can get person info"""
+    person, _ = invited_person
+    url = reverse("gregui-v1:person-get", kwargs={"id": person.id})
+    log_in(user_sponsor)
+    response = client.get(url)
+    assert response.status_code == status.HTTP_200_OK
+
+
+@pytest.mark.django_db
+def test_patch_person_no_data_fail(client, log_in, user_sponsor, invited_person):
+    """No data in patch should fail"""
+    person, _ = invited_person
+    url = reverse("gregui-v1:person-get", kwargs={"id": person.id})
+    log_in(user_sponsor)
+    response = client.patch(url)
+    assert response.status_code == status.HTTP_400_BAD_REQUEST
+
+
+@pytest.mark.django_db
+def test_patch_person_new_email_ok(client, log_in, user_sponsor, invited_person):
+    """Logged in sponsor can update email address of person"""
+    person, _ = invited_person
+    url = reverse("gregui-v1:person-get", kwargs={"id": person.id})
+    log_in(user_sponsor)
+    assert person.private_email.value == "foo@example.org"
+    response = client.patch(url, data={"email": "new@example.com"})
+    assert response.status_code == status.HTTP_200_OK
+    person.refresh_from_db()
+    assert person.private_email.value == "new@example.com"
diff --git a/gregui/tests/conftest.py b/gregui/tests/conftest.py
index 53b04a306be928c28584d09270abf5d5bbf34a83..b7f6e8f6c8ce4d793ae5789361df4c7f3d49c3aa 100644
--- a/gregui/tests/conftest.py
+++ b/gregui/tests/conftest.py
@@ -385,6 +385,40 @@ def invited_person_no_ids(
     )
 
 
+@pytest.fixture
+def invited_person_verified_nin(
+    create_person,
+    create_role,
+    create_invitation,
+    create_invitation_link,
+    sponsor_foo,
+    unit_foo,
+    role_type_foo,
+) -> Tuple[Person, InvitationLink]:
+    """
+    Invited person, with a verified NIN.
+    """
+    person = create_person(
+        first_name="Victor",
+        last_name="Verified",
+        email="foo@bar2.com",
+        nin="12345678912",
+    )
+    fnr = person.identities.get(type=Identity.IdentityType.NORWEGIAN_NATIONAL_ID_NUMBER)
+    fnr.verified = Identity.Verified.AUTOMATIC
+    fnr.save()
+
+    role = create_role(
+        person=person, sponsor=sponsor_foo, unit=unit_foo, role_type=role_type_foo
+    )
+
+    invitation = create_invitation(role=role)
+    invitation_link = create_invitation_link(invitation=invitation)
+    return Person.objects.get(id=person.id), InvitationLink.objects.get(
+        id=invitation_link.id
+    )
+
+
 @pytest.fixture
 def log_in(client) -> Callable[[UserModel], APIClient]:
     def _log_in(user):