diff --git a/examples/submission.ipynb b/examples/submission.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..c9a7c1378de4d91a7a0560e760f0b886a638bbe5
--- /dev/null
+++ b/examples/submission.ipynb
@@ -0,0 +1,156 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Example notebooks for using the submission service"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from rwth_nb.misc.submission import Submission\n",
+    "\n",
+    "from random import randint\n",
+    "from pprint import pprint\n",
+    "        \n",
+    "sub = Submission('test_realm')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "print('\\nCreate some random submissions...')\n",
+    "for i in range(5):\n",
+    "    sub.submit({\n",
+    "        'random_integer': randint(1, 100)\n",
+    "    })"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Admin actions\n",
+    "\n",
+    "For performing admin actions the user must own the role manager-{profile_slug} or submission-{realm}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "print('\\nAll submissions:')\n",
+    "pprint(sub.get_all())\n",
+    "        \n",
+    "print('\\nDelete all submissions')\n",
+    "sub.delete_all()\n",
+    "    \n",
+    "print('\\nAll submissions:')\n",
+    "pprint(sub.get_all())"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## User actions"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "if sub.is_submitted():\n",
+    "    print('\\nEvaluation already submitted')\n",
+    "else:\n",
+    "    print('\\nNothing submitted yet!')\n",
+    "    sub.submit({'test': [1, 2, 3]})\n",
+    "        \n",
+    "    if sub.is_submitted():\n",
+    "        print('\\nNow it is submitted!:')\n",
+    "        pprint(sub.get())\n",
+    "              \n",
+    "print('\\nMy submissions:')\n",
+    "mysubs = sub.get()\n",
+    "print(mysubs)\n",
+    "    \n",
+    "ident = mysubs[0]['id']\n",
+    "print(f'\\nMy submission ID: {ident}')\n",
+    "    \n",
+    "print(f'\\nDeleting my submission with ID: {ident}')\n",
+    "sub.delete(ident=ident)\n",
+    "    \n",
+    "print('\\nMy submissions:')\n",
+    "mysubs = sub.get()\n",
+    "print(mysubs)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Submitting whole notebooks\n",
+    "\n",
+    "The following cell submits the current notebook contents"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "sub.submit_notebook()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The following cell fetches all submitted notebooks in the current realm by the current user and stores them in the current directory"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "sub.fetch_notebook(subdir='fetched_notebooks', prefix='a1')"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.6"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/rwth_nb/misc/feedback.py b/rwth_nb/misc/feedback.py
index 4d2e4a89570a5c99dbe934b34e8fcd60ba95f7d0..048dd71f829e9c8786bef95da6d5fcaac36a00e3 100644
--- a/rwth_nb/misc/feedback.py
+++ b/rwth_nb/misc/feedback.py
@@ -13,7 +13,6 @@ import subprocess  # for hiding files on Windows
 import pandas as pd
 import logging
 
-
 def get_notebook_name():
     try:
         # import necessary packages (see https://github.com/jupyter/notebook/issues/1000)
@@ -43,7 +42,8 @@ def get_notebook_name():
 
 
 class RWTHFeedback:
-    """ RWTH Feedback submission class
+    """
+    RWTH Feedback submission class
 
     Use as described in RWTH\ Misc.ipynb
     """
@@ -365,7 +365,6 @@ class RWTHFeedback:
         self.btn_submit.disabled = True
         self.btn_submit.description = self.feedback_text['sent']
 
-
 class RWTHCollector:
     """ RWTH Collector Class
 
