diff --git a/api/funkwhale_api/radios/migrations/0004_auto_20180107_1813.py b/api/funkwhale_api/radios/migrations/0004_auto_20180107_1813.py
new file mode 100644
index 0000000000000000000000000000000000000000..fc768b303365e3146054b7f05749d5dd0fc9d259
--- /dev/null
+++ b/api/funkwhale_api/radios/migrations/0004_auto_20180107_1813.py
@@ -0,0 +1,36 @@
+# Generated by Django 2.0 on 2018-01-07 18:13
+
+from django.conf import settings
+import django.contrib.postgres.fields.jsonb
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+        ('radios', '0003_auto_20160521_1708'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Radio',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=100)),
+                ('description', models.TextField(blank=True)),
+                ('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
+                ('is_public', models.BooleanField(default=False)),
+                ('version', models.PositiveIntegerField(default=0)),
+                ('config', django.contrib.postgres.fields.jsonb.JSONField()),
+                ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='radios', to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+        migrations.AddField(
+            model_name='radiosession',
+            name='custom_radio',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sessions', to='radios.Radio'),
+        ),
+    ]
diff --git a/api/funkwhale_api/radios/models.py b/api/funkwhale_api/radios/models.py
index 984b34a1f7d86230c6e9186c123246286f0c6eac..d9c12534c03f779d497a1a9e7ae43e12cc3bb32f 100644
--- a/api/funkwhale_api/radios/models.py
+++ b/api/funkwhale_api/radios/models.py
@@ -1,11 +1,34 @@
 from django.db import models
 from django.utils import timezone
 from django.core.exceptions import ValidationError
+from django.contrib.postgres.fields import JSONField
 from django.contrib.contenttypes.fields import GenericForeignKey
 from django.contrib.contenttypes.models import ContentType
 
 from funkwhale_api.music.models import Track
 
+from . import filters
+
+
+class Radio(models.Model):
+    CONFIG_VERSION = 0
+    user = models.ForeignKey(
+        'users.User',
+        related_name='radios',
+        null=True,
+        blank=True,
+        on_delete=models.CASCADE)
+    name = models.CharField(max_length=100)
+    description = models.TextField(blank=True)
+    creation_date = models.DateTimeField(default=timezone.now)
+    is_public = models.BooleanField(default=False)
+    version = models.PositiveIntegerField(default=0)
+    config = JSONField()
+
+    def get_candidates(self):
+        return filters.run(self.config)
+
+
 class RadioSession(models.Model):
     user = models.ForeignKey(
         'users.User',
@@ -15,6 +38,12 @@ class RadioSession(models.Model):
         on_delete=models.CASCADE)
     session_key = models.CharField(max_length=100, null=True, blank=True)
     radio_type = models.CharField(max_length=50)
+    custom_radio = models.ForeignKey(
+        Radio,
+        related_name='sessions',
+        null=True,
+        blank=True,
+        on_delete=models.CASCADE)
     creation_date = models.DateTimeField(default=timezone.now)
     related_object_content_type = models.ForeignKey(
         ContentType,
@@ -51,6 +80,7 @@ class RadioSession(models.Model):
         from . import radios
         return registry[self.radio_type](session=self)
 
+
 class RadioSessionTrack(models.Model):
     session = models.ForeignKey(
         RadioSession, related_name='session_tracks', on_delete=models.CASCADE)