diff --git a/api/funkwhale_api/federation/actors.py b/api/funkwhale_api/federation/actors.py
index fa1b56282b127ef7f14d259b4d70a203f5aa3df5..6f782ced4d195f03303cca2bbcd93222e0b2f134 100644
--- a/api/funkwhale_api/federation/actors.py
+++ b/api/funkwhale_api/federation/actors.py
@@ -50,6 +50,11 @@ class SystemActor(object):
     additional_attributes = {}
     manually_approves_followers = False
 
+    def serialize(self):
+        actor = self.get_actor_instance()
+        serializer = serializers.ActorSerializer()
+        return serializer.data
+
     def get_actor_instance(self):
         args = self.get_instance_argument(
             self.id,
@@ -172,6 +177,17 @@ class LibraryActor(SystemActor):
         'manually_approves_followers': True
     }
 
+    def serialize(self):
+        data = super().serialize()
+        urls = data.setdefault('url', [])
+        urls.append({
+            'type': 'Link',
+            'mediaType': 'application/activity+json',
+            'name': 'library',
+            'href': utils.full_url(reverse('federation:music:files-list'))
+        })
+        return data
+
     @property
     def manually_approves_followers(self):
         return settings.FEDERATION_MUSIC_NEEDS_APPROVAL
diff --git a/api/funkwhale_api/federation/urls.py b/api/funkwhale_api/federation/urls.py
index f2c6f4c78c61973436b3d92aacebdec3506156fd..e899869a445282278a64020996b7315baa7399b5 100644
--- a/api/funkwhale_api/federation/urls.py
+++ b/api/funkwhale_api/federation/urls.py
@@ -1,8 +1,10 @@
-from rest_framework import routers
+from django.conf.urls import include, url
 
+from rest_framework import routers
 from . import views
 
 router = routers.SimpleRouter(trailing_slash=False)
