diff --git a/config/api_urls.py b/config/api_urls.py
index 2af30e37e4ff814471e159d8bf8232f50fd67fdd..5519cc63ba0ada49308626c23a84af56a5eba24c 100644
--- a/config/api_urls.py
+++ b/config/api_urls.py
@@ -1,6 +1,7 @@
 from rest_framework import routers
 from django.conf.urls import include, url
 from funkwhale_api.music import views
+from funkwhale_api.playlists import views as playlists_views
 
 router = routers.SimpleRouter()
 router.register(r'tags', views.TagViewSet, 'tags')
@@ -9,6 +10,8 @@ router.register(r'artists', views.ArtistViewSet, 'artists')
 router.register(r'albums', views.AlbumViewSet, 'albums')
 router.register(r'import-batches', views.ImportBatchViewSet, 'import-batches')
 router.register(r'submit', views.SubmitViewSet, 'submit')
+router.register(r'playlists', playlists_views.PlaylistViewSet, 'playlists')
+router.register(r'playlist-tracks', playlists_views.PlaylistTrackViewSet, 'playlist-tracks')
 urlpatterns = router.urls
 
 urlpatterns += [
diff --git a/config/settings/common.py b/config/settings/common.py
index 9ac3b47e4b321f9e1b996e882e419c589fd97ca8..6efad404cd7b832892e9643263645b2595ae3ee0 100644
--- a/config/settings/common.py
+++ b/config/settings/common.py
@@ -52,6 +52,7 @@ THIRD_PARTY_APPS = (
     'cachalot',
     'rest_auth',
     'rest_auth.registration',
+    'mptt',
 )
 
 # Apps specific for this project go here.
@@ -62,7 +63,7 @@ LOCAL_APPS = (
     'funkwhale_api.favorites',
     'funkwhale_api.radios',
     'funkwhale_api.history',
-    # 'funkwhale_api.playlists',
+    'funkwhale_api.playlists',
 )
 
 # See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
diff --git a/funkwhale_api/music/migrations/0012_auto_20161122_1905.py b/funkwhale_api/music/migrations/0012_auto_20161122_1905.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d7e25246bbea637c2f5d91fbac7b06cab851af1
--- /dev/null
+++ b/funkwhale_api/music/migrations/0012_auto_20161122_1905.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import versatileimagefield.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('music', '0011_rename_files'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='album',
+            name='cover',
+            field=versatileimagefield.fields.VersatileImageField(null=True, blank=True, upload_to='albums/covers/%Y/%m/%d'),
+        ),
+    ]
diff --git a/funkwhale_api/playlists/admin.py b/funkwhale_api/playlists/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..b337154c9c6ae3e9d86a22a250ca39c8b97533bd
--- /dev/null
+++ b/funkwhale_api/playlists/admin.py
@@ -0,0 +1,17 @@
+from django.contrib import admin
+
+from . import models
+
+
+@admin.register(models.Playlist)
+class PlaylistAdmin(admin.ModelAdmin):
+    list_display = ['name', 'user', 'is_public', 'creation_date']
+    search_fields = ['name', ]
+    list_select_related = True
+
+
+@admin.register(models.PlaylistTrack)
+class PlaylistTrackAdmin(admin.ModelAdmin):
+    list_display = ['playlist', 'track', 'position', ]
+    search_fields = ['track__name', 'playlist__name']
+    list_select_related = True
diff --git a/funkwhale_api/playlists/migrations/0001_initial.py b/funkwhale_api/playlists/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..f42ca154e6064cb9de8f2f8dbb28c114e37dc5bd
--- /dev/null
+++ b/funkwhale_api/playlists/migrations/0001_initial.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+from django.conf import settings
+import django.utils.timezone
+import mptt.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('music', '0012_auto_20161122_1905'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Playlist',
+            fields=[
+                ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
+                ('name', models.CharField(max_length=50)),
+                ('is_public', models.BooleanField(default=False)),
+                ('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
+                ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='playlists')),
+            ],
+        ),
+        migrations.CreateModel(
+            name='PlaylistTrack',
+            fields=[
+                ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
+                ('lft', models.PositiveIntegerField(db_index=True, editable=False)),
+                ('rght', models.PositiveIntegerField(db_index=True, editable=False)),
+                ('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
+                ('position', models.PositiveIntegerField(db_index=True, editable=False)),
+                ('playlist', models.ForeignKey(to='playlists.Playlist', related_name='playlist_tracks')),
+                ('previous', mptt.fields.TreeOneToOneField(null=True, to='playlists.PlaylistTrack', related_name='next', blank=True)),
+                ('track', models.ForeignKey(to='music.Track', related_name='playlist_tracks')),
+            ],
+            options={
+                'ordering': ('-playlist', 'position'),
+            },
+        ),
+    ]
diff --git a/funkwhale_api/playlists/migrations/__init__.py b/funkwhale_api/playlists/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/funkwhale_api/playlists/models.py b/funkwhale_api/playlists/models.py
index c869ab8e81df6d0f8a5f592f6d588b40c0025de0..35a30a704a06a494d0b37c322150cc6ee81cc660 100644
--- a/funkwhale_api/playlists/models.py
+++ b/funkwhale_api/playlists/models.py
@@ -1,6 +1,8 @@
 from django.db import models
 from django.utils import timezone
 
