diff --git a/SciPost_v1/settings/base.py b/SciPost_v1/settings/base.py
index 47b1c76fd61a63d008d33b8dadd844331230fa25..e0f5c8fb342cf0195d871009db767669754a46f4 100644
--- a/SciPost_v1/settings/base.py
+++ b/SciPost_v1/settings/base.py
@@ -86,6 +86,7 @@ INSTALLED_APPS = (
     'django_countries',
     'django_extensions',
     'haystack',
+    'affiliates',
     'api',
     'apimail',
     'careers',
diff --git a/SciPost_v1/urls.py b/SciPost_v1/urls.py
index cb15a9fb936db09e45466365dc9cad1af5c14ad2..33de077734ed7070bbe92a66655c23b7fc319976 100644
--- a/SciPost_v1/urls.py
+++ b/SciPost_v1/urls.py
@@ -28,6 +28,10 @@ urlpatterns = [
     url(r'^sitemap.xml$', scipost_views.sitemap_xml, name='sitemap_xml'),
     url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
     url(r'^admin/', admin.site.urls),
+    path(
+        'affiliates/',
+        include('affiliates.urls', namespace='affiliates')
+    ),
     url(r'^api/', include('api.urls', namespace='api')),
     path(
         'mail/',
diff --git a/affiliates/__init__.py b/affiliates/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/affiliates/admin.py b/affiliates/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..550598ea9172c950a65ab84b7fb33f04acf7644c
--- /dev/null
+++ b/affiliates/admin.py
@@ -0,0 +1,38 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.contrib import admin
+
+from .models import (
+    AffiliatePublisher, AffiliateJournal,
+    AffiliatePublication, AffiliatePubFraction
+)
+
+
+admin.site.register(AffiliatePublisher)
+
+
+class AffiliateJournalAdmin(admin.ModelAdmin):
+    search_fields = ['name']
+    list_display = ['name', 'publisher']
+
+admin.site.register(AffiliateJournal, AffiliateJournalAdmin)
+
+
+class AffiliatePubFractionInline(admin.TabularInline):
+    model = AffiliatePubFraction
+    list_display = ('organization', 'publication', 'fraction')
+    autocomplete_fields = [
+        'organization',
+    ]
+
+class AffiliatePublicationAdmin(admin.ModelAdmin):
+    search_fields = ['doi', 'journal',]
+    list_display = [
+        'journal',
+        'doi',
+    ]
+    inlines = [AffiliatePubFractionInline,]
+
+admin.site.register(AffiliatePublication, AffiliatePublicationAdmin)
diff --git a/affiliates/apps.py b/affiliates/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..dd56ccff182cec1540993782a37b7fbaa58a74cd
--- /dev/null
+++ b/affiliates/apps.py
@@ -0,0 +1,9 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.apps import AppConfig
+
+
+class AffiliatesConfig(AppConfig):
+    name = 'affiliates'
diff --git a/affiliates/converters.py b/affiliates/converters.py
new file mode 100644
index 0000000000000000000000000000000000000000..c5621a88c387a267a2647173e9258591b03388ae
--- /dev/null
+++ b/affiliates/converters.py
@@ -0,0 +1,11 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.urls.converters import StringConverter
+
+from .regexes import DOI_AFFILIATEPUBLICATION_REGEX
+
+
+class Crossref_DOI_converter(StringConverter):
+    regex = DOI_AFFILIATEPUBLICATION_REGEX
diff --git a/affiliates/migrations/0001_initial.py b/affiliates/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..2678619a929d7a82d80d10d81b4e28350f20e7c2
--- /dev/null
+++ b/affiliates/migrations/0001_initial.py
@@ -0,0 +1,68 @@
+# Generated by Django 2.2.16 on 2021-05-08 14:20
+
+from decimal import Decimal
+import django.contrib.postgres.fields.jsonb
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+import re
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('organizations', '0012_auto_20210310_2026'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='AffiliateJournal',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=256)),
+                ('short_name', models.CharField(default='', max_length=256)),
+                ('slug', models.SlugField(max_length=128, validators=[django.core.validators.RegexValidator(re.compile('^[-\\w]+\\Z'), "Enter a valid 'slug' consisting of Unicode letters, numbers, underscores, or hyphens.", 'invalid')])),
+            ],
+            options={
+                'ordering': ['publisher', 'name'],
+            },
+        ),
+        migrations.CreateModel(
+            name='AffiliatePublisher',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=256)),
+            ],
+            options={
+                'ordering': ['name'],
+            },
+        ),
+        migrations.CreateModel(
+            name='AffiliatePublication',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('doi', models.CharField(db_index=True, max_length=256, unique=True, validators=[django.core.validators.RegexValidator('^10.\\d{4,9}/[-._;()/:a-zA-Z0-9]+$', 'Only expressions with regex 10.\\d{4,9}/[-._;()/:a-zA-Z0-9]+ are allowed.')])),
+                ('_metadata_crossref', django.contrib.postgres.fields.jsonb.JSONField(default=dict)),
+                ('journal', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='affiliates.AffiliateJournal')),
+            ],
+        ),
+        migrations.AddField(
+            model_name='affiliatejournal',
+            name='publisher',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='journals', to='affiliates.AffiliatePublisher'),
+        ),
+        migrations.CreateModel(
+            name='AffiliatePubFraction',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('fraction', models.DecimalField(decimal_places=3, default=Decimal('0.000'), max_digits=4)),
+                ('organization', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='affiliate_pubfractions', to='organizations.Organization')),
+                ('publication', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pubfractions', to='affiliates.AffiliatePublication')),
+            ],
+            options={
+                'unique_together': {('organization', 'publication')},
+            },
+        ),
+    ]
diff --git a/affiliates/migrations/0002_auto_20210508_1629.py b/affiliates/migrations/0002_auto_20210508_1629.py
new file mode 100644
index 0000000000000000000000000000000000000000..e683662f49a0abd1345a386fcce994264f77711d
--- /dev/null
+++ b/affiliates/migrations/0002_auto_20210508_1629.py
@@ -0,0 +1,20 @@
+# Generated by Django 2.2.16 on 2021-05-08 14:29
+
+import django.core.validators
+from django.db import migrations, models
+import re
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('affiliates', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='affiliatejournal',
+            name='slug',
+            field=models.SlugField(max_length=128, unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-\\w]+\\Z'), "Enter a valid 'slug' consisting of Unicode letters, numbers, underscores, or hyphens.", 'invalid')]),
+        ),
+    ]
diff --git a/affiliates/migrations/0003_auto_20210508_1653.py b/affiliates/migrations/0003_auto_20210508_1653.py
new file mode 100644
index 0000000000000000000000000000000000000000..893701aefccf7585c3ed140f22dfd590d5879e24
--- /dev/null
+++ b/affiliates/migrations/0003_auto_20210508_1653.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.2.16 on 2021-05-08 14:53
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('affiliates', '0002_auto_20210508_1629'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='affiliatepublication',
+            name='journal',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='publications', to='affiliates.AffiliateJournal'),
+        ),
+    ]
diff --git a/affiliates/migrations/__init__.py b/affiliates/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/affiliates/models/__init__.py b/affiliates/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..991e724208301c249374ddd480b7cadc5994a244
--- /dev/null
+++ b/affiliates/models/__init__.py
@@ -0,0 +1,11 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from .publisher import AffiliatePublisher
+
+from .journal import AffiliateJournal
+
+from .publication import AffiliatePublication
+
+from .pubfraction import AffiliatePubFraction
diff --git a/affiliates/models/journal.py b/affiliates/models/journal.py
new file mode 100644
index 0000000000000000000000000000000000000000..989f257e6364c9d1757fc7df5dc78c508371ce82
--- /dev/null
+++ b/affiliates/models/journal.py
@@ -0,0 +1,51 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.core.validators import validate_unicode_slug
+from django.db import models
+from django.urls import reverse
+
+
+class AffiliateJournal(models.Model):
+    """
+    A Journal which piggybacks on SciPost's services.
+    """
+
+    publisher = models.ForeignKey(
+        'affiliates.AffiliatePublisher',
+        on_delete=models.CASCADE,
+        related_name='journals'
+    )
+
+    name = models.CharField(
+        max_length=256
+    )
+
+    # Note that the short name can be just as long as the full name. This is because not all
+    # journals have abbreviated names in Crossref, and instead return the full journal name.
+    short_name = models.CharField(
+        max_length=256,
+        default=""
+    )
+
+    slug = models.SlugField(
+        max_length=128,
+        validators=[validate_unicode_slug,],
+        unique=True
+    )
+
+    class Meta:
+        ordering = [
+            'publisher',
+            'name'
+        ]
+
+    def __str__(self):
+        return self.name
+
+    def get_absolute_url(self):
+        return reverse(
+            'affiliates:journal_detail',
+            kwargs={'slug': self.slug}
+        )
diff --git a/affiliates/models/pubfraction.py b/affiliates/models/pubfraction.py
new file mode 100644
index 0000000000000000000000000000000000000000..92d87a9131007efd67e2088af3bd32cc3836184c
--- /dev/null
+++ b/affiliates/models/pubfraction.py
@@ -0,0 +1,40 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from decimal import Decimal
+
+from django.db import models
+
+
+class AffiliatePubFraction(models.Model):
+    """
+    PubFraction for an AffiliatePublication.
+    """
+    organization = models.ForeignKey(
+        'organizations.Organization',
+        on_delete=models.CASCADE,
+        related_name='affiliate_pubfractions'
+    )
+    publication = models.ForeignKey(
+        'affiliates.AffiliatePublication',
+        on_delete=models.CASCADE,
+        related_name='pubfractions'
+    )
+    fraction = models.DecimalField(
+        max_digits=4,
+        decimal_places=3,
+        default=Decimal('0.000')
+    )
+
+    class Meta:
+        unique_together = (
+            ('organization', 'publication'),
+        )
+
+    def __str__(self):
+        return 'PubFraction of %s for %s: %d' % (
+            self.organization,
+            self.publication,
+            self.fraction
+        )
diff --git a/affiliates/models/publication.py b/affiliates/models/publication.py
new file mode 100644
index 0000000000000000000000000000000000000000..a463850534cfed69b6dd1dda3b31c4cc2cd30ba7
--- /dev/null
+++ b/affiliates/models/publication.py
@@ -0,0 +1,41 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.contrib.postgres.fields import JSONField
+from django.db import models
+from django.urls import reverse
+
+from ..validators import doi_affiliatepublication_validator
+
+
+class AffiliatePublication(models.Model):
+    """
+    Publication item from an affiliate Publisher/Journal.
+    """
+
+    doi = models.CharField(
+        max_length=256,
+        unique=True,
+        db_index=True,
+        validators=[doi_affiliatepublication_validator]
+    )
+    _metadata_crossref = JSONField(
+        default=dict,
+
+    )
+
+    journal = models.ForeignKey(
+        'affiliates.AffiliateJournal',
+        on_delete=models.CASCADE,
+        related_name='publications'
+    )
+
+    def __str__(self):
+        return self.doi
+
+    def get_absolute_url(self):
+        return reverse(
+            'affiliates:publication_detail',
+            kwargs={'doi': self.doi}
+        )
diff --git a/affiliates/models/publisher.py b/affiliates/models/publisher.py
new file mode 100644
index 0000000000000000000000000000000000000000..c8305c638cc23f78063571d0e79f3becd310aac8
--- /dev/null
+++ b/affiliates/models/publisher.py
@@ -0,0 +1,23 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.db import models
+
+
+class AffiliatePublisher(models.Model):
+    """
+    A Publisher which piggybacks on SciPost's services.
+    """
+
+    name = models.CharField(
+        max_length=256
+    )
+
+    class Meta:
+        ordering = [
+            'name'
+        ]
+
+    def __str__(self):
+        return self.name
diff --git a/affiliates/regexes.py b/affiliates/regexes.py
new file mode 100644
index 0000000000000000000000000000000000000000..c334c8f5757e4ea930f1d11791417912e8fdd47a
--- /dev/null
+++ b/affiliates/regexes.py
@@ -0,0 +1,5 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+DOI_AFFILIATEPUBLICATION_REGEX = r'10.\d{4,9}/[-._;()/:a-zA-Z0-9]+'
diff --git a/affiliates/templates/affiliates/affiliatejournal_detail.html b/affiliates/templates/affiliates/affiliatejournal_detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..b30a23998b49efc4da3aa36a5a53c3bdbcafec62
--- /dev/null
+++ b/affiliates/templates/affiliates/affiliatejournal_detail.html
@@ -0,0 +1,22 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: Affiliate Journal: {{ object }}{% endblock %}
+
+{% block content %}
+
+  <h2 class="highlight">Affiliate Journal: {{ object }}</h2>
+
+  <h3 class="highlight">Publications</h3>
+  <table class="table">
+    {% for pub in object.publications.all %}
+      <tr>
+	<td><a href="{{ pub.get_absolute_url }}">{{ pub }}</a></td>
+      </tr>
+    {% empty %}
+      <tr>
+	<td>No publications yet</td>
+      </tr>
+    {% endfor %}
+  </table>
+
+{% endblock content %}
diff --git a/affiliates/templates/affiliates/affiliatejournal_list.html b/affiliates/templates/affiliates/affiliatejournal_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..cc71786c1da477b1d83fe14946b3cbe4f3d643c4
--- /dev/null
+++ b/affiliates/templates/affiliates/affiliatejournal_list.html
@@ -0,0 +1,17 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: Affiliate Journals{% endblock %}
+
+{% block content %}
+
+  <h2 class="highlight">Affiliate Journals</h2>
+
+  <ul>
+    {% for journal in object_list %}
+      <li><a href="{{ journal.get_absolute_url }}">{{ journal }}</a></li>
+    {% empty %}
+      <li>There are no affiliate journals at this moment</li>
+    {% endfor %}
+  </ul>
+
+{% endblock content %}
diff --git a/affiliates/templates/affiliates/affiliatepublication_detail.html b/affiliates/templates/affiliates/affiliatepublication_detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..4c180f8a8c37a4d3d018aa2bf4fb644de8cb6a09
--- /dev/null
+++ b/affiliates/templates/affiliates/affiliatepublication_detail.html
@@ -0,0 +1,23 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: Publication: {{ object }}{% endblock %}
+
+{% block content %}
+
+  <h2 class="highlight">Publication: {{ object }} </h2>
+  <p>(in affiliate journal {{ object.journal }})</p>
+
+  <h3 class="highlight">PubFractions</h3>
+  <table class="table">
+    {% for pubfrac in object.pufractions.all %}
+      <tr>
+	<td>{{ pubfrac }}</td>
+      </tr>
+    {% empty %}
+      <tr>
+	<td>No PubFractions yet</td>
+      </tr>
+    {% endfor %}
+  </table>
+
+{% endblock content %}
diff --git a/affiliates/urls.py b/affiliates/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..91ce179305ffcc40f5a5c21813183a36bd78c854
--- /dev/null
+++ b/affiliates/urls.py
@@ -0,0 +1,30 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.urls import path, register_converter
+
+from . import views
+from .converters import Crossref_DOI_converter
+
+app_name='affiliates'
+
+register_converter(Crossref_DOI_converter, 'doi')
+
+urlpatterns = [
+    path( # /affiliates/journals
+        'journals',
+        views.AffiliateJournalListView.as_view(),
+        name='journals'
+    ),
+    path( # /affiliates/journals/<slug>
+        'journals/<slug:slug>',
+        views.AffiliateJournalDetailView.as_view(),
+        name='journal_detail'
+    ),
+    path( # /affiliates/publications/<doi:doi>
+        'publications/<doi:doi>',
+        views.AffiliatePublicationDetailView.as_view(),
+        name='publication_detail'
+    ),
+]
diff --git a/affiliates/validators.py b/affiliates/validators.py
new file mode 100644
index 0000000000000000000000000000000000000000..eb13135b75c87ad7616d60174b48c1e2ab053171
--- /dev/null
+++ b/affiliates/validators.py
@@ -0,0 +1,12 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.core.validators import RegexValidator
+
+from .regexes import DOI_AFFILIATEPUBLICATION_REGEX
+
+
+doi_affiliatepublication_validator = RegexValidator(
+    r'^{regex}$'.format(regex=DOI_AFFILIATEPUBLICATION_REGEX),
+    'Only expressions with regex %s are allowed.' % DOI_AFFILIATEPUBLICATION_REGEX)
diff --git a/affiliates/views.py b/affiliates/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a6661eb4f2e0f761d78db2fb0b161bc7d3d0ebb
--- /dev/null
+++ b/affiliates/views.py
@@ -0,0 +1,23 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.shortcuts import render
+from django.views.generic.detail import DetailView
+from django.views.generic.list import ListView
+
+from .models import AffiliateJournal, AffiliatePublication
+
+
+class AffiliateJournalListView(ListView):
+    model = AffiliateJournal
+
+
+class AffiliateJournalDetailView(DetailView):
+    model = AffiliateJournal
+
+
+class AffiliatePublicationDetailView(DetailView):
+    model = AffiliatePublication
+    slug_field = 'doi'
+    slug_url_kwarg = 'doi'