diff --git a/scipost_django/finances/admin.py b/scipost_django/finances/admin.py
index f2fd82f5fe2beec896bcded4f466e759abec3289..1c5dc3b9b7ce41c2dd3deaba88532fdc3bb933db 100644
--- a/scipost_django/finances/admin.py
+++ b/scipost_django/finances/admin.py
@@ -2,10 +2,12 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
 __license__ = "AGPL v3"
 
 
+from django import forms
 from django.contrib import admin
 
 from finances.models.account import Account
 from finances.models.balance import Balance
+from finances.models.subsidy import SubsidyCollective
 from finances.models.transaction import FuturePeriodicTransaction
 
 from .models import (
@@ -81,6 +83,23 @@ def detach(modeladmin, request, queryset):
             invoice_proof.save()
 
 
+class SubsidyInline(admin.TabularInline):
+    model = Subsidy
+    autocomplete_fields = [
+        "organization",
+        "renewal_of",
+        "individual_budget",
+        "collective",
+    ]
+    extra = 0
+
+    def formfield_for_dbfield(self, db_field, request, **kwargs):
+        if db_field.name == "description":
+            kwargs["widget"] = forms.Textarea(attrs={"rows": 1, "cols": 20})
+            return db_field.formfield(**kwargs)
+        return super().formfield_for_dbfield(db_field, request, **kwargs)
+
+
 @admin.register(SubsidyAttachment)
 class SubsidyAttachmentAdmin(admin.ModelAdmin):
     list_display = [
@@ -184,3 +203,32 @@ class AccountAdmin(admin.ModelAdmin):
         FuturePeriodicTransactionInline,
         BalanceInline,
     ]
+
+
+@admin.register(SubsidyCollective)
+class SubsidyCollectiveAdmin(admin.ModelAdmin):
+    list_display = [
+        "str",
+        "coordinator",
+        "subsidy_count",
+    ]
+    autocomplete_fields = [
+        "coordinator",
+    ]
+    search_fields = [
+        "str",
+        "description",
+        "coordinator__name",
+        "coordinator__name_original",
+        "coordinator__acronym",
+        "subsidies__organization__name",
+    ]
+    inlines = [SubsidyInline]
+
+    @admin.display(description="str")
+    def str(self, obj):
+        return str(obj)
+
+    @admin.display(description="subsidy count")
+    def subsidy_count(self, obj):
+        return obj.subsidies.count()
diff --git a/scipost_django/finances/forms.py b/scipost_django/finances/forms.py
index aadfb6faa0a6b8cf8d1828541c3b50fb8ba91991..90fc301e9dc02ebedc6f76f8b8f10f21d5cb7850 100644
--- a/scipost_django/finances/forms.py
+++ b/scipost_django/finances/forms.py
@@ -25,6 +25,7 @@ from finances.constants import (
     SUBSIDY_TYPES,
 )
 
+from finances.models.subsidy import SubsidyCollective
 from organizations.models import Organization
 from scipost.fields import UserModelChoiceField
 
@@ -71,6 +72,7 @@ class SubsidyForm(forms.ModelForm):
             "date_until",
             "renewable",
             "renewal_of",
+            "collective",
         ]
         widgets = {
             "paid_on": forms.DateInput(attrs={"type": "date"}),
@@ -78,6 +80,13 @@ class SubsidyForm(forms.ModelForm):
             "date_until": forms.DateInput(attrs={"type": "date"}),
         }
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        subsidy_collective_create = reverse_lazy("finances:subsidy_collective_create")
+        self.fields["collective"].help_text = (
+            f"If missing, <a href='{subsidy_collective_create}'>create a new one</a>."
+        )
+
 
 class SubsidySearchForm(forms.Form):
     organization_query = forms.CharField(
@@ -812,3 +821,141 @@ class LogsFilterForm(forms.Form):
                 )
 
         return output