+from mptt.models import MPTTModel, TreeOneToOneField
+
 
 class Playlist(models.Model):
     name = models.CharField(max_length=50)
@@ -8,24 +10,24 @@ class Playlist(models.Model):
     user = models.ForeignKey('users.User', related_name="playlists")
     creation_date = models.DateTimeField(default=timezone.now)
 
-    def add_tracks(self, tracks):
-        try:
-            last_position = self.playlist_tracks.objects.last().position
-        except AttributeError:
-            last_position = -1
-
-        playlist_tracks = []
-        for idx, track in enumerate(tracks):
-            plt = PlaylistTrack(position=last_position + idx +1, track=track, playlist=self)
-            plt.save()
-            playlist_tracks.append(plt)
-        return playlist_tracks
-
-class PlaylistTrack(models.Model):
-    position = models.PositiveIntegerField(default=0)
+    def __str__(self):
+        return self.name
+
+    def add_track(self, track, previous=None):
+        plt = PlaylistTrack(previous=previous, track=track, playlist=self)
+        plt.save()
+
+        return plt
+
+
+class PlaylistTrack(MPTTModel):
     track = models.ForeignKey('music.Track', related_name='playlist_tracks')
+    previous = TreeOneToOneField('self', blank=True, null=True, related_name='next')
     playlist = models.ForeignKey(Playlist, related_name='playlist_tracks')
 
+    class MPTTMeta:
+        level_attr = 'position'
+        parent_attr = 'previous'
+
     class Meta:
-        unique_together = ('playlist', 'position')
         ordering = ('-playlist', 'position')
diff --git a/funkwhale_api/playlists/serializers.py b/funkwhale_api/playlists/serializers.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f889d53e8b7c3163dfb1c017af2df14665d3df7
--- /dev/null
+++ b/funkwhale_api/playlists/serializers.py
@@ -0,0 +1,30 @@
+from rest_framework import serializers
+from taggit.models import Tag
+
+from funkwhale_api.music.serializers import TrackSerializerNested
+
+from . import models
+
+
+class PlaylistTrackSerializer(serializers.ModelSerializer):
+    track = TrackSerializerNested()
+
+    class Meta:
+        model = models.PlaylistTrack
+        fields = ('id', 'track', 'playlist', 'position')
+
+
+class PlaylistTrackCreateSerializer(serializers.ModelSerializer):
+
+    class Meta:
+        model = models.PlaylistTrack
+        fields = ('id', 'track', 'playlist', 'position')
+
+
+class PlaylistSerializer(serializers.ModelSerializer):
+    playlist_tracks = PlaylistTrackSerializer(many=True, read_only=True)
+
+    class Meta:
+        model = models.Playlist
+        fields = ('id', 'name', 'is_public', 'creation_date', 'playlist_tracks')
+        read_only_fields = ['id', 'playlist_tracks', 'creation_date']
diff --git a/funkwhale_api/playlists/tests/test_playlists.py b/funkwhale_api/playlists/tests/test_playlists.py
index ab056d90750bfac4735e99c8ed27b0214dee4a6e..056ca06e6e9325eb35ee009291a294a38e2ba47b 100644
--- a/funkwhale_api/playlists/tests/test_playlists.py
+++ b/funkwhale_api/playlists/tests/test_playlists.py
@@ -8,6 +8,8 @@ from model_mommy import mommy
 
 from funkwhale_api.users.models import User
 from funkwhale_api.playlists import models
