diff --git a/api/config/api_urls.py b/api/config/api_urls.py
index b0d7eaaffefbf542eb4ef9b51dfe4d86692b37a7..7339df445d43653e7580220e528dd89a9b24b125 100644
--- a/api/config/api_urls.py
+++ b/api/config/api_urls.py
@@ -23,6 +23,7 @@ router.register(r"libraries", views.LibraryViewSet, "libraries")
 router.register(r"listen", views.ListenViewSet, "listen")
 router.register(r"artists", views.ArtistViewSet, "artists")
 router.register(r"channels", audio_views.ChannelViewSet, "channels")
+router.register(r"subscriptions", audio_views.SubscriptionsViewSet, "subscriptions")
 router.register(r"albums", views.AlbumViewSet, "albums")
 router.register(r"licenses", views.LicenseViewSet, "licenses")
 router.register(r"playlists", playlists_views.PlaylistViewSet, "playlists")
diff --git a/api/funkwhale_api/audio/views.py b/api/funkwhale_api/audio/views.py
index a473dbbe80bf8adff550e16e6376d3f3a55b5c1c..ba9983672a6ff826d97fcc4bedd42539191bdf57 100644
--- a/api/funkwhale_api/audio/views.py
+++ b/api/funkwhale_api/audio/views.py
@@ -10,6 +10,7 @@ from django.db.utils import IntegrityError
 
 from funkwhale_api.common import permissions
 from funkwhale_api.common import preferences
+from funkwhale_api.federation import models as federation_models
 from funkwhale_api.users.oauth import permissions as oauth_permissions
 
 from . import filters, models, serializers
@@ -66,10 +67,12 @@ class ChannelViewSet(
     )
     def subscribe(self, request, *args, **kwargs):
         object = self.get_object()
+        subscription = federation_models.Follow(
+            target=object.actor, approved=True, actor=request.user.actor,
+        )
+        subscription.fid = subscription.get_federation_id()
         try:
-            subscription = object.actor.received_follows.create(
-                approved=True, actor=request.user.actor,
-            )
+            subscription.save()
         except IntegrityError:
             # there's already a subscription for this actor/channel
             subscription = object.actor.received_follows.filter(
@@ -88,3 +91,48 @@ class ChannelViewSet(
         object = self.get_object()
         request.user.actor.emitted_follows.filter(target=object.actor).delete()
         return response.Response(status=204)
+
+
+class SubscriptionsViewSet(
+    ChannelsMixin,
+    mixins.RetrieveModelMixin,
+    mixins.ListModelMixin,
+    viewsets.GenericViewSet,
+):
+    lookup_field = "uuid"
+    serializer_class = serializers.SubscriptionSerializer
+    queryset = (
+        federation_models.Follow.objects.exclude(target__channel__isnull=True)
+        .prefetch_related(
+            "target__channel__library",
+            "target__channel__attributed_to",
+            "target__channel__artist__description",
+            "actor",
+        )
+        .order_by("-creation_date")
+    )
+    permission_classes = [
+        oauth_permissions.ScopePermission,
+        rest_permissions.IsAuthenticated,
+    ]
+    required_scope = "libraries"
+    anonymous_policy = False
+
+    def get_queryset(self):
+        qs = super().get_queryset()
+        return qs.filter(actor=self.request.user.actor)
+
+    @decorators.action(methods=["get"], detail=False)
+    def all(self, request, *args, **kwargs):
+        """
+        Return all the subscriptions of the current user, with only limited data
+        to have a performant endpoint and avoid lots of queries just to display
+        subscription status in the UI
+        """
+        subscriptions = list(self.get_queryset().values_list("uuid", flat=True))
+
+        payload = {
+            "results": [str(u) for u in subscriptions],
+            "count": len(subscriptions),
+        }
+        return response.Response(payload, status=200)
diff --git a/api/tests/audio/test_views.py b/api/tests/audio/test_views.py
index f8cf456a669f9cc383284e6206d969654c22ebef..0724bfa98b07e69008c0d4abaa5a04625fede72b 100644
--- a/api/tests/audio/test_views.py
+++ b/api/tests/audio/test_views.py
@@ -140,6 +140,7 @@ def test_channel_subscribe(factories, logged_in_api_client):
     subscription = actor.emitted_follows.select_related(
         "target__channel__artist__description"
     ).latest("id")
+    assert subscription.fid == subscription.get_federation_id()
     expected = serializers.SubscriptionSerializer(subscription).data
     assert response.data == expected
     assert subscription.target == channel.actor
@@ -157,3 +158,34 @@ def test_channel_unsubscribe(factories, logged_in_api_client):
 
     with pytest.raises(subscription.DoesNotExist):
         subscription.refresh_from_db()
+
+
+def test_subscriptions_list(factories, logged_in_api_client):
+    actor = logged_in_api_client.user.create_actor()
+    channel = factories["audio.Channel"](artist__description=None)
+    subscription = factories["audio.Subscription"](target=channel.actor, actor=actor)
+    factories["audio.Subscription"](target=channel.actor)
+    url = reverse("api:v1:subscriptions-list")
+    expected = serializers.SubscriptionSerializer(subscription).data
+    response = logged_in_api_client.get(url)
+
+    assert response.status_code == 200
+    assert response.data["results"][0] == expected
+    assert response.data == {
+        "results": [expected],
+        "count": 1,
+        "next": None,
+        "previous": None,
+    }
+
+
+def test_subscriptions_all(factories, logged_in_api_client):
+    actor = logged_in_api_client.user.create_actor()
+    channel = factories["audio.Channel"](artist__description=None)
+    subscription = factories["audio.Subscription"](target=channel.actor, actor=actor)
+    factories["audio.Subscription"](target=channel.actor)
+    url = reverse("api:v1:subscriptions-all")
+    response = logged_in_api_client.get(url)
+
+    assert response.status_code == 200
+    assert response.data == {"results": [subscription.uuid], "count": 1}