diff --git a/core/migrations/0006_auto_20180104_2001.py b/core/migrations/0006_auto_20180104_2001.py
index 7a1672479bf09f7629b13877cba53a6183003e49..f790ca9e5be399441ce8ee2176a5b14a27974b82 100644
--- a/core/migrations/0006_auto_20180104_2001.py
+++ b/core/migrations/0006_auto_20180104_2001.py
@@ -1,8 +1,8 @@
 # Generated by Django 2.0.1 on 2018-01-04 20:01
 
+import django.db.models.deletion
 from django.conf import settings
 from django.db import migrations, models
-import django.db.models.deletion
 
 
 class Migration(migrations.Migration):
diff --git a/core/models.py b/core/models.py
index f2268ed945cd64a993ee96e391ce98f01c28ac83..40af977566befbd7000bd739e75b92595482b974 100644
--- a/core/models.py
+++ b/core/models.py
@@ -526,6 +526,15 @@ class GeneralTaskSubscription(models.Model):
             subscription=self,
             submission=task)[0]
 
+    def reserve_all_assignments_for_a_student(self):
+        assert self.query_type == self.STUDENT_QUERY
+
+        try:
+            while True:
+                self.get_or_create_work_assignment()
+        except SubscriptionEnded as err:
+            log.info(f'Loaded all subscriptions of student {self.query_key}')
+
     def _create_new_assignment_if_subscription_empty(self):
         if self.assignments.filter(is_done=False).count() < 1:
             self.get_or_create_work_assignment()
diff --git a/core/permissions.py b/core/permissions.py
index e88aed697a0e5500f6f8e5f376e2d9dc8f1fae12..7c5f5cf0e427c0acf8cd12a08b3b6864f8c9e51b 100644
--- a/core/permissions.py
+++ b/core/permissions.py
@@ -4,7 +4,6 @@ from django.http import HttpRequest
 from django.views import View
 from rest_framework import permissions
 
-
 log = logging.getLogger(__name__)
 
 
diff --git a/core/serializers.py b/core/serializers.py
index 18b7f14233b234bec04b853500c6c912ed39b294..ecff4a41ae11e8116f45ebc786f5d5acd57c7bbb 100644
--- a/core/serializers.py
+++ b/core/serializers.py
@@ -1,15 +1,12 @@
 import logging
 
-from django.db import IntegrityError
 from django.core.exceptions import ObjectDoesNotExist
-
 from drf_dynamic_fields import DynamicFieldsMixin
 from rest_framework import serializers
 
 from core import models
 from core.models import (ExamType, Feedback, GeneralTaskSubscription,
-                         StudentInfo,
-                         Submission, SubmissionType,
+                         StudentInfo, Submission, SubmissionType,
                          TutorSubmissionAssignment)
 from util.factories import GradyUserFactory
 
@@ -37,16 +34,12 @@ class FeedbackSerializer(DynamicFieldsModelSerializer):
         log.debug(data)
         assignment_id = data.pop('assignment_id')
         score = data.get('score')
-        creator = self.context.get('request').user
 
         try:
             assignment = TutorSubmissionAssignment.objects.get(
                 assignment_id=assignment_id)
         except ObjectDoesNotExist as err:
-            raise serializers.ValidationError('No assignment for id')
-
-        if not assignment.subscription.owner == creator:
-            raise serializers.ValidationError('This is not your assignment')
+            raise serializers.ValidationError('No assignment for given id.')
 
         submission = assignment.submission
         if not 0 <= score <= submission.type.full_score:
@@ -60,12 +53,10 @@ class FeedbackSerializer(DynamicFieldsModelSerializer):
         return {
             **data,
             'assignment': assignment,
-            'of_tutor': creator,
             'of_submission': submission
         }
 
     def create(self, validated_data) -> Feedback:
-        log.debug(validated_data)
         assignment = validated_data.pop('assignment')
         assignment.set_done()
 