+music_router = routers.SimpleRouter(trailing_slash=False)
 router.register(
     r'federation/instance/actors',
     views.InstanceActorViewSet,
@@ -12,4 +14,11 @@ router.register(
     views.WellKnownViewSet,
     'well-known')
 
-urlpatterns = router.urls
+music_router.register(
+    r'federation/files',
+    views.MusicFilesViewSet,
+    'files',
+)
+urlpatterns = router.urls + [
+    url('music/', include((music_router.urls, 'music'), namespace='music'))
+]
diff --git a/api/funkwhale_api/federation/views.py b/api/funkwhale_api/federation/views.py
index 2e3feb8d082ebdca00917e59e13d5f3cc601eb33..390a371bce6cf0b2f1143091ab86bcd33b5b44c4 100644
--- a/api/funkwhale_api/federation/views.py
+++ b/api/funkwhale_api/federation/views.py
@@ -1,16 +1,23 @@
 from django import forms
 from django.conf import settings
+from django.core import paginator
 from django.http import HttpResponse
+from django.urls import reverse
 
 from rest_framework import viewsets
 from rest_framework import views
 from rest_framework import response
 from rest_framework.decorators import list_route, detail_route
 
+from funkwhale_api.music.models import TrackFile
+from funkwhale_api.music.serializers import AudioSerializer
+
 from . import actors
 from . import authentication
+from . import permissions
 from . import renderers
 from . import serializers
+from . import utils
 from . import webfinger
 
 
@@ -38,8 +45,8 @@ class InstanceActorViewSet(FederationMixin, viewsets.GenericViewSet):
     def retrieve(self, request, *args, **kwargs):
         system_actor = self.get_object()
         actor = system_actor.get_actor_instance()
-        serializer = serializers.ActorSerializer(actor)
-        return response.Response(serializer.data, status=200)
+        data = actor.system_conf.serialize()
+        return response.Response(data, status=200)
 
     @detail_route(methods=['get', 'post'])
     def inbox(self, request, *args, **kwargs):
@@ -101,3 +108,47 @@ class WellKnownViewSet(FederationMixin, viewsets.GenericViewSet):
         username, hostname = clean_result
         actor = actors.SYSTEM_ACTORS[username].get_actor_instance()
         return serializers.ActorWebfingerSerializer(actor).data
+
+
+class MusicFilesViewSet(FederationMixin, viewsets.GenericViewSet):
+    authentication_classes = [
+        authentication.SignatureAuthentication]
+    permission_classes = [permissions.LibraryFollower]
+    renderer_classes = [renderers.ActivityPubRenderer]
+
+    def list(self, request, *args, **kwargs):
+        page = request.GET.get('page')
+        library = actors.SYSTEM_ACTORS['library'].get_actor_instance()
+        qs = TrackFile.objects.order_by('-creation_date')
+        if page is None:
+            conf = {
+                'id': utils.full_url(reverse('federation:music:files-list')),
+                'page_size': settings.FEDERATION_COLLECTION_PAGE_SIZE,
+                'items': qs,
+                'item_serializer': AudioSerializer,
+                'actor': library,
+            }
+            serializer = serializers.PaginatedCollectionSerializer(conf)
+            data = serializer.data
+        else:
+            try:
+                page_number = int(page)
+            except:
+                return response.Response(
+                    {'page': ['Invalid page number']}, status=400)
+            p = paginator.Paginator(
+                qs, settings.FEDERATION_COLLECTION_PAGE_SIZE)
+            try:
+                page = p.page(page_number)
+            except paginator.EmptyPage:
+                return response.Response(status=404)
+            conf = {
+                'id': utils.full_url(reverse('federation:music:files-list')),
+                'page': page,
+                'item_serializer': AudioSerializer,
+                'actor': library,
+            }
+            serializer = serializers.CollectionPageSerializer(conf)
+            data = serializer.data
+
+        return response.Response(data)
diff --git a/api/tests/federation/test_views.py b/api/tests/federation/test_views.py
index 0d2ac882fb25ecac154a8426ffc2949ca7f81435..6f05a16f91893fb390b8b3ddbe60ee8e8d19bdd3 100644
--- a/api/tests/federation/test_views.py
+++ b/api/tests/federation/test_views.py
@@ -1,11 +1,13 @@
 from django.urls import reverse
+from django.core.paginator import Paginator
 
 import pytest
 
 from funkwhale_api.federation import actors
 from funkwhale_api.federation import serializers
+from funkwhale_api.federation import utils
 from funkwhale_api.federation import webfinger
-
+from funkwhale_api.music.serializers import AudioSerializer
 
 
 @pytest.mark.parametrize('system_actor', actors.SYSTEM_ACTORS.keys())
@@ -62,3 +64,89 @@ def test_wellknown_webfinger_system(
     assert response.status_code == 200
     assert response['Content-Type'] == 'application/jrd+json'
     assert response.data == serializer.data
+
+
+def test_audio_file_list_requires_authenticated_actor(
+        db, settings, api_client):
+    settings.FEDERATION_MUSIC_NEEDS_APPROVAL = True
+    url = reverse('federation:music:files-list')
+    response = api_client.get(url)
+
+    assert response.status_code == 403
+
+
+def test_audio_file_list_actor_no_page(
+        db, settings, api_client, factories):
+    settings.FEDERATION_MUSIC_NEEDS_APPROVAL = False
+    settings.FEDERATION_COLLECTION_PAGE_SIZE = 2
+    library = actors.SYSTEM_ACTORS['library'].get_actor_instance()
+    tfs = factories['music.TrackFile'].create_batch(size=5)
+    conf = {
+        'id': utils.full_url(reverse('federation:music:files-list')),
+        'page_size': 2,
+        'items': list(reversed(tfs)),  # we order by -creation_date
+        'item_serializer': AudioSerializer,
+        'actor': library
+    }
+    expected = serializers.PaginatedCollectionSerializer(conf).data
+    url = reverse('federation:music:files-list')
+    response = api_client.get(url)
+
+    assert response.status_code == 200
+    assert response.data == expected
+
+
+def test_audio_file_list_actor_page(
+        db, settings, api_client, factories):
+    settings.FEDERATION_MUSIC_NEEDS_APPROVAL = False
+    settings.FEDERATION_COLLECTION_PAGE_SIZE = 2
+    library = actors.SYSTEM_ACTORS['library'].get_actor_instance()
+    tfs = factories['music.TrackFile'].create_batch(size=5)
+    conf = {
+        'id': utils.full_url(reverse('federation:music:files-list')),
+        'page': Paginator(list(reversed(tfs)), 2).page(2),
+        'item_serializer': AudioSerializer,
+        'actor': library
+    }
+    expected = serializers.CollectionPageSerializer(conf).data
+    url = reverse('federation:music:files-list')
+    response = api_client.get(url, data={'page': 2})
+
+    assert response.status_code == 200
+    assert response.data == expected
+
+
+def test_audio_file_list_actor_page_error(
+        db, settings, api_client, factories):
+    settings.FEDERATION_MUSIC_NEEDS_APPROVAL = False
+    url = reverse('federation:music:files-list')
+    response = api_client.get(url, data={'page': 'nope'})
+
+    assert response.status_code == 400
+
+
+def test_audio_file_list_actor_page_error_too_far(
+        db, settings, api_client, factories):
+    settings.FEDERATION_MUSIC_NEEDS_APPROVAL = False
+    url = reverse('federation:music:files-list')
+    response = api_client.get(url, data={'page': 5000})
+
+    assert response.status_code == 404
+
+
+def test_library_actor_includes_library_link(db, settings, api_client):
+    actor = actors.SYSTEM_ACTORS['library'].get_actor_instance()
+    url = reverse(
+        'federation:instance-actors-detail',
+        kwargs={'actor': 'library'})
+    response = api_client.get(url)
+    expected_links = [
+        {
+            'type': 'Link',
+            'name': 'library',
+            'mediaType': 'application/activity+json',
+            'href': utils.full_url(reverse('federation:music:files-list'))
+        }
+    ]
+    assert response.status_code == 200
+    assert response.data['url'] == expected_links