diff --git a/SAS/TMSS/client/lib/populate.py b/SAS/TMSS/client/lib/populate.py
index bb39f6967617e077aa4c8d00f425534cbfc4d95c..63a148b2eeaa2cb59b7f2a77ecc9b9405d67283e 100644
--- a/SAS/TMSS/client/lib/populate.py
+++ b/SAS/TMSS/client/lib/populate.py
@@ -72,7 +72,7 @@ def populate_schemas(schema_dir: str=None, templates_filename: str=None):
                             else:
                                 template['schema'] = json_schema
 
-                            logger.info("Uploading template name='%s' version='%s'", name, version)
+                            logger.info("Uploading template with name='%s' version='%s' template='%s' ", name, version, template)
 
                             client.post_template(template_path=template_name,
                                                   name=name,
diff --git a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py
index 4ae9725ed8dbaa5c4897e7d309adfdb2fe9ff126..5ee172f8b5694b25455dd932284059d9d87a3885 100644
--- a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py
+++ b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py
@@ -243,6 +243,19 @@ class Migration(migrations.Migration):
                 'abstract': False,
             },
         ),
+        migrations.CreateModel(
+            name='DefaultReservationTemplate',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('tags', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)),
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')),
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')),
+                ('name', models.CharField(max_length=128, unique=True)),
+            ],
+            options={
+                'abstract': False,
+            },
+        ),
         migrations.CreateModel(
             name='DefaultSchedulingConstraintsTemplate',
             fields=[
@@ -405,6 +418,39 @@ class Migration(migrations.Migration):
                 'abstract': False,
             },
         ),
+        migrations.CreateModel(
+            name='Reservation',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('tags', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)),
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')),
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')),
+                ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)),
+                ('description', models.CharField(help_text='Short description for this reservation, used in overviews', max_length=255)),
+                ('start_time', models.DateTimeField(help_text='Start of this reservation.')),
+                ('duration', models.IntegerField(help_text='Duration of this reservations.', null=True)),
+                ('specifications_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Properties of this reservation')),
+            ],
+            options={
+                'abstract': False,
+            },
+        ),
+        migrations.CreateModel(
+            name='ReservationTemplate',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('tags', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)),
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')),
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')),
+                ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)),
+                ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)),
+                ('version', models.IntegerField(editable=False, help_text='Version of this template (with respect to other templates of the same name)')),
+                ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')),
+            ],
+            options={
+                'abstract': False,
+            },
+        ),
         migrations.CreateModel(
             name='ResourceType',
             fields=[
@@ -1147,6 +1193,20 @@ class Migration(migrations.Migration):
             name='quantity',
             field=models.ForeignKey(help_text='The quantity of this resource type.', on_delete=django.db.models.deletion.PROTECT, to='tmssapp.Quantity'),
         ),
+        migrations.AddConstraint(
+            model_name='reservationtemplate',
+            constraint=models.UniqueConstraint(fields=('name', 'version'), name='reservationtemplate_unique_name_version'),
+        ),
+        migrations.AddField(
+            model_name='reservation',
+            name='project',
+            field=models.ForeignKey(help_text='Reservation will be accounted for this project.', on_delete=django.db.models.deletion.CASCADE, related_name='reservations', to='tmssapp.Project'),
+        ),
+        migrations.AddField(
+            model_name='reservation',
+            name='specifications_template',
+            field=models.ForeignKey(help_text='Schema used for specifications_doc.', on_delete=django.db.models.deletion.CASCADE, to='tmssapp.ReservationTemplate'),
+        ),
         migrations.AddField(
             model_name='projectquota',
             name='project',
@@ -1211,6 +1271,11 @@ class Migration(migrations.Migration):
             name='template',
             field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.SchedulingConstraintsTemplate'),
         ),
+        migrations.AddField(
+            model_name='defaultreservationtemplate',
+            name='template',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.ReservationTemplate'),
+        ),
         migrations.AddField(
             model_name='defaultgeneratortemplate',
             name='template',
@@ -1380,6 +1445,10 @@ class Migration(migrations.Migration):
             model_name='defaultschedulingconstraintstemplate',
             index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_480bbd_gin'),
         ),
+        migrations.AddIndex(
+            model_name='defaultreservationtemplate',
+            index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_58d7a4_gin'),
+        ),
         migrations.AddIndex(
             model_name='defaultgeneratortemplate',
             index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_89c89d_gin'),
@@ -1404,4 +1473,4 @@ class Migration(migrations.Migration):
             model_name='dataproduct',
             index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_dat_tags_5932a3_gin'),
         ),
-    ]
+    ]
\ No newline at end of file
diff --git a/SAS/TMSS/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/src/tmss/tmssapp/models/specification.py
index 503bb9dbe020d3e462d936e5dc2f47052a1453d5..1f5a6e3b5be0631f4c5b99ee9e4b6a2176556623 100644
--- a/SAS/TMSS/src/tmss/tmssapp/models/specification.py
+++ b/SAS/TMSS/src/tmss/tmssapp/models/specification.py
@@ -375,6 +375,44 @@ class DefaultTaskRelationSelectionTemplate(BasicCommon):
     name = CharField(max_length=128, unique=True)
     template = ForeignKey("TaskRelationSelectionTemplate", on_delete=PROTECT)
 