@@ -176,27 +167,29 @@ class SubscriptionSerializer(DynamicFieldsModelSerializer):
     assignments = AssignmentSerializer(read_only=True, many=True)
 
     def validate(self, data):
+        data['owner'] = self.context['request'].user
+
         if 'query_key' in data != \
                 data['query_type'] == GeneralTaskSubscription.RANDOM:
             raise serializers.ValidationError(
                 f'The {data["query_type"]} query_type does not work with the'
                 f'provided key')
 
-        return data
-
-    def create(self, validated_data) -> GeneralTaskSubscription:
-        subscription = GeneralTaskSubscription.objects.create(
-            owner=self.context.get("request").user,
-            **validated_data)
         try:
-            subscription._create_new_assignment_if_subscription_empty()
-        except IntegrityError as err:
-            log.debug(err)
-            raise
+            GeneralTaskSubscription.objects.get(
+                owner=data['owner'],
+                query_type=data['query_type'],
+                query_key=data.get('query_key', None))
+        except ObjectDoesNotExist:
+            pass
+        else:
             raise serializers.ValidationError(
-                "Oh great, you raised an IntegrityError. I'm disappointed.")
+                'The user already has the subscription')
+
+        return data
 
-        return subscription
+    def create(self, validated_data) -> GeneralTaskSubscription:
+        return GeneralTaskSubscription.objects.create(**validated_data)
 
     class Meta:
         model = GeneralTaskSubscription
diff --git a/core/tests/test_subscription_assignment_service.py b/core/tests/test_subscription_assignment_service.py
index 20f81577d32c2c3998d68cb4b03261e22e2509dc..ebdcd33d0de612dc6dd05950c46379e8595da0d7 100644
--- a/core/tests/test_subscription_assignment_service.py
+++ b/core/tests/test_subscription_assignment_service.py
@@ -1,12 +1,12 @@
-
-from django.test import TestCase
+from rest_framework import status
+from rest_framework.test import APIClient, APITestCase
 
 from core.models import (GeneralTaskSubscription, Submission, SubmissionType,
                          SubscriptionEnded)
-from util.factories import GradyUserFactory
+from util.factories import GradyUserFactory, make_test_data
 
 
-class GeneralTaskSubscriptionRandomTest(TestCase):
+class GeneralTaskSubscriptionRandomTest(APITestCase):
 
     @classmethod
     def setUpTestData(cls):
@@ -56,3 +56,120 @@ class GeneralTaskSubscriptionRandomTest(TestCase):
         assignment = self.subscription.get_oldest_unfinished_assignment()
         self.assertEqual(assignment,
                          self.subscription.get_oldest_unfinished_assignment())