+
+
+class SubsidyCollectiveForm(forms.ModelForm):
+    required_css_class = "required-asterisk"
+
+    subsidies = forms.ModelMultipleChoiceField(
+        queryset=Subsidy.objects.all(),
+        widget=autocomplete.ModelSelect2Multiple(
+            url=reverse_lazy("finances:subsidy_autocomplete"),
+            attrs={
+                "data-html": True,
+                "style": "width: 100%",
+            },
+        ),
+        required=False,
+    )
+
+    class Meta:
+        model = SubsidyCollective
+        fields = ["name", "description", "coordinator"]
+        widgets = {
+            "coordinator": autocomplete.ModelSelect2(
+                url=reverse_lazy("organizations:organization-autocomplete"),
+                attrs={
+                    "data-html": True,
+                    "style": "width: 100%",
+                },
+            ),
+        }
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        if self.instance.pk:
+            self.fields["subsidies"].initial = self.instance.subsidies.all()
+
+        self.helper = FormHelper()
+        self.helper.layout = Layout(
+            Field("name"),
+            Field("description"),
+            Field("coordinator"),
+            Field("subsidies"),
+            ButtonHolder(Submit("submit", "Submit", css_class="btn-sm")),
+        )
+
+    def save(self, commit: bool = True):
+        collective = super().save(commit)
+
+        collective.subsidies.set(self.cleaned_data["subsidies"])
+        return collective
+
+
+class SubsidyCollectiveRenewForm(forms.Form):
+    subsidies = forms.ModelMultipleChoiceField(
+        queryset=Subsidy.objects.all(),
+        widget=forms.CheckboxSelectMultiple,
+    )
+
+    start_date = forms.DateField(
+        widget=forms.DateInput(attrs={"type": "date"}),
+        required=False,
+    )
+    end_date = forms.DateField(
+        widget=forms.DateInput(attrs={"type": "date"}),
+        required=False,
+    )
+
+    def __init__(self, *args, **kwargs):
+        self.collective = kwargs.pop("collective")
+        super().__init__(*args, **kwargs)
+        self.fields["subsidies"].queryset = self.collective.subsidies.all()
+        self.fields["subsidies"].initial = self.fields["subsidies"].queryset
+
+        self.helper = FormHelper()
+        self.helper.layout = Layout(
+            Div(
+                Field("subsidies", css_class="col-12"),
+                Div(FloatingField("start_date"), css_class="col-6"),
+                Div(FloatingField("end_date"), css_class="col-6"),
+                css_class="row mb-0",
+            ),
+            ButtonHolder(Submit("submit", "Renew", css_class="btn-sm")),
+        )
+
+    def clean(self):
+        valid = self.is_valid()
+        if not (data := self.cleaned_data):
+            raise forms.ValidationError("No data was submitted")
+        elif not valid:
+            raise forms.ValidationError("Invalid form data")
+
+        start = data.get("start_date")
+        end = data.get("end_date")
+
+        if start > end:
+            self.add_error("end_date", "End date must be after start date")
+
+        return data
+
+    def save(self):
+        start_date = self.cleaned_data["start_date"]
+        end_date = self.cleaned_data["end_date"]
+
+        new_subsidies = [
+            Subsidy(
+                organization=subsidy.organization,
+                subsidy_type=subsidy.subsidy_type,
+                description=subsidy.description,
+                amount=subsidy.amount,
+                amount_publicly_shown=subsidy.amount_publicly_shown,
+                status=subsidy.status,
+                paid_on=subsidy.paid_on,
+                renewable=subsidy.renewable,
+                # Renewal dates are optional
+                date_from=start_date or subsidy.date_from,
+                date_until=end_date or subsidy.date_until,
+            )
+            for subsidy in self.cleaned_data["subsidies"]
+        ]
+
+        # Create new subsidies
+        Subsidy.objects.bulk_create(new_subsidies)
+
+        # Update `renewal_of` field to point to the original subsidy
+        for new, old in zip(new_subsidies, self.cleaned_data["subsidies"]):
+            new.renewal_of.add(old)
+            new.save()
+
+        # Create new collective
+        new_collective = SubsidyCollective.objects.create(
+            name=f"{self.collective.name} - Renewal {start_date} - {end_date}",
+            description=f"{self.collective.description}\n Renewal {start_date} - {end_date}",
+            coordinator=self.collective.coordinator,
+        )
+        new_collective.subsidies.set(new_subsidies)
+        new_collective.save()
+
+        return new_collective
diff --git a/scipost_django/finances/migrations/0047_subsidycollective.py b/scipost_django/finances/migrations/0047_subsidycollective.py
new file mode 100644
index 0000000000000000000000000000000000000000..c862c26c621db6ab9bec583640ee6115ac439785
--- /dev/null
+++ b/scipost_django/finances/migrations/0047_subsidycollective.py
@@ -0,0 +1,53 @@
+# Generated by Django 4.2.15 on 2024-12-02 12:26
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("organizations", "0024_contactperson_info_source"),
+        ("finances", "0046_account_transaction_futureperiodictransaction_and_more"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="SubsidyCollective",
+            fields=[
+                (
+                    "id",
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("name", models.CharField(blank=True, max_length=256, null=True)),
+                ("description", models.TextField(blank=True, null=True)),
+                (
+                    "coordinator",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        to="organizations.organization",
+                    ),
+                ),
+            ],
+            options={
+                "default_related_name": "collectives",
+                "verbose_name_plural": "subsidy collectives",
+                "ordering": ["coordinator__name"],
+            },
+        ),
+        migrations.AddField(
+            model_name="subsidy",
+            name="collective",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.SET_NULL,
+                related_name="subsidies",
+                to="finances.subsidycollective",
+            ),
+        ),
+    ]
diff --git a/scipost_django/finances/models/subsidy.py b/scipost_django/finances/models/subsidy.py
index 8467098b9d7b3870c531bb056588dbb1e09f35df..e1f248444e5c096ac072db10e0771b5d6f6d7c28 100644
--- a/scipost_django/finances/models/subsidy.py
+++ b/scipost_django/finances/models/subsidy.py
@@ -7,6 +7,7 @@ import datetime
 
 from django.db import models
 from django.db.models import Sum