+
+class ReservationTemplate(Template):
+    pass
+
+
+class DefaultReservationTemplate(BasicCommon):
+    name = CharField(max_length=128, unique=True)
+    template = ForeignKey("ReservationTemplate", on_delete=PROTECT)
+
+
+#
+# DatabaseView  objects
+#
+class TaskBlueprintSummary(Model):
+    taskblueprint_id = IntegerField()
+    subtask_id = IntegerField()
+    substate = CharField(max_length=128)
+    subtask_type = CharField(max_length=128)
+
+    class Meta:
+        managed = False
+        db_table = 'tmssapp_taskblueprintsummary'
+
+
+class SchedulingUnitBlueprintSummary(Model):
+    # Using in an id and ForeignKey is not common for a view BUT the id is a 'dummy' to be able to use in Django
+    # https://resources.rescale.com/using-database-views-in-django-orm/
+    # otherwise an exception will be thrown
+    id = IntegerField(primary_key=True)
+    sub_id = IntegerField()
+    taskblueprint_id = IntegerField()
+    task_type = CharField(max_length=128)
+    derived_task_status = CharField(max_length=128)
+
+    class Meta:
+        managed = False
+        db_table = 'tmssapp_schedulingunitblueprintsummary'
+
 #
 # Instance Objects
 #
@@ -1084,3 +1122,15 @@ class TaskSchedulingRelationDraft(BasicCommon):
             raise ValidationError("Time_offset must be >= 0")
         super().save(force_insert, force_update, using, update_fields)
 
+
+class Reservation(NamedCommon):
+    project = ForeignKey('Project', related_name='reservations', on_delete=CASCADE, help_text='Reservation will be accounted for this project.')
+    description = CharField(max_length=255, help_text='Short description for this reservation, used in overviews')
+    start_time = DateTimeField(help_text='Start of this reservation.')
+    duration = IntegerField(null=True, help_text='Duration of this reservations.')
+    specifications_doc = JSONField(help_text='Properties of this reservation')
+    specifications_template = ForeignKey('ReservationTemplate', on_delete=CASCADE, help_text='Schema used for specifications_doc.')
+
+    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
+        annotate_validate_add_defaults_to_doc_using_template(self, 'specifications_doc', 'specifications_template')
+        super().save(force_insert, force_update, using, update_fields)
diff --git a/SAS/TMSS/src/tmss/tmssapp/populate.py b/SAS/TMSS/src/tmss/tmssapp/populate.py
index 05ec07e83f2f102caa1f65d1bcadf8ffb3447935..73116db990983bddcc038740907cae326e5d75b3 100644
--- a/SAS/TMSS/src/tmss/tmssapp/populate.py
+++ b/SAS/TMSS/src/tmss/tmssapp/populate.py
@@ -68,6 +68,16 @@ def populate_test_data():
                 if 'Commissioning' not in tmss_project.tags:
                     continue
 
+                # for test purposes also add a reservation object
+                reservation_template = models.ReservationTemplate.objects.get(name="resource reservation")
+                reservation_template_spec = get_default_json_object_for_schema(reservation_template.schema)
+                Reservation.objects.create(name="DummyReservation",
+                                           description="Just A non-scheduled reservation as example",
+                                           project=tmss_project,
+                                           specifications_template=reservation_template,
+                                           specifications_doc=reservation_template_spec,
+                                           start_time=datetime.now())
+
                 for scheduling_set in tmss_project.scheduling_sets.all():
                     for unit_nr in range(2):
                         for strategy_template in [uc1_strategy_template, simple_strategy_template]:
diff --git a/SAS/TMSS/src/tmss/tmssapp/schemas/reservation_template-reservation-1.json b/SAS/TMSS/src/tmss/tmssapp/schemas/reservation_template-reservation-1.json
new file mode 100644
index 0000000000000000000000000000000000000000..cdcbb306ad3f90ddde1701666ac2eb10845695a7
--- /dev/null
+++ b/SAS/TMSS/src/tmss/tmssapp/schemas/reservation_template-reservation-1.json
@@ -0,0 +1,132 @@
+{
+  "$id": "http://tmss.lofar.org/api/schemas/tasktemplate/reservation/1#",
+  "$schema": "http://json-schema.org/draft-06/schema#",
+  "title": "resource reservation",
+  "description": "This schema defines the parameters to reserve instrument resources, and to annotate the reservation.",
+  "version": 1,
+  "type": "object",
+  "properties": {
+    "activity": {
+      "title": "Activity",
+      "description": "Description of the activity during this reservation",
+      "type": "object",
+      "additonalProperties": false,
+      "default":{},
+      "properties": {
+        "type": {
+          "title": "Type",
+          "description": "Reason for this reservation",
+          "type": "string",
+          "enum": [ "maintenance", "test", "upgrade", "outage", "pr", "stand-alone mode", "test system", "other" ],
+          "default": "maintenance"
+        },
+        "description": {
+          "title": "Description",
+          "description": "Free-form explanation of the reason",
+          "type": "string",
+	      "default": ""
+        },
+        "contact": {
+          "title": "Contact",
+          "description": "Who coordinates this maintenance",
+          "type": "string",
+	      "default": ""
+        },
+        "subject": {
+          "title": "Subject",
+          "description": "What will be modified or affected (select 'system' if multiple)",
+          "type": "string",
+          "enum": [ "environment", "hardware", "firmware", "software", "system", "network", "nothing" ],
+          "default": "nothing"
+        },
+        "planned": {
+          "title": "Planned",
+          "description": "Was this planned?",
+          "type": "boolean",
+          "default": true
+        }
+      },
+      "required": [
+        "type"
+      ]
+    },
+    "resources": {
+      "title": "Resources",
+      "description": "Which resources are affected",
+      "type": "object",
+      "additonalProperties": false,
+      "default":{},
+      "properties": {
+        "stations": {
+          "title": "Stations",
+          "description": "List of stations",
+	      "$ref": "http://tmss.lofar.org/api/schemas/commonschematemplate/stations/1#/definitions/station_list"
+        }
+      },
+      "required": []
+    },
+    "schedulability": {
+      "title": "Schedulability",
+      "description": "Schedulability of the reserved resources",
+      "type": "object",
+      "additonalProperties": false,
+      "default":{},
+      "properties": {
+        "manual": {
+          "title": "Manual",
+          "description": "Manual scheduling is allowed",
+          "type": "boolean",
+          "default": true
+        },
+        "dynamic": {
+          "title": "Dynamic",
+          "description": "Dynamic scheduling is allowed",
+          "type": "boolean",
+          "default": false
+        },
+        "project_exclusive": {
+          "title": "Schedule only for this project",
+          "description": "Only tasks from this project can be scheduled",
+          "type": "boolean",
+          "default": true
+        }
+      }
+    },
+    "effects": {
+      "title": "Effect",
+      "description": "Effect the actions have during this reservation",
+      "type": "object",
+      "additonalProperties": false,
+      "default":{},
+      "properties": {
+        "lba_rfi": {
+          "title": "LBA RFI",
+          "description": "RFI increases in the LBA spectrum during this maintenance",
+	      "type": "boolean",
+	      "default": false
+        },
+        "hba_rfi": {
+          "title": "HBA RFI",
+          "description": "RFI increases in the HBA spectrum during this maintenance",
+	      "type": "boolean",
+	      "default": false
+        },
+        "expert": {
+          "title": "Expert mode",
+          "description": "Quality cannot be guaranteed",
+	      "type": "boolean",
+	      "default": true
+        }
+      },
+      "required": []
+    }
+  },
+  "required": [
+    "activity", "resources", "effects"
+  ]
+}
+
+
+
+
+
diff --git a/SAS/TMSS/src/tmss/tmssapp/schemas/subtask_template-reservation-1.json b/SAS/TMSS/src/tmss/tmssapp/schemas/subtask_template-reservation-1.json
new file mode 100644
index 0000000000000000000000000000000000000000..dd1d1996959e6630bc0b78f5be64a6422ec6721f
--- /dev/null
+++ b/SAS/TMSS/src/tmss/tmssapp/schemas/subtask_template-reservation-1.json
@@ -0,0 +1,27 @@
+{
+  "$id": "http://tmss.lofar.org/api/schemas/subtasktemplate/reservation/1#",
+  "$schema": "http://json-schema.org/draft-06/schema#",
+  "title": "resource reservation",
+  "description": "This schema defines reserved resources",
+  "version": 1,
+  "type": "object",
+  "properties": {
+    "resources": {
+      "title": "Resources",
+      "description": "Which resources are reserved",
+      "type": "object",
+      "additonalProperties": false,
+      "properties": {
+        "stations": {
+          "title": "Stations",
+          "description": "List of stations",
+	  "$ref": "http://tmss.lofar.org/api/schemas/commonschematemplate/stations/1#/definitions/station_list"
+        }
+      },
+      "required": []
+    }
+  },
+  "required": [
+    "resources"
+  ]
+}
diff --git a/SAS/TMSS/src/tmss/tmssapp/schemas/templates.json b/SAS/TMSS/src/tmss/tmssapp/schemas/templates.json
index 6e1d2c710101efe1a396935340fcdee899fe3ded..55f5cd2d4401c5592f0faaa3b627557e29f6cace 100644
--- a/SAS/TMSS/src/tmss/tmssapp/schemas/templates.json
+++ b/SAS/TMSS/src/tmss/tmssapp/schemas/templates.json
@@ -126,14 +126,18 @@
     "file_name": "sap_template-1.json",
     "template": "sap_template"
   },