+from funkwhale_api.playlists.serializers import PlaylistSerializer
+
 
 class TestPlayLists(TestCase):
 
@@ -16,14 +18,48 @@ class TestPlayLists(TestCase):
         self.user = User.objects.create_user(username='test', email='test@test.com', password='test')
 
     def test_can_create_playlist(self):
-        tracks = mommy.make('music.Track', _quantity=5)
+        tracks = list(mommy.make('music.Track', _quantity=5))
         playlist = models.Playlist.objects.create(user=self.user, name="test")
 
-        playlist.add_tracks(tracks)
+        previous = None
+        for i in range(len(tracks)):
+            previous = playlist.add_track(tracks[i], previous=previous)
 
         playlist_tracks = list(playlist.playlist_tracks.all())
 
+        previous = None
         for idx, track in enumerate(tracks):
-            self.assertEqual(playlist_tracks[idx].position, idx)
-            self.assertEqual(playlist_tracks[idx].track, track)
-            self.assertEqual(playlist_tracks[idx].playlist, playlist)
+            plt = playlist_tracks[idx]
+            self.assertEqual(plt.position, idx)
+            self.assertEqual(plt.track, track)
+            if previous:
+                self.assertEqual(playlist_tracks[idx + 1], previous)
+            self.assertEqual(plt.playlist, playlist)
+
+    def test_can_create_playlist_via_api(self):
+        self.client.login(username=self.user.username, password='test')
+        url = reverse('api:playlists-list')
+        data = {
+            'name': 'test',
+        }
+
+        response = self.client.post(url, data)
+
+        playlist = self.user.playlists.latest('id')
+        self.assertEqual(playlist.name, 'test')
+
+    def test_can_add_playlist_track_via_api(self):
+        tracks = list(mommy.make('music.Track', _quantity=5))
+        playlist = models.Playlist.objects.create(user=self.user, name="test")
+
+        self.client.login(username=self.user.username, password='test')
+
+        url = reverse('api:playlist-tracks-list')
+        data = {
+            'playlist': playlist.pk,
+            'track': tracks[0].pk
+        }
+
+        response = self.client.post(url, data)
+        plts = self.user.playlists.latest('id').playlist_tracks.all()
+        self.assertEqual(plts.first().track, tracks[0])
diff --git a/funkwhale_api/playlists/views.py b/funkwhale_api/playlists/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..1a88d231e46c63d865554f56b40128a24b9edac4
--- /dev/null
+++ b/funkwhale_api/playlists/views.py
@@ -0,0 +1,58 @@
+from rest_framework import generics, mixins, viewsets
+from rest_framework import status
+from rest_framework.response import Response
+
+from funkwhale_api.music.models import Track
+from funkwhale_api.common.permissions import ConditionalAuthentication
+
+from . import models
+from . import serializers
+
+
+class PlaylistViewSet(
+        mixins.RetrieveModelMixin,
+        mixins.CreateModelMixin,
+        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)
+
+    def get_queryset(self):
+        return self.queryset.filter(user=self.request.user)
+
+    def perform_create(self, serializer):
+        return serializer.save(user=self.request.user)
+
+
+class PlaylistTrackViewSet(
+        mixins.CreateModelMixin,
+        mixins.DestroyModelMixin,
+        mixins.ListModelMixin,
+        viewsets.GenericViewSet):
+
+    serializer_class = serializers.PlaylistTrackSerializer
+    queryset = (models.PlaylistTrack.objects.all())
+    permission_classes = [ConditionalAuthentication]
+
+    def create(self, request, *args, **kwargs):
+        serializer = serializers.PlaylistTrackCreateSerializer(
+            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)
+
+    def get_queryset(self):
+        return self.queryset.filter(playlist__user=self.request.user)
diff --git a/requirements/base.txt b/requirements/base.txt
index 2599948fb2e6be6f3a82e211360d0e2a37176ce1..4e9dd953db14736bbd58d74b520cecf51c3a19c2 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -48,6 +48,7 @@ youtube_dl>=2015.12.21
 djangorestframework
 djangorestframework-jwt
 django-celery
+django-mptt
 google-api-python-client
 arrow
 django-taggit