diff --git a/api/funkwhale_api/playlists/views.py b/api/funkwhale_api/playlists/views.py
index f78b5b8016258f5ed018ac00aace509c4501f9e9..5ef00ebeaa7f8abdba0bf8cf693b688dcb16eade 100644
--- a/api/funkwhale_api/playlists/views.py
+++ b/api/funkwhale_api/playlists/views.py
@@ -1,9 +1,11 @@
 from rest_framework import generics, mixins, viewsets
 from rest_framework import status
 from rest_framework.response import Response
+from rest_framework.permissions import IsAuthenticatedOrReadOnly
 
 from funkwhale_api.music.models import Track
-from funkwhale_api.common.permissions import ConditionalAuthentication
+from funkwhale_api.common import permissions
+from funkwhale_api.common import fields
 
 from . import models
 from . import serializers
@@ -12,24 +14,22 @@ from . import serializers
 class PlaylistViewSet(
         mixins.RetrieveModelMixin,
         mixins.CreateModelMixin,
+        mixins.UpdateModelMixin,
         mixins.DestroyModelMixin,
         mixins.ListModelMixin,
         viewsets.GenericViewSet):
 
     serializer_class = serializers.PlaylistSerializer
     queryset = (models.Playlist.objects.all())
-    permission_classes = [ConditionalAuthentication]
-
-    def create(self, request, *args, **kwargs):
-        serializer = self.get_serializer(data=request.data)
-        serializer.is_valid(raise_exception=True)
-        instance = self.perform_create(serializer)
-        serializer = self.get_serializer(instance=instance)
-        headers = self.get_success_headers(serializer.data)
-        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
+    permission_classes = [
+        permissions.ConditionalAuthentication,
+        permissions.OwnerPermission,
+        IsAuthenticatedOrReadOnly,
+    ]
 
     def get_queryset(self):
-        return self.queryset.filter(user=self.request.user)
+        return self.queryset.filter(
+            fields.privacy_level_query(self.request.user))
 
     def perform_create(self, serializer):
         return serializer.save(
@@ -41,23 +41,39 @@ class PlaylistViewSet(
 
 
 class PlaylistTrackViewSet(
+        mixins.RetrieveModelMixin,
         mixins.CreateModelMixin,
+        mixins.UpdateModelMixin,
         mixins.DestroyModelMixin,
         mixins.ListModelMixin,
         viewsets.GenericViewSet):
 
     serializer_class = serializers.PlaylistTrackSerializer
     queryset = (models.PlaylistTrack.objects.all())
-    permission_classes = [ConditionalAuthentication]
+    permission_classes = [
+        permissions.ConditionalAuthentication,
+        permissions.OwnerPermission,
+        IsAuthenticatedOrReadOnly,
+    ]
 
     def create(self, request, *args, **kwargs):
         serializer = serializers.PlaylistTrackCreateSerializer(
             data=request.data)
         serializer.is_valid(raise_exception=True)
+        if serializer.validated_data['playlist'].user != request.user:
+            return Response(
+                {'playlist': [
+                    'This playlist does not exists or you do not have the'
+                    'permission to edit it']
+                },
+                status=400)
         instance = self.perform_create(serializer)
         serializer = self.get_serializer(instance=instance)
         headers = self.get_success_headers(serializer.data)
         return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
 
     def get_queryset(self):
-        return self.queryset.filter(playlist__user=self.request.user)
+        return self.queryset.filter(
+            fields.privacy_level_query(
+                self.request.user,
+                lookup_field='playlist__privacy_level'))
diff --git a/api/tests/playlists/test_views.py b/api/tests/playlists/test_views.py
index f3084e6a06b93121fd7f9c696d446543b6d2b0e9..0a3549b84c3df3c8cff0651a36d7ce79d685e46c 100644
--- a/api/tests/playlists/test_views.py
+++ b/api/tests/playlists/test_views.py
@@ -1,4 +1,6 @@
 import json
+import pytest
+
 from django.urls import reverse
 from django.core.exceptions import ValidationError
 from django.utils import timezone
@@ -48,3 +50,67 @@ def test_can_add_playlist_track_via_api(factories, logged_in_api_client):
     response = logged_in_api_client.post(url, data)
     plts = logged_in_api_client.user.playlists.latest('id').playlist_tracks.all()
     assert plts.first().track == tracks[0]
+
+
+@pytest.mark.parametrize('name,method', [
+    ('api:v1:playlist-tracks-list', 'post'),
+    ('api:v1:playlists-list', 'post'),
+])
+def test_url_requires_login(name, method, factories, api_client):
+    url = reverse(name)
+
+    response = getattr(api_client, method)(url, {})
+
+    assert response.status_code == 401
+
+
+def test_only_can_add_track_on_own_playlist_via_api(
+        factories, logged_in_api_client):
+    track = factories['music.Track']()
+    playlist = factories['playlists.Playlist']()
+    url = reverse('api:v1:playlist-tracks-list')
+    data = {
+        'playlist': playlist.pk,
+        'track': track.pk
+    }
+
+    response = logged_in_api_client.post(url, data)
+    assert response.status_code == 400
+    assert playlist.playlist_tracks.count() == 0
+
+
+@pytest.mark.parametrize('level', ['instance', 'me', 'followers'])
+def test_playlist_privacy_respected_in_list_anon(level, factories, api_client):
+    factories['playlists.Playlist'](privacy_level=level)
+    url = reverse('api:v1:playlists-list')
+    response = api_client.get(url)
+
+    assert response.data['count'] == 0
+
+
+@pytest.mark.parametrize('method', ['PUT', 'PATCH', 'DELETE'])
+def test_only_owner_can_edit_playlist(method, factories, api_client):
+    playlist = factories['playlists.Playlist']()
+    url = reverse('api:v1:playlists-detail', kwargs={'pk': playlist.pk})
+    response = api_client.get(url)
+
+    assert response.status_code == 404
+
+
+@pytest.mark.parametrize('method', ['PUT', 'PATCH', 'DELETE'])
+def test_only_owner_can_edit_playlist_track(method, factories, api_client):
+    plt = factories['playlists.PlaylistTrack']()
+    url = reverse('api:v1:playlist-tracks-detail', kwargs={'pk': plt.pk})
+    response = api_client.get(url)
+
+    assert response.status_code == 404
+
+
+@pytest.mark.parametrize('level', ['instance', 'me', 'followers'])
+def test_playlist_track_privacy_respected_in_list_anon(
+        level, factories, api_client):
+    factories['playlists.PlaylistTrack'](playlist__privacy_level=level)
+    url = reverse('api:v1:playlist-tracks-list')
+    response = api_client.get(url)
+
+    assert response.data['count'] == 0