-    {
+  {
     "file_name": "subtask_template-ingest-1.json",
     "template": "subtask_template",
     "type": "copy"
-    },
-    {
+  },
+  {
     "file_name": "task_template-ingest-1.json",
     "template": "task_template",
     "type": "ingest"
+  },
+  {
+    "file_name": "reservation_template-reservation-1.json",
+    "template": "reservation_template"
   }
 ]
\ No newline at end of file
diff --git a/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py b/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py
index 0c215aa57d1915e0660bd31572775bd3992d00d9..19afb2076dfec6e7b2644021680e1750d90db36e 100644
--- a/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py
+++ b/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py
@@ -385,3 +385,20 @@ class TaskTypeSerializer(RelationalHyperlinkedModelSerializer):
         model = models.TaskType
         fields = '__all__'
 
+
+class ReservationTemplateSerializer(AbstractTemplateSerializer):
+    class Meta:
+        model = models.ReservationTemplate
+        fields = '__all__'
+
+
+class DefaultReservationTemplateSerializer(RelationalHyperlinkedModelSerializer):
+    class Meta:
+        model = models.DefaultReservationTemplate
+        fields = '__all__'
+
+
+class ReservationSerializer(RelationalHyperlinkedModelSerializer):
+    class Meta:
+        model = models.Reservation
+        fields = '__all__'
diff --git a/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py
index f4f1e95ddbe38152855429597c6360be6448e4dc..64c4e9e588e228a509c12be4f66a687b132ae096 100644
--- a/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py
+++ b/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py
@@ -174,6 +174,21 @@ class DefaultTaskRelationSelectionTemplateViewSet(LOFARViewSet):
     serializer_class = serializers.DefaultTaskRelationSelectionTemplateSerializer
 
 
+class DefaultReservationTemplateViewSet(LOFARViewSet):
+    queryset = models.DefaultReservationTemplate.objects.all()
+    serializer_class = serializers.DefaultReservationTemplateSerializer
+
+
+class ReservationTemplateViewSet(AbstractTemplateViewSet):
+    queryset = models.ReservationTemplate.objects.all()
+    serializer_class = serializers.ReservationTemplateSerializer
+
+
+class ReservationViewSet(LOFARViewSet):
+    queryset = models.Reservation.objects.all()
+    serializer_class = serializers.ReservationSerializer
+
+
 class RoleViewSet(LOFARViewSet):
     queryset = models.Role.objects.all()
     serializer_class = serializers.RoleSerializer