+
+
+class TestApiEndpoints(APITestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        cls.data = make_test_data(data_dict={
+            'submission_types': [
+                {
+                    'name': '01. Sort this or that',
+                    'full_score': 35,
+                    'description': 'Very complicated',
+                    'solution': 'Trivial!'
+                },
+                {
+                    'name': '02. Merge this or that or maybe even this',
+                    'full_score': 35,
+                    'description': 'Very complicated',
+                    'solution': 'Trivial!'
+                },
+                {
+                    'name': '03. This one exists for the sole purpose to test',
+                    'full_score': 30,
+                    'description': 'Very complicated',
+                    'solution': 'Trivial!'
+                }
+            ],
+            'students': [
+                {'username': 'student01'},
+                {'username': 'student02'}
+            ],
+            'tutors': [
+                {'username': 'tutor01'},
+                {'username': 'tutor02'}
+            ],
+            'submissions': [
+                {
+                    'text': 'function blabl\n'
+                    '   on multi lines\n'
+                    '       for blabla in bla:\n'
+                    '           lorem ipsum und so\n',
+                    'type': '01. Sort this or that',
+                    'user': 'student01',
+                    'feedback': {
+                            'text': 'Not good!',
+                            'score': 5,
+                            'of_tutor': 'tutor01',
+                            'is_final': True
+                    }
+                },
+                {
+                    'text': 'function blabl\n'
+                    '       asasxasx\n'
+                    '           lorem ipsum und so\n',
+                    'type': '02. Merge this or that or maybe even this',
+                    'user': 'student01'
+                },
+                {
+                    'text': 'function blabl\n'
+                    '   on multi lines\n'
+                    '       asasxasx\n'
+                    '           lorem ipsum und so\n',
+                    'type': '03. This one exists for the sole purpose to test',
+                    'user': 'student01'
+                },
+                {
+                    'text': 'function lorem ipsum etc\n',
+                    'type': '03. This one exists for the sole purpose to test',
+                    'user': 'student02'
+                },
+            ]}
+        )
+
+    def test_can_create_a_subscription(self):
+        client = APIClient()
+        client.force_authenticate(user=self.data['tutors'][0])
+
+        response = client.post('/api/subscription/', {'query_type': 'random'})
+
+        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
+
+    def test_create_subscription_and_get_one_assignment(self):
+        client = APIClient()
+        client.force_authenticate(user=self.data['tutors'][0])
+
+        response = client.post('/api/subscription/', {'query_type': 'random'})
+
+        self.assertEqual('tutor01', response.data['owner'])
+
+    def test_subscription_has_next_assignment(self):
+        client = APIClient()
+        client.force_authenticate(user=self.data['tutors'][0])
+
+        response_subs = client.post(
+            '/api/subscription/', {'query_type': 'random'})
+        subscription_id = response_subs.data['subscription_id']
+        assignment_id = response_subs.data['assignments'][0]['assignment_id']
+
+        response_current = client.get(
+            f'/api/subscription/{subscription_id}/assignments/current/')
+
+        self.assertEqual(1, len(response_subs.data['assignments']))
+        self.assertEqual(assignment_id,
+                         response_current.data['assignment_id'])
+
+    def test_subscription_can_assign_to_student(self):
+        client = APIClient()
+        client.force_authenticate(user=self.data['tutors'][0])
+
+        response_subs = client.post(
+            '/api/subscription/', {
+                'query_type': 'student',
+                'query_key': 'student01'
+            })
+
+        assignments = response_subs.data['assignments']
+        self.assertEqual(2, len(assignments))
diff --git a/core/tests/test_tutor_api_endpoints.py b/core/tests/test_tutor_api_endpoints.py
index 908626d1a3b90829b2d1fc516b6484b4c03b801e..133b23826e0219086fe911a42f26a7fd4191017f 100644
--- a/core/tests/test_tutor_api_endpoints.py
+++ b/core/tests/test_tutor_api_endpoints.py
@@ -109,7 +109,6 @@ class TutorDetailViewTests(APITestCase):
 
     @classmethod
     def setUpTestData(cls):
-        cls.factory = APIClient()
         cls.user_factory = GradyUserFactory()
 
     def setUp(self):
diff --git a/core/views.py b/core/views.py
index fc584ded203c172bdbe76fd3cc84404e723f276d..6a8b9839b4f014ff2cd3c0e1f529d4498e0086ee 100644
--- a/core/views.py
+++ b/core/views.py
@@ -7,16 +7,16 @@ from rest_framework.decorators import api_view, detail_route
 from rest_framework.response import Response
 
 from core import models
-from core.models import (ExamType, GeneralTaskSubscription, StudentInfo,
-                         SubmissionType, TutorSubmissionAssignment,
-                         Feedback)
+from core.models import (ExamType, Feedback, GeneralTaskSubscription,
+                         StudentInfo, SubmissionType,
+                         TutorSubmissionAssignment)
 from core.permissions import IsReviewer, IsStudent, IsTutorOrReviewer
-from core.serializers import (AssignmentSerializer, ExamSerializer,
+from core.serializers import (AssignmentDetailSerializer, AssignmentSerializer,
+                              ExamSerializer, FeedbackSerializer,
                               StudentInfoSerializer,
                               StudentInfoSerializerForListView,
                               SubmissionTypeSerializer, SubscriptionSerializer,
-                              TutorSerializer, FeedbackSerializer,
-                              AssignmentDetailSerializer)
+                              TutorSerializer)
 
 
 @api_view()
@@ -57,6 +57,21 @@ class FeedbackApiView(
     serializer_class = FeedbackSerializer
     lookup_field = 'submission__submission_id'
 
+    def create(self, request, *args, **kwargs):
+        serializer = self.get_serializer(
+            data={**request.data, 'of_tutor': request.user})
+        serializer.is_valid(raise_exception=True)
+
+        if serializer.data['assignment'].subscription.owner != request.user:
+            return Response({'You do not have permission to edit this'},
+                            status=status.HTTP_403_FORBIDDEN)
+
+        self.perform_create(serializer)
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data,
+                        status=status.HTTP_201_CREATED,
+                        headers=headers)
+
 
 class TutorApiViewSet(
         mixins.RetrieveModelMixin,
@@ -129,6 +144,21 @@ class SubscriptionApiViewSet(
         instance.delete()
         return Response(status=status.HTTP_204_NO_CONTENT)
 
+    def create(self, request, *args, **kwargs):
+        serializer = self.get_serializer(data=request.data)
+        serializer.is_valid(raise_exception=True)
+        subscription = serializer.save()
+
+        if subscription.query_type == GeneralTaskSubscription.STUDENT_QUERY:
+            subscription.reserve_all_assignments_for_a_student()
+        else:
+            subscription.get_oldest_unfinished_assignment()
+
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data,
+                        status=status.HTTP_201_CREATED,
+                        headers=headers)
+
 
 class AssignmentApiViewSet(
         mixins.RetrieveModelMixin,
diff --git a/docs/feedback.api.json b/docs/feedback.api.json
new file mode 100644
index 0000000000000000000000000000000000000000..c48beea4146bc18419f8a5b03ecf2d9de9826fe2
--- /dev/null
+++ b/docs/feedback.api.json
@@ -0,0 +1,43 @@
+GET /subscription/<id>
+    {
+        "subscription_id": "e313e608-7453-4053-a536-5d18fc9ec3a9",
+        "owner": "reviewer01",
+        "query_type": "random",
+        "query_key": "",
+        "assignments": [
+            {
+                "assignment_id": "dbdde0d0-b1a6-474c-b2be-41edb5229803",
+                "submission_id": "1558c390-5598-482b-abd3-1f5780e75e0d",
+                "is_done": false
+            }
+        ]
+    }
+
+POST /subscription/
+    {
+        "owner": "<some user>",
+        "query_type": "random|student|submission_type|exam",
+        "query_key": "<pk for query type>?"
+    }
+
+DELETE /subscription/<id>
+PATCH /subscription/<id> {
+    "deactivate": true // or false for reactivation
+}
+
+GET /subscription/assignments/current
+GET /subscription/assignments/next
+GET /subscription/assignments/past
+
+GET /assignment/<id> // only those belonging to the requests user
+    {
+        "assignment_id": "dbdde0d0-b1a6-474c-b2be-41edb5229803",
+        "submission_id": "1558c390-5598-482b-abd3-1f5780e75e0d",
+        "is_done": false
+    }
+
+DELETE /assignment/<id> // check done conditions
+
+// done conditions
+// * feedback was posted
+// * feedback was patched (every)
diff --git a/util/factories.py b/util/factories.py
index 463fb549a7a3d2926d1d7d28ceb07f8f94d3bb56..9ea00f3bd8b16329ca2680e24f7d3aa13cfdcbbf 100644
--- a/util/factories.py
+++ b/util/factories.py
@@ -123,9 +123,11 @@ def make_submission_types(submission_types=[], **kwargs):
 
 
 def make_students(students=[], **kwargs):
+
     return [GradyUserFactory().make_student(
         username=student['username'],
-        exam=ExamType.objects.get(module_reference=student['exam'])
+        exam=ExamType.objects.get(
+            module_reference=student['exam']) if 'exam' in student else None
     ) for student in students]