+from django.db.models.functions import ExtractYear
 from django.urls import reverse
 from django.utils.html import format_html
 
@@ -18,6 +19,12 @@ from ..constants import (
 )
 from ..managers import SubsidyQuerySet, PubFracQuerySet
 
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from django.db.models.manager import RelatedManager
+    from organizations.models import Organization
+
 
 class Subsidy(models.Model):
     """
@@ -54,6 +61,16 @@ class Subsidy(models.Model):
     renewal_of = models.ManyToManyField(
         "self", related_name="renewed_by", symmetrical=False, blank=True
     )
+    collective = models.ForeignKey["SubsidyCollective"](
+        "SubsidyCollective",
+        on_delete=models.SET_NULL,
+        blank=True,
+        null=True,
+        related_name="subsidies",
+    )
+
+    if TYPE_CHECKING:
+        collectives: RelatedManager["SubsidyCollective"]
 
     objects = SubsidyQuerySet.as_manager()
 
@@ -189,3 +206,57 @@ class Subsidy(models.Model):
             compensated[pubfrac.publication.doi_label]["fraction"] += pubfrac.fraction
             compensated[pubfrac.publication.doi_label]["value"] += pubfrac.cf_value
         return compensated
+
+
+class SubsidyCollective(models.Model):
+    """
+    A collective of Subsidies, which can be used to group together relevant subsidies.
+    Primarily used to group together all subsidies from a single collective agreement,
+    as coordinated by a "parent" Organization.
+    """
+
+    coordinator = models.ForeignKey["Organization"](
+        "organizations.Organization", on_delete=models.CASCADE
+    )
+    name = models.CharField(max_length=256, null=True, blank=True)
+    description = models.TextField(null=True, blank=True)
+
+    if TYPE_CHECKING:
+        subsidies: RelatedManager[Subsidy]
+
+    class Meta:
+        verbose_name_plural = "subsidy collectives"
+        default_related_name = "collectives"
+        ordering = ["coordinator__name"]
+
+    @property
+    def year_str(self):
+        min_year = (
+            self.subsidies.annotate(year=ExtractYear("date_from"))
+            .values_list("year", flat=True)
+            .order_by("year")
+            .first()
+        )
+        max_year = (
+            self.subsidies.annotate(year=ExtractYear("date_until"))
+            .values_list("year", flat=True)
+            .order_by("year")
+            .last()
+        )
+        if min_year and max_year:
+            if min_year == max_year:
+                return str(min_year)
+            return f"{min_year}-{max_year}"
+
+    def __str__(self):
+        if self.name:
+            return self.name
+
+        str_rep = f"Collective by {self.coordinator}"
+        if self.year_str:
+            str_rep += f" for {self.year_str}"
+
+        return str_rep
+
+    def get_absolute_url(self):
+        return reverse("finances:subsidy_collective_details", args=(self.id,))
diff --git a/scipost_django/finances/templates/finances/_subsidy_collective_nav_links_list.html b/scipost_django/finances/templates/finances/_subsidy_collective_nav_links_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..aa3bda1904ef785c5538f6ccc378af69bab101ca
--- /dev/null
+++ b/scipost_django/finances/templates/finances/_subsidy_collective_nav_links_list.html
@@ -0,0 +1,14 @@
+<h5>
+  <a href="{{ collective.get_absolute_url }}">{{ collective }}</a>
+</h5>
+
+  <ul class="list-unstyled">
+    {% for sub in collective.subsidies.all %}
+    <li class="nav-item">
+      <a href="{{ sub.get_absolute_url }}" class="nav-link {% if sub.id == subsidy.id %}active{% endif %}">
+        {{ sub.organization }}
+      </a>
+    </li>
+    {% endfor %}
+  </ul>
+
diff --git a/scipost_django/finances/templates/finances/_subsidy_details.html b/scipost_django/finances/templates/finances/_subsidy_details.html
index 9e512ca256cbb684ad6eb3e24fbaf877aec6b0bf..5e1d1ef67e321700259988c131b4edb4a0a00bad 100644
--- a/scipost_django/finances/templates/finances/_subsidy_details.html
+++ b/scipost_django/finances/templates/finances/_subsidy_details.html
@@ -5,7 +5,7 @@
 {% get_obj_perms request.user for subsidy.organization as "user_org_perms" %}
 
 <div class="row">
-  <div class="col-12">
+  <div class="col">
     {% if perms.scipost.can_manage_subsidies %}
       <ul class="list-inline"><li class="list-inline-item"><strong>Admin actions:</strong></li>
 	<li class="list-inline-item"><a href="{% url 'finances:subsidy_update' pk=subsidy.id %}"><span class="text-warning">Update</span></a></li>
@@ -65,6 +65,18 @@
     {% endif %}
 
   </div>
+
+  {% if subsidy.collective %}
+    <div class="col-12 col-sm-6 col-md-3">
+      <h4>Subsidies of the same Collective</h4>
+      <nav class="nav nav-pills flex-column">
+        
+        {% include "finances/_subsidy_collective_nav_links_list.html" with collective=subsidy.collective %}
+
+      </nav>
+    </div>
+  {% endif %}
+
 </div>
 
 {% if "finadmin" in user_roles %}
diff --git a/scipost_django/finances/templates/finances/subsidy_collective_delete.html b/scipost_django/finances/templates/finances/subsidy_collective_delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..f77deb37e20d26b5838ddd8c84804064ae2a28b4
--- /dev/null
+++ b/scipost_django/finances/templates/finances/subsidy_collective_delete.html
@@ -0,0 +1,48 @@
+{% extends 'finances/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+  {{ block.super }}
+  <span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span>
+  <span class="breadcrumb-item">Collectives</span>
+  <span class="breadcrumb-item"><a href="{{ object.get_absolute_url }}">{{ object }}</a></span>
+  <span class="breadcrumb-item"><a href="#" class="active">Delete</a></span>
+{% endblock %}
+
+{% block pagetitle %}
+  : Delete Subsidy Collective
+{% endblock pagetitle %}
+
+{% block content %}
+
+  <hgroup class="highlight p-3 mb-3">
+    <h1>Delete Subsidy Collective</h1>
+    <p class="m-0 fs-4"><a href="{{ collective.get_absolute_url }}">{{ collective }}</a></p>
+  </hgroup>
+
+  <div class="row">
+    <div class="col-12">
+      <h2><a href="{{ collective.get_absolute_url }}">{{ collective }}</a></h2>
+      <p>The collective is coordinated by <a href="{{ collective.coordinator.get_absolute_url }}">{{ collective.coordinator }}</a>.</p>
+      <p>{{ collective.description }}</p>
+
+      <h2>Subsidies part of this Collective</h2>
+      <ul class="list-unstyled">
+        {% for subsidy in collective.subsidies.all %}
+          <li><a href="{{ subsidy.get_absolute_url }}">{{ subsidy }}</a></li>
+        {% endfor %}
+      </ul>
+    </div>
+      
+    <div class="col-12">
+      <form method="post">
+        {% csrf_token %}
+        <div class="fs-5 mb-2">Are you sure you want to delete this Subsidy Collective?</div>
+        <p>Deleting this collective will <strong>not</strong> delete the subsidies associated with it.</p>
+        <input type="submit" class="btn btn-danger" value="Yes, delete it" />
+      </form>
+    </div>
+  </div>
+
+{% endblock content %}
diff --git a/scipost_django/finances/templates/finances/subsidy_collective_detail.html b/scipost_django/finances/templates/finances/subsidy_collective_detail.html
new file mode 100644
index 0000000000000000000000000000000000000000..e8d7b3bb8685a9d125812acf424e743671c9f5f7
--- /dev/null
+++ b/scipost_django/finances/templates/finances/subsidy_collective_detail.html
@@ -0,0 +1,89 @@
+{% extends 'finances/base.html' %}
+
+{% load bootstrap %}
+
+{% block meta_description %}
+  {{ block.super }} Subsidy Collective Detail
+{% endblock meta_description %}
+
+{% block pagetitle %}
+  : Subsidy Collective details
+{% endblock pagetitle %}
+
+{% block breadcrumb_items %}
+  {{ block.super }}
+  <span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span>
+  <span class="breadcrumb-item"><a href="{% url 'finances:subsidy_collectives' %}">Collectives</a></span>
+  <span class="breadcrumb-item"><a href="#" class="active">{{ collective }}</a></span>
+{% endblock %}
+
+{% block content %}
+
+  <div class="highlight p-3 d-flex flex-row justify-content-between align-items-center mb-3">
+    <hgroup>
+      <h1>{{ collective }}</h1>
+      <p class="m-0 fs-4">(Coordinated by <a href="{{ collective.coordinator.get_absolute_url }}">{{ collective.coordinator }}</a>)</p>
+    </hgroup>
+    <div class="dropdown">
+      <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
+        <span>Actions</span>
+      </button>
+      <ul class="dropdown-menu dropdown-menu-end">
+        <li><a href="{% url 'finances:subsidy_collective_renew' collective_id=collective.id %}" class="dropdown-item">Renew</a></li>
+        <li><hr class="dropdown-divider" /></li>
+        <li><a href="{% url 'finances:subsidy_collective_update' collective_id=collective.id %}" class="dropdown-item">Edit</a></li>
+        <li><a href="{% url 'finances:subsidy_collective_delete' collective_id=collective.id %}" class="dropdown-item">Delete</a></li>
+      </ul>
+    </div>
+  </div>
+    
+  {% if collective.description %}
+  <div class="fs-5 fw-bold">Description</div>
+  <p>{{ collective.description }}</p>
+  {% endif %}
+
+  <h2>Subsidies part of this Collective</h2>
+  <table class="table table-hover position-relative">
+    <thead class="table-light position-sticky top-0">
+      <tr>
+        <th>From Organization</th>
+        <th>Type</th>
+
+        {% if perms.scipost.can_manage_subsidies %}
+          <th>
+            <span class="small" style="writing-mode: vertical-rl;">Payments
+              <br />
+            Scheduled?</span>
+          </th>
+        {% endif %}
+
+        <th>Amount</th>
+        <th>From</th>
+        <th>Until</th>
+
+        {% if perms.scipost.can_manage_subsidies %}
+
+          <th>Status</th>
+          <th>
+            <span class="small" style="writing-mode: vertical-lr;">Renewable?</span>
+          </th>
+          <th>
+            <span class="small" style="writing-mode: vertical-lr;">Renewed?</span>
+          </th>
+          <th>
+            Renewal
+            <br />
+            action date
+          </th>
+        {% endif %}
+
+
+      </tr>
+
+      <tbody id="subsidy-table-tbody">
+        {% include "finances/_hx_subsidy_list.html" with page_obj=page_encapsulated_subsidies %}
+      </tbody>
+    </table>
+
+
+  {% endblock content %}
diff --git a/scipost_django/finances/templates/finances/subsidy_collective_form.html b/scipost_django/finances/templates/finances/subsidy_collective_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..8d52ac37f54b2d5f1f95d3ab5407a82ea07bb3c7
--- /dev/null
+++ b/scipost_django/finances/templates/finances/subsidy_collective_form.html
@@ -0,0 +1,47 @@
+{% extends 'finances/base.html' %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+  {{ block.super }}
+  <span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span>
+  <span class="breadcrumb-item"><a href="{% url 'finances:subsidy_collectives' %}">Collectives</a></span>
+  {% if form.instance.id %}
+    <span class="breadcrumb-item"><a href="{{ form.instance.get_absolute_url }}">{{ form.instance }}</a></span>
+    <span class="breadcrumb-item"><a href="#" class="active">Update</a></span>
+  {% else %}
+    <span class="breadcrumb-item"><a href="#" class="active">Create</a></span>
+  {% endif %}
+
+{% endblock %}
+
+{% block pagetitle %}
+  : Subsidies
+{% endblock pagetitle %}
+
+
+{% block content %}
+<hgroup class="highlight p-3 mb-3">
+  <h1>{% if form.instance.id %}Update{% else %}Create Subsidy Collective{% endif %} Form</h1>
+  {% if form.instance.id %}
+    <p class="m-0 fs-4"><a href="{{ form.instance.get_absolute_url }}">{{ form.instance }}</a></p>
+  {% endif %}
+</hgroup>
+
+  <div class="row">
+    <form action="" method="post">
+      <div class="col-12">
+        {% csrf_token %}
+        {{ form|bootstrap }}
+	
+        <input type="submit" value="Submit" class="btn btn-primary" />
+      </div>
+    </form>
+  </div>
+{% endblock content %}
+
+
+{% block footer_script %}
+  {{ block.super }}
+  {{ form.media }}
+{% endblock footer_script %}
diff --git a/scipost_django/finances/templates/finances/subsidy_collective_list.html b/scipost_django/finances/templates/finances/subsidy_collective_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..31b03f1822603e246c938331edd50483c76833c2
--- /dev/null
+++ b/scipost_django/finances/templates/finances/subsidy_collective_list.html
@@ -0,0 +1,39 @@
+{% extends 'finances/base.html' %}
+{% load crispy_forms_tags %}
+
+{% block meta_description %}
+  {{ block.super }} Subsidies List
+{% endblock meta_description %}
+
+{% block pagetitle %}
+  : Subsidies
+{% endblock pagetitle %}
+
+{% load static %}
+{% load bootstrap %}
+
+{% block breadcrumb_items %}{{ block.super }}
+  <span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span>
+  <span class="breadcrumb-item"><a href="#" class="active">Collectives</a></span>
+{% endblock %}
+
+{% block content %}
+ 
+  <div class="highlight p-3 d-flex flex-row justify-content-between align-items-center mb-3">
+    <h1>Subsidy Collectives</h1>
+    <a href="{% url 'finances:subsidy_collective_create' %}" class="btn btn-primary">Create</a>
+  </div>
+  
+  <div class="row">
+    <div class="col">
+      <ul class="list-unstyled">
+        {% for collective in collectives %}
+          <li><a href="{{ collective.get_absolute_url }}">{{ collective }}</a></li>
+        {% empty %}
+          <li>No Subsidy Collectives</li>
+        {% endfor %}
+      </ul>
+    </div>
+  </div>
+
+  {% endblock content %}
diff --git a/scipost_django/finances/templates/finances/subsidy_collective_renew_form.html b/scipost_django/finances/templates/finances/subsidy_collective_renew_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..7133d2ae4b62aaed3afa11573e5011b42e0412c9
--- /dev/null
+++ b/scipost_django/finances/templates/finances/subsidy_collective_renew_form.html
@@ -0,0 +1,37 @@
+{% extends 'finances/base.html' %}
+
+{% load bootstrap %}
+{% load crispy_forms_tags %}
+
+{% block meta_description %}
+  {{ block.super }} Subsidy Collective Renewal Form
+{% endblock meta_description %}
+
+{% block pagetitle %}
+  : Subsidy Collective Renewal Form
+{% endblock pagetitle %}
+
+{% block breadcrumb_items %}
+  {{ block.super }}
+  <span class="breadcrumb-item"><a href="{% url 'finances:subsidies' %}">Subsidies</a></span>
+  <span class="breadcrumb-item">Collectives</span>
+  <span class="breadcrumb-item"><a href="{{ collective.get_absolute_url }}">{{ collective }}</a></span>
+  <span class="breadcrumb-item"><a href="#" class="active">Renewal Form</a></span>
+{% endblock %}
+
+{% block content %}
+
+  <hgroup class="highlight p-3 mb-3">
+    <h1>Renewal Form</h1>
+    <p class="m-0 fs-4"><a href="{{ collective.get_absolute_url }}">{{ collective }}</a></p>
+  </hgroup>
+ 
+  <h2>Renew Subsidies of this Collective</h2>
+  <p>
+    Submitting this form will create new subsidies for all selected organizations, keeping the same details as the current subsidy.
+    If provided, the start and end dates will be overridden by the values in the form.
+  </p>
+
+  {% crispy form %}
+
+  {% endblock content %}
diff --git a/scipost_django/finances/templates/finances/subsidy_list.html b/scipost_django/finances/templates/finances/subsidy_list.html
index 7b6f155d57375ba54e0ba316605ad4c752e7f200..504237ca20cb32825467c927b52838a80d36fc7b 100644
--- a/scipost_django/finances/templates/finances/subsidy_list.html
+++ b/scipost_django/finances/templates/finances/subsidy_list.html
@@ -29,6 +29,9 @@
           <li>
             <a href="{% url 'finances:subsidyattachment_create' %}">Add a SubsidyAttachment</a>
           </li>
+          <li>
+            <a href="{% url 'finances:subsidy_collective_create' %}">Create a Collective Subsidy</a>
+          </li>
           <li>
             <a href="{% url 'finances:subsidyattachment_orphaned_list' %}">Link orphaned SubsidyAttachments</a>
           </li>
diff --git a/scipost_django/finances/urls.py b/scipost_django/finances/urls.py
index d3543a1eaea793d065711fd452fc5a56e93e603b..beec4587b03f52f940d001c023fb50b89cf3752a 100644
--- a/scipost_django/finances/urls.py
+++ b/scipost_django/finances/urls.py
@@ -88,7 +88,44 @@ urlpatterns = [
                         ]
                     ),
                 ),
-            ]
+                path(
+                    "collectives/<int:collective_id>/",
+                    include(
+                        [
+                            path(
+                                "",
+                                views.SubsidyCollectiveDetailView.as_view(),
+                                name="subsidy_collective_details",
+                            ),
+                            path(
+                                "delete/",
+                                views.SubsidyCollectiveDeleteView.as_view(),
+                                name="subsidy_collective_delete",
+                            ),
+                            path(
+                                "update/",
+                                views.SubsidyCollectiveUpdateView.as_view(),
+                                name="subsidy_collective_update",
+                            ),
+                            path(
+                                "renew/",
+                                views.SubsidyCollectiveRenewFormView.as_view(),
+                                name="subsidy_collective_renew",
+                            ),
+                        ]
+                    ),
+                ),
+                path(
+                    "collectives/create/",
+                    views.SubsidyCollectiveCreateView.as_view(),
+                    name="subsidy_collective_create",
+                ),
+                path(
+                    "collectives/",
+                    views.SubsidyCollectiveListView.as_view(),
+                    name="subsidy_collectives",
+                ),
+            ],
         ),
     ),
     path("subsidies/", views.subsidy_list, name="subsidies"),
diff --git a/scipost_django/finances/views.py b/scipost_django/finances/views.py
index 8078a674734dfdc731cac0c4463652907ca73854..8983a7c839408e509f616c3989528ce3524e0777 100644
--- a/scipost_django/finances/views.py
+++ b/scipost_django/finances/views.py
@@ -5,19 +5,23 @@ __license__ = "AGPL v3"
 import datetime
 from itertools import accumulate, chain
 import mimetypes
+from typing import Any
 from dal import autocomplete
 
 from django.contrib.contenttypes.models import ContentType
+from django.core.handlers.asgi import HttpRequest
 from django.db import models
 from django.db.models import Q, Count, Exists, OuterRef, Subquery
 from django.db.models.functions import Coalesce
 from django.template.response import TemplateResponse
 from django.utils.html import format_html
+from django.views.generic import FormView
 import matplotlib
 
 from common.views import HXDynselAutocomplete, HXDynselSelectOptionView
 from finances.constants import SUBSIDY_TYPE_SPONSORSHIPAGREEMENT, SUBSIDY_PROMISED
 from finances.models.account import Account
+from finances.models.subsidy import SubsidyCollective
 from journals.models.publication import PublicationAuthorsTable
 
 matplotlib.use("Agg")
@@ -40,6 +44,8 @@ from django.views.generic.list import ListView
 from .forms import (
     SubsidyAttachmentInlineLinkForm,
     SubsidyAttachmentSearchForm,
+    SubsidyCollectiveForm,
+    SubsidyCollectiveRenewForm,
     SubsidyForm,
     SubsidySearchForm,
     SubsidyPaymentForm,
@@ -882,3 +888,95 @@ def periodicreport_file(request, pk):
     filename = periodicreport._file.name
     response["Content-Disposition"] = f"filename={filename}"
     return response
+
+
+#######################
+# Subsidy Collectives #
+#######################
+
+
+class SubsidyCollectiveListView(PermissionsMixin, ListView):
+    model = SubsidyCollective
+    template_name = "finances/subsidy_collective_list.html"
+    permission_required = "scipost.can_manage_subsidies"
+    context_object_name = "collectives"
+
+
+class SubsidyCollectiveDetailView(PermissionsMixin, DetailView):
+    model = SubsidyCollective
+    template_name = "finances/subsidy_collective_detail.html"
+    permission_required = "scipost.can_manage_subsidies"
+    pk_url_kwarg = "collective_id"
+    context_object_name = "collective"
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context["page_encapsulated_subsidies"] = Paginator(
+            self.object.subsidies.all(),
+            1000,
+        ).get_page(self.request.GET.get("page"))
+        return context
+
+
+class SubsidyCollectiveDeleteView(PermissionsMixin, DeleteView):
+    model = SubsidyCollective
+    template_name = "finances/subsidy_collective_delete.html"
+    success_url = reverse_lazy("finances:subsidy_collectives")
+    permission_required = "scipost.can_manage_subsidies"
+    pk_url_kwarg = "collective_id"
+    context_object_name = "collective"
+
+
+class SubsidyCollectiveCreateView(PermissionsMixin, CreateView):
+    model = SubsidyCollective
+    form_class = SubsidyCollectiveForm
+    template_name = "finances/subsidy_collective_form.html"
+    permission_required = "scipost.can_manage_subsidies"
+    pk_url_kwarg = "collective_id"
+    context_object_name = "collective"
+
+    def get_success_url(self):
+        return self.object.get_absolute_url()
+
+
+class SubsidyCollectiveUpdateView(PermissionsMixin, UpdateView):
+    model = SubsidyCollective
+    form_class = SubsidyCollectiveForm
+    template_name = "finances/subsidy_collective_form.html"
+    permission_required = "scipost.can_manage_subsidies"
+    pk_url_kwarg = "collective_id"
+    context_object_name = "collective"
+
+    def get_success_url(self):
+        return self.object.get_absolute_url()
+
+
+class SubsidyCollectiveRenewFormView(FormView):
+    template_name = "finances/subsidy_collective_renew_form.html"
+    form_class = SubsidyCollectiveRenewForm
+
+    def dispatch(self, request: HttpRequest, *args, **kwargs):
+        self.collective = get_object_or_404(
+            SubsidyCollective, pk=kwargs.get("collective_id", None)
+        )
+        return super().dispatch(request, *args, **kwargs)
+
+    def get_form_kwargs(self) -> dict[str, Any]:
+        kwargs = super().get_form_kwargs()
+        kwargs["collective"] = self.collective
+        return kwargs
+
+    def get_initial(self):
+        return {"collective": self.collective}
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context["collective"] = self.collective
+        return context
+
+    def get_success_url(self):
+        return self.new_collective.get_absolute_url()
+
+    def form_valid(self, form):
+        self.new_collective = form.save()
+        return super().form_valid(form)