diff --git a/rwth_nb/misc/notebook.py b/rwth_nb/misc/notebook.py
new file mode 100644
index 0000000000000000000000000000000000000000..ea334f1e78a64568d5260a9bde587f6a6c3ee54c
--- /dev/null
+++ b/rwth_nb/misc/notebook.py
@@ -0,0 +1,28 @@
+import os
+import requests
+from IPython.lib import kernel
+from notebook import notebookapp
+
+def get_contents():
+    servers = list(notebookapp.list_running_servers())
+    
+    token = servers[0]['token']
+    api_url = servers[0]['url'] + 'api'
+
+    connection_file_path = kernel.get_connection_file()
+    connection_file = os.path.basename(connection_file_path)
+    kernel_id = connection_file.split('-', 1)[1].split('.')[0]
+    
+    headers = {
+        'Authorization': f'token {token}'
+    }
+
+    r = requests.request('GET', f'{api_url}/sessions', headers=headers)
+    
+    for session in r.json():
+        if session['kernel']['id'] == kernel_id:
+            path = session['notebook']['path']
+
+    r = requests.request('GET', f'{api_url}/contents/{path}', headers=headers)
+
+    return r.json()
\ No newline at end of file
diff --git a/rwth_nb/misc/submission.py b/rwth_nb/misc/submission.py
new file mode 100644
index 0000000000000000000000000000000000000000..92cb1615fce968b0c51a748d7665e3f8d16bf17b
--- /dev/null
+++ b/rwth_nb/misc/submission.py
@@ -0,0 +1,134 @@
+import requests
+import json
+import os
+import datetime as dt
+
+import rwth_nb.misc.notebook as notebook
+
+
+class Submission:
+    """Submit and retrieve submissions to RWTH JupyterHub Service"""
+
+    def __init__(self, realm):
+        self.realm = realm
+        
+        self.profile = os.environ.get('JUPYTERHUB_PROFILE')
+        self.token = os.environ.get('JUPYTERHUB_API_TOKEN')
+
+        self.service_url = 'http://proxy-public.jhub/services/submission'
+        
+        if self.token is None or self.profile is None:
+            raise Exception('Submissions only work inside the RWTHjupyter cluster!')
+    
+    def url(self, user='me', ident=None):
+        url = f'{self.service_url}/{self.profile}/{self.realm}'
+        
+        if user is not None:
+            url += f'/{user}'
+            
+            if ident is not None:
+                url += f'/{ident}'
+                
+        return url
+    
+    def headers(self):
+        return {
+            'Authorization': f'token {self.token}'
+        }
+    
+    def _parse_get(self, response):
+        payload = response.json()
+        
+        if 'data' in payload:
+            for data in payload['data']:
+                if 'submitted' in data:
+                    data['submitted'] = dt.datetime.fromisoformat(data['submitted'])
+                    
+        return payload
+
+    def submit(self, data):
+        """Submit some arbitrary JSON payload"""
+
+        r = requests.request('POST',
+                             url=self.url(user=None),
+                             data=json.dumps(data),
+                             headers=self.headers())
+        r.raise_for_status()
+        
+    def submit_notebook(self):
+        """Submit the notebook as JSON"""
+
+        nb = notebook.get_contents()
+        
+        self.submit(nb)
+
+    def is_submitted(self):
+        """Check if the user has already submitted something to this realm"""
+        
+        s = self.get()
+        
+        return len(s) > 0
+    
+    def get(self, user='me', ident=None, limit=None):
+        """Get all submissions for a user"""
+
+        params = {}
+        if limit is not None:
+            params['limit'] = limit
+        
+        r = requests.request('GET', url=self.url(user, ident),
+                             headers=self.headers(),
+                             params=params)
+        r.raise_for_status()
+
+        j = self._parse_get(r)
+        
+        return j['submissions']
+    
+    def fetch_notebook(self, user='me', ident=None, limit=None, subdir=None, prefix=None):
+        subs = self.get(user, ident, limit)
+        
+        for sub in subs:            
+            nb = sub.pop('data')
+            
+            realm = sub['realm']
+            submitter = sub['submitter']
+            id = sub['id']
+            name, ext = os.path.splitext(nb['name'])
+            
+            # Add submission details as metadata to the notebook
+            nb['content']['metadata']['submission'] = sub
+            
+            fn = f'{name}_{realm}_{submitter}-{id}{ext}'
+            
+            if prefix:
+                fn = f'{prefix}_{fn}'
+
+            if subdir:
+                os.makedirs(subdir)
+                fn = f'{subdir}/{fn}'
+            
+            with open(fn, 'w+') as nb_file:
+                json.dump(nb['content'], nb_file)
+                
+    def fetch_all_notebooks(self):
+        """Get all submissions in a realm"""
+
+        return self.fetch_notebook(user=None)
+    
+    def delete(self, user='me', ident=None):
+        """Delete the users submission"""
+        
+        r = requests.request('DELETE', url=self.url(user, ident),
+                             headers=self.headers())
+        r.raise_for_status()
+        
+    def get_all(self):
+        """Get all submissions in a realm"""
+
+        return self.get(user=None)
+    
+    def delete_all(self):
+        """Delete all submissions"""
+        
+        return self.delete(user=None)
\ No newline at end of file
diff --git a/tests/submission.py b/tests/submission.py
new file mode 100644
index 0000000000000000000000000000000000000000..9ba0825a8f240d56f88ed3f3790b7d23c7fdb844
--- /dev/null
+++ b/tests/submission.py
@@ -0,0 +1,20 @@
+# Testing
+
+from rwth_nb.misc.submission import Submission
+
+#os.environ['JUPYTERHUB_API_TOKEN'] = 'xxx'
+
+if __name__ == '__main__':
+    sub = Submission('test_realm')
+
+    is_submitted = sub.is_submitted()
+    if is_submitted:
+        print('Evaluation already submitted')
+    else:
+        sub.submit({
+            'test': [1, 2, 3]
+        })
+
+    print('All submissions:')
+    for s in sub.get_all():
+        print(s)