diff --git a/api/funkwhale_api/federation/activity.py b/api/funkwhale_api/federation/activity.py
index 1b03d19f8e2be2a080ff905a3435686084412599..b253955c85703457158efe97bb0e7d6a2ce6d3bb 100644
--- a/api/funkwhale_api/federation/activity.py
+++ b/api/funkwhale_api/federation/activity.py
@@ -101,6 +101,20 @@ def get_follow(follow_id, follower, followed):
     }
 
 
+def get_undo(id, actor, object):
+    return {
+        '@context': [
+            'https://www.w3.org/ns/activitystreams',
+            'https://w3id.org/security/v1',
+            {}
+        ],
+        'type': 'Undo',
+        'id': id + '/undo',
+        'actor': actor.url,
+        'object': object,
+    }
+
+
 def get_accept_follow(accept_id, accept_actor, follow, follow_actor):
     return {
         "@context": [
diff --git a/api/funkwhale_api/federation/actors.py b/api/funkwhale_api/federation/actors.py
index 8871b1013b4d492fb35aa90885c8df8a1fd8fc63..0da78fdbe8acbf4fb8f93f6a7214565508147956 100644
--- a/api/funkwhale_api/federation/actors.py
+++ b/api/funkwhale_api/federation/actors.py
@@ -146,6 +146,23 @@ class SystemActor(object):
             system_actor, ac, sender
         )
 
+    def handle_undo_follow(self, ac, sender):
+        actor = self.get_actor_instance()
+        models.Follow.objects.filter(
+            actor=sender,
+            target=actor,
+        ).delete()
+
+    def handle_undo(self, ac, sender):
+        if ac['object']['type'] != 'Follow':
+            return
+
+        if ac['object']['actor'] != sender.url:
+            # not the same actor, permission issue
+            return
+
+        self.handle_undo_follow(ac, sender)
+
 
 class LibraryActor(SystemActor):
     id = 'library'
@@ -268,39 +285,28 @@ class TestActor(SystemActor):
             to=[ac['actor']],
             on_behalf_of=test_actor)
 
-    def handle_undo(self, ac, sender):
-        if ac['object']['type'] != 'Follow':
-            return
-
-        if ac['object']['actor'] != sender.url:
-            # not the same actor, permission issue
-            return
-
-        test_actor = self.get_actor_instance()
-        models.Follow.objects.filter(
-            actor=sender,
-            target=test_actor,
-        ).delete()
+    def handle_undo_follow(self, ac, sender):
+        super().handle_undo_follow(ac, sender)
+        actor = self.get_actor_instance()
         # we also unfollow the sender, if possible
         try:
             follow = models.Follow.objects.get(
                 target=sender,
-                actor=test_actor,
+                actor=actor,
             )
         except models.Follow.DoesNotExist:
             return
-        undo = {
-            '@context': serializers.AP_CONTEXT,
-            'type': 'Undo',
-            'id': follow.get_federation_url() + '/undo',
-            'actor': test_actor.url,
-            'object': serializers.FollowSerializer(follow).data,
-        }
+        undo = activity.get_undo(
+            id=follow.get_federation_url(),
+            actor=actor,
+            object=serializers.FollowSerializer(follow).data,
+        )
         follow.delete()
         activity.deliver(
             undo,
             to=[sender.url],
-            on_behalf_of=test_actor)
+            on_behalf_of=actor)
+
 
 SYSTEM_ACTORS = {
     'library': LibraryActor(),