diff --git a/hook.wsgi b/hook.wsgi
index 740d30b031f5823c2fc886a6a15c05c603a0a45b..5306dfede92b75985856426cd7ba7d06c14599ee 100644
--- a/hook.wsgi
+++ b/hook.wsgi
@@ -4,7 +4,10 @@
 import configparser
 import json
 import psycopg2
+import psycopg2.extras
 import traceback
+import dateutil.parser
+# import dateutil.tz
 
 ### Configuration ###
 
@@ -21,22 +24,31 @@ def db_connect():
     db_connection = psycopg2.connect(
                 host='localhost',
                 user=config['db']['user'],
-                passwd=config['db']['passwd'],
-                db=config['db']['name'],
+                password=config['db']['passwd'],
+                dbname=config['db']['name'],
             )
-    db = db_conn.cursor(cursor_factory=psycopg2.extras.NamedTupleCursor)
+    db = db_connection.cursor(cursor_factory=psycopg2.extras.NamedTupleCursor)
 
 def db_query(query, args=()):
     if db is None:
         db_connect()
     try:
         db.execute(query, args)
-        # FIXME: Adapt for Postgres!
-    except MySQLdb.OperationalError:
+    except psycopg2.DatabaseError:
         # Reconnect if the connection died (timeout, server restart etc.)
         db_connect()
         db.execute(query, args)
 
+### Utilities ###
+
+# FIXME: Move to shared code?
+
+def parse_time(iso_time, tz_name):
+    utc = dateutil.parser.isoparse(iso_time)
+    # tz = dateutil.tz.gettz(tz_name)
+    # return utc.astimezone(tz)
+    return utc
+
 ### Application ###
 
 class HookApp:
@@ -54,21 +66,82 @@ class HookApp:
             ])
         return ["{} {}".format(code, msg)]
 
-    def run(self):
-        self.log(self.env)
+    def create_meeting(self, js):
+        payload = js["payload"]
+        object = payload["object"]
+        meeting_id = object["id"]
+
+        type = object["type"]
+        if type != 2 and type != 8:
+            self.log(f"Meeting type {type} ignored")
+            return
+
+        host_user_id = object["host_id"]
+        db_query("SELECT * FROM zoom_users WHERE user_id=%s", (host_user_id,))
+        user = db.fetchone()
+        if user is None:
+            self.log(f"Meeting {meeting_id}: Host {host_user_id} not found in zoom_users")
+
+        self.log(f"Meeting {meeting_id}: Planning")
+        db_query("""
+                INSERT INTO zoom_meetings
+                (meeting_id, uuid, host_id, topic, type, start_time, duration)
+                VALUES (%s, %s, %s, %s, %s, %s, %s)
+            """, (
+                meeting_id,
+                object['uuid'],
+                user.id,
+                object['topic'],
+                object['type'],
+                parse_time(object['start_time'], object['timezone']),
+                object['duration'],
+            ))
+
+        db_connection.commit()
+
+    def delete_meeting(self, js):
+        payload = js["payload"]
+        object = payload["object"]
+        meeting_id = object["id"]
+
+        type = object["type"]
+        if type != 2 and type != 8:
+            self.log(f"Meeting type {type} ignored")
+            return
+
+        self.log(f"Meeting {meeting_id}: Deleting")
+        db_query("""
+                DELETE FROM zoom_meetings
+                WHERE meeting_id=%s AND start_time=%s AND duration=%s
+            """, (
+                meeting_id,
+                parse_time(object['start_time'], object['timezone']),
+                object['duration'],
+            ))
+
+        db_connection.commit()
 
+    def run(self):
         method = self.env['REQUEST_METHOD']
         if method != 'POST':
             return self.http_error(405, 'Method not allowed', [('Allow', 'POST')])
 
-	# FIXME: Check authorization
-
-        self.log('Gotcha!')
+        if self.env.get('HTTP_AUTHORIZATION', '') != config['hooks']['verification_token']:
+            self.log('Verification token does not match!')
+            return self.http_error(401, 'Authorization failed')
 
         body = self.env['wsgi.input'].read()
         js = json.loads(body)
         self.log(js)
 
+        event = js["event"]
+#        if event == "meeting.created":
+#            self.create_meeting(js)
+#        elif event == "meeting.deleted":
+#            self.delete_meeting(js)
+#        else:
+#            self.log(f"Unknown event: {event}")
+
         self.wsgi_start("204 No Content", [])
         return b""