@@ -914,4 +929,5 @@ class TaskRelationBlueprintNestedViewSet(LOFARNestedViewSet):
 
 class TaskTypeViewSet(LOFARViewSet):
     queryset = models.TaskType.objects.all()
-    serializer_class = serializers.TaskTypeSerializer
\ No newline at end of file
+    serializer_class = serializers.TaskTypeSerializer
+
diff --git a/SAS/TMSS/src/tmss/urls.py b/SAS/TMSS/src/tmss/urls.py
index 623d43642732d4a11463f252adffb0938259d9c9..0ba7a22d9fbf789defbb7022074cec4963ead9bc 100644
--- a/SAS/TMSS/src/tmss/urls.py
+++ b/SAS/TMSS/src/tmss/urls.py
@@ -127,12 +127,14 @@ router.register(r'scheduling_unit_template', viewsets.SchedulingUnitTemplateView
 router.register(r'scheduling_constraints_template', viewsets.SchedulingConstraintsTemplateViewSet)
 router.register(r'task_template', viewsets.TaskTemplateViewSet)
 router.register(r'task_relation_selection_template', viewsets.TaskRelationSelectionTemplateViewSet)
+router.register(r'reservation_template', viewsets.ReservationTemplateViewSet)
 router.register(r'task_connector_type', viewsets.TaskConnectorTypeViewSet)
 router.register(r'default_generator_template', viewsets.DefaultGeneratorTemplateViewSet)
 router.register(r'default_scheduling_unit_template', viewsets.DefaultSchedulingUnitTemplateViewSet)
 router.register(r'default_scheduling_constraints_template', viewsets.DefaultSchedulingConstraintsTemplateViewSet)
 router.register(r'default_task_template', viewsets.DefaultTaskTemplateViewSet)
 router.register(r'default_task_relation_selection_template', viewsets.DefaultTaskRelationSelectionTemplateViewSet)
+router.register(r'default_reservation_template', viewsets.DefaultReservationTemplateViewSet)
 
 # instances
 router.register(r'cycle', viewsets.CycleViewSet)
@@ -141,6 +143,7 @@ router.register(r'project', viewsets.ProjectViewSet)
 router.register(r'resource_type', viewsets.ResourceTypeViewSet)
 router.register(r'project_quota', viewsets.ProjectQuotaViewSet)
 router.register(r'setting', viewsets.SettingViewSet)
+router.register(r'reservation', viewsets.ReservationViewSet)
 
 router.register(r'scheduling_set', viewsets.SchedulingSetViewSet)
 router.register(r'scheduling_unit_draft', viewsets.SchedulingUnitDraftViewSet)
diff --git a/SAS/TMSS/test/t_tmssapp_specification_REST_API.py b/SAS/TMSS/test/t_tmssapp_specification_REST_API.py
index 018c985f4b69f7b626564bda91f076dcc49591b9..e69a0a55f0bf1cbd466253a051ec5db88cd42392 100755
--- a/SAS/TMSS/test/t_tmssapp_specification_REST_API.py
+++ b/SAS/TMSS/test/t_tmssapp_specification_REST_API.py
@@ -267,6 +267,70 @@ class SchedulingConstraintsTemplateTestCase(unittest.TestCase):
         DELETE_and_assert_gone(self, url)
 
 
+class ReservationTemplateTestCase(unittest.TestCase):
+    def test_reservation_template_list_apiformat(self):
+        r = requests.get(BASE_URL + '/reservation_template/?format=api', auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        self.assertTrue("Reservation Template List" in r.content.decode('utf8'))
+
+    def test_reservation_template_GET_nonexistant_raises_error(self):
+        GET_and_assert_equal_expected_code(self, BASE_URL + '/reservation_template/1234321/', 404)
+
+    def test_reservation_template_POST_and_GET(self):
+        # POST and GET a new item and assert correctness
+        test_data = test_data_creator.ReservationTemplate()
+        expected_data = test_data_creator.update_schema_from_template("reservationtemplate", test_data)
+        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/reservation_template/', test_data, 201, expected_data)
+        url = r_dict['url']
+        GET_OK_and_assert_equal_expected_response(self, url+'?format=json', expected_data)
+
+    def test_reservation_template_PUT_invalid_raises_error(self):
+        test_data = test_data_creator.ReservationTemplate()
+        PUT_and_assert_expected_response(self, BASE_URL + '/reservation_template/9876789876/', test_data, 404, {})
+
+    def test_reservation_template_PUT(self):
+        # POST new item, verify
+        test_data = test_data_creator.ReservationTemplate()
+        expected_data = test_data_creator.update_schema_from_template("reservationtemplate", test_data)
+        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/reservation_template/', test_data, 201, expected_data)
+        url = r_dict['url']
+        GET_OK_and_assert_equal_expected_response(self, url, expected_data)
+        # PUT new values, verify
+        test_data2 = test_data_creator.ReservationTemplate("reservationtemplate2")
+        expected_data2 = test_data_creator.update_schema_from_template("reservationtemplate", test_data2)
+        PUT_and_assert_expected_response(self, url, test_data2, 200, expected_data2)
+        GET_OK_and_assert_equal_expected_response(self, url, expected_data2)
+
+    def test_reservation_template_PATCH(self):
+        # POST new item, verify
+        test_data = test_data_creator.ReservationTemplate()
+        expected_data = test_data_creator.update_schema_from_template("reservationtemplate", test_data)
+        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/reservation_template/', test_data, 201, expected_data)
+        url = r_dict['url']
+        GET_OK_and_assert_equal_expected_response(self, url, expected_data)
+
+        test_patch = {"name": "new_name",
+                      "description": "better description",
+                      "schema": minimal_json_schema(properties={"mykey": {"type":"string", "default":"my better value"}})}
+
+        # PATCH item and verify
+        expected_patch_data = test_data_creator.update_schema_from_template("reservationtemplate", test_patch)
+        PATCH_and_assert_expected_response(self, url, test_patch, 200, expected_patch_data)
+        expected_data = dict(test_data)
+        expected_data.update(expected_patch_data)
+        GET_OK_and_assert_equal_expected_response(self, url, expected_data)
+
+    def test_reservation_template_DELETE(self):
+        # POST new item, verify
+        test_data = test_data_creator.ReservationTemplate()
+        expected_data = test_data_creator.update_schema_from_template("reservationtemplate", test_data)
+        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/reservation_template/', test_data, 201, expected_data)
+        url = r_dict['url']
+        GET_OK_and_assert_equal_expected_response(self, url, expected_data)
+        # DELETE and check it's gone
+        DELETE_and_assert_gone(self, url)
+
+
 class TaskTemplateTestCase(unittest.TestCase):
 
     def test_task_template_list_apiformat(self):
@@ -1099,7 +1163,6 @@ class ProjectQuotaTestCase(unittest.TestCase):
         GET_OK_and_assert_equal_expected_response(self, project_quota_url, project_quota_test_data)
 
 
-
 class SchedulingSetTestCase(unittest.TestCase):
     def test_scheduling_set_list_apiformat(self):
         r = requests.get(BASE_URL + '/scheduling_set/?format=api', auth=AUTH)
@@ -2661,6 +2724,84 @@ class TaskSchedulingRelationDraftTestCase(unittest.TestCase):
         GET_OK_and_assert_equal_expected_response(self, BASE_URL + '/task_scheduling_relation_draft/%s/' % id2, test_data_2)
 
 
+class ReservationTestCase(unittest.TestCase):
+    def test_reservation_list_apiformat(self):
+        r = requests.get(BASE_URL + '/reservation/?format=api', auth=AUTH)
+        self.assertEqual(r.status_code, 200)
+        self.assertTrue("Reservation List" in r.content.decode('utf8'))
+
+    def test_reservation_GET_nonexistant_raises_error(self):
+        GET_and_assert_equal_expected_code(self, BASE_URL + '/reservation/1234321/', 404)
+
+    def test_reservation_POST_and_GET(self):
+        reservation_test_data = test_data_creator.Reservation(duration=60)
+
+        # POST and GET a new item and assert correctness
+        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/reservation/', reservation_test_data, 201, reservation_test_data)
+        url = r_dict['url']
+        GET_OK_and_assert_equal_expected_response(self, url, reservation_test_data)
+
+    def test_reservation_PUT_invalid_raises_error(self):
+        reservation_test_data = test_data_creator.Reservation(duration=60)
+        PUT_and_assert_expected_response(self, BASE_URL + '/reservation/9876789876/', reservation_test_data, 404, {})
+
+    def test_reservation_PUT(self):
+        project_url = test_data_creator.post_data_and_get_url(test_data_creator.Project(), '/project/')
+        reservation_test_data = test_data_creator.Reservation(name="reservation 1", duration=50, project_url=project_url)
+
+        # POST new item, verify
+        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/reservation/', reservation_test_data, 201, reservation_test_data)
+        url = r_dict['url']
+        GET_OK_and_assert_equal_expected_response(self, url, reservation_test_data)
+
+        reservation_test_data2 = test_data_creator.Reservation(name="reservation2", project_url=project_url)
+        # PUT new values, verify
+        PUT_and_assert_expected_response(self, url, reservation_test_data2, 200, reservation_test_data2)
+        GET_OK_and_assert_equal_expected_response(self, url, reservation_test_data2)
+
+    def test_reservation_PATCH(self):
+        reservation_test_data = test_data_creator.Reservation(duration=60)
+
+        # POST new item, verify
+        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/reservation/', reservation_test_data, 201, reservation_test_data)
+        url = r_dict['url']
+        GET_OK_and_assert_equal_expected_response(self, url, reservation_test_data)
+
+        test_patch = {"description": "This is a new and improved description",
+                      "duration": 90}
+
+        # PATCH item and verify
+        expected_patch_data = test_data_creator.update_schema_from_template("reservationtemplate", test_patch)
+        PATCH_and_assert_expected_response(self, url, test_patch, 200, expected_patch_data)
+        expected_data = dict(reservation_test_data)
+        expected_data.update(test_patch)
+        GET_OK_and_assert_equal_expected_response(self, url, expected_patch_data)
+
+    def test_reservation_DELETE(self):
+        reservation_test_data = test_data_creator.Reservation(duration=30, start_time=datetime.utcnow() + timedelta(days=1))
+        # POST new item, verify
+        r_dict = POST_and_assert_expected_response(self, BASE_URL + '/reservation/', reservation_test_data, 201, reservation_test_data)
+        url = r_dict['url']
+        GET_OK_and_assert_equal_expected_response(self, url, reservation_test_data)
+
+        # DELETE and check it's gone
+        DELETE_and_assert_gone(self, url)
+
+    def test_GET_Reservation_list_shows_entry(self):
+        test_data_1 = Reservation_test_data(duration=3600)
+        models.Reservation.objects.create(**test_data_1)
+        nbr_results = models.Reservation.objects.count()
+        GET_and_assert_in_expected_response_result_list(self, BASE_URL + '/reservation/', test_data_1, nbr_results)
+
+    def test_GET_Reservation_view_returns_correct_entry(self):
+        test_data_1 = Reservation_test_data(name="Reservation 1", duration=60, start_time=datetime.utcnow() + timedelta(days=1))
+        test_data_2 = Reservation_test_data(name="Reservation 2", duration=120, start_time=datetime.utcnow() + timedelta(days=2))
+        id1 = models.Reservation.objects.create(**test_data_1).id
+        id2 = models.Reservation.objects.create(**test_data_2).id
+        GET_OK_and_assert_equal_expected_response(self, BASE_URL + '/reservation/' + str(id1) + '/', test_data_1)
+        GET_OK_and_assert_equal_expected_response(self, BASE_URL + '/reservation/' + str(id2) + '/', test_data_2)
+
+
 if __name__ == "__main__":
     logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                         level=logging.INFO)
diff --git a/SAS/TMSS/test/tmss_test_data_django_models.py b/SAS/TMSS/test/tmss_test_data_django_models.py
index 7f5f266be4ac768d006f7860abd9d8f85351c723..8c59a5c8959d5252825dff208bb07bce1574cb65 100644
--- a/SAS/TMSS/test/tmss_test_data_django_models.py
+++ b/SAS/TMSS/test/tmss_test_data_django_models.py
@@ -68,7 +68,6 @@ def SchedulingConstraintsTemplate_test_data(name="my_SchedulingConstraintsTempla
             "tags": ["TMSS", "TESTING"]}
 
 
-
 def SchedulingUnitObservingStrategyTemplate_test_data(name="my_SchedulingUnitObservingStrategyTemplate",
                                                       scheduling_unit_template:models.SchedulingUnitTemplate=None,
                                                       template:dict=None) -> dict:
@@ -495,3 +494,32 @@ def SAPTemplate_test_data() -> dict:
             "schema": minimal_json_schema(),
             "tags": ["TMSS", "TESTING"]}
 
+
+def ReservationTemplate_test_data(name="my_ReservationTemplate", schema:dict=None) -> dict:
+    if schema is None:
+        schema = minimal_json_schema(properties={ "foo" : { "type": "string", "default": "bar" } }, required=["foo"])
+
+    return {"name": name,
+            "description": 'My ReservationTemplate description',
+            "schema": schema,
+            "tags": ["TMSS", "TESTING"]}
+
+
+def Reservation_test_data(name="MyReservation", duration=None, start_time=None, project: models.Project = None) -> dict:
+    if project is None:
+        project = models.Project.objects.create(**Project_test_data())
+
+    if start_time is None:
+        start_time = datetime.utcnow() + timedelta(hours=12)
+
+    specifications_template = models.ReservationTemplate.objects.create(**ReservationTemplate_test_data())
+    specifications_doc = get_default_json_object_for_schema(specifications_template.schema)
+
+    return {"name": name,
+            "project": project,
+            "description": "Test Reservation",
+            "tags": ["TMSS", "TESTING"],
+            "start_time": start_time,
+            "duration": duration, # can be None
+            "specifications_doc": specifications_doc,
+            "specifications_template": specifications_template}
diff --git a/SAS/TMSS/test/tmss_test_data_rest.py b/SAS/TMSS/test/tmss_test_data_rest.py
index 1a16d480f10c74cd783b3ea88d39fd363b1c2cfc..17f78eaf04f89360724f2c1896037f65c2029445 100644
--- a/SAS/TMSS/test/tmss_test_data_rest.py
+++ b/SAS/TMSS/test/tmss_test_data_rest.py
@@ -130,6 +130,16 @@ class TMSSRESTTestDataCreator():
                  "tags": ["TMSS", "TESTING"]}
 
 
+    def ReservationTemplate(self, name="reservationtemplate1", schema:dict=None) -> dict:
+        if schema is None:
+            schema = minimal_json_schema(properties={"foo": {"type": "string", "default": "bar"}})
+
+        return { "name": name,
+                 "description": 'My description',
+                 "schema": schema,
+                 "tags": ["TMSS", "TESTING"]}
+
+
     def SchedulingUnitObservingStrategyTemplate(self, name="my_SchedulingUnitObservingStrategyTemplate",
                                                       scheduling_unit_template_url=None,
                                                       template:dict=None) -> dict:
@@ -669,4 +679,30 @@ class TMSSRESTTestDataCreator():
 
         return {"specifications_doc": specifications_doc,
                 "specifications_template": specifications_template_url,
-                "tags": ['tmss', 'testing']}
\ No newline at end of file
+                "tags": ['tmss', 'testing']}
+
+    def Reservation(self, name="My Reservation", duration=None, start_time=None, project_url=None,
+                    specifications_template_url=None, specifications_doc=None) -> dict:
+
+        if project_url is None:
+            project_url = self.post_data_and_get_url(self.Project(), '/project/')
+        if start_time is None:
+            start_time = datetime.utcnow() + timedelta(hours=12)
+
+        if specifications_template_url is None:
+            specifications_template_url = self.post_data_and_get_url(self.ReservationTemplate(), '/reservation_template/')
+
+        if specifications_doc is None:
+            specifications_doc = self.get_response_as_json_object(specifications_template_url + '/default')
+
+        if isinstance(start_time, datetime):
+            start_time = start_time.isoformat()
+
+        return {"name": name,
+                "project": project_url,
+                "description": "Test Reservation",
+                "tags": ["TMSS", "TESTING"],
+                "start_time": start_time,
+                "duration": duration, # can be None
+                "specifications_doc": specifications_doc,
+                "specifications_template": specifications_template_url}
\ No newline at end of file