diff --git a/api/funkwhale_api/federation/migrations/0001_initial.py b/api/funkwhale_api/federation/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..a9157e57e3fa123c5e79b2d23176f7cd744ee926
--- /dev/null
+++ b/api/funkwhale_api/federation/migrations/0001_initial.py
@@ -0,0 +1,37 @@
+# Generated by Django 2.0.3 on 2018-03-31 13:43
+
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Actor',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('url', models.URLField(db_index=True, max_length=500, unique=True)),
+                ('outbox_url', models.URLField(max_length=500)),
+                ('inbox_url', models.URLField(max_length=500)),
+                ('following_url', models.URLField(blank=True, max_length=500, null=True)),
+                ('followers_url', models.URLField(blank=True, max_length=500, null=True)),
+                ('shared_inbox_url', models.URLField(blank=True, max_length=500, null=True)),
+                ('type', models.CharField(choices=[('Person', 'Person'), ('Application', 'Application'), ('Group', 'Group'), ('Organization', 'Organization'), ('Service', 'Service')], default='Person', max_length=25)),
+                ('name', models.CharField(blank=True, max_length=200, null=True)),
+                ('domain', models.CharField(max_length=1000)),
+                ('summary', models.CharField(blank=True, max_length=500, null=True)),
+                ('preferred_username', models.CharField(blank=True, max_length=200, null=True)),
+                ('public_key', models.CharField(blank=True, max_length=5000, null=True)),
+                ('private_key', models.CharField(blank=True, max_length=5000, null=True)),
+                ('creation_date', models.DateTimeField(default=django.utils.timezone.now)),
+                ('last_fetch_date', models.DateTimeField(default=django.utils.timezone.now)),
+                ('manually_approves_followers', models.NullBooleanField(default=None)),
+            ],
+        ),
+    ]
diff --git a/api/funkwhale_api/federation/migrations/__init__.py b/api/funkwhale_api/federation/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/api/funkwhale_api/federation/models.py b/api/funkwhale_api/federation/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..201307d46c93214f9cd7f0066eb60bff2a45bd88
--- /dev/null
+++ b/api/funkwhale_api/federation/models.py
@@ -0,0 +1,40 @@
+from django.conf import settings
+from django.db import models
+from django.utils import timezone
+
+TYPE_CHOICES = [
+    ('Person', 'Person'),
+    ('Application', 'Application'),
+    ('Group', 'Group'),
+    ('Organization', 'Organization'),
+    ('Service', 'Service'),
+]
+
+
+class Actor(models.Model):
+    url = models.URLField(unique=True, max_length=500, db_index=True)
+    outbox_url = models.URLField(max_length=500)
+    inbox_url = models.URLField(max_length=500)
+    following_url = models.URLField(max_length=500, null=True, blank=True)
+    followers_url = models.URLField(max_length=500, null=True, blank=True)
+    shared_inbox_url = models.URLField(max_length=500, null=True, blank=True)
+    type = models.CharField(
+        choices=TYPE_CHOICES, default='Person', max_length=25)
+    name = models.CharField(max_length=200, null=True, blank=True)
+    domain = models.CharField(max_length=1000)
+    summary = models.CharField(max_length=500, null=True, blank=True)
+    preferred_username = models.CharField(
+        max_length=200, null=True, blank=True)
+    public_key = models.CharField(max_length=5000, null=True, blank=True)
+    private_key = models.CharField(max_length=5000, null=True, blank=True)
+    creation_date = models.DateTimeField(default=timezone.now)
+    last_fetch_date = models.DateTimeField(
+        default=timezone.now)
+    manually_approves_followers = models.NullBooleanField(default=None)
+
+    @property
+    def webfinger_subject(self):
+        return '{}@{}'.format(
+            self.preferred_username,
+            settings.FEDERATION_HOSTNAME,
+        )