diff --git a/skouter.go b/skouter.go
index 86bf325..1160d9b 100644
--- a/skouter.go
+++ b/skouter.go
@@ -571,6 +571,23 @@ func fetchFeesTemp(db *sql.DB, user int, branch int) ([]FeeTemplate, error) {
 	return fees, nil
 }
 
+func constructEvent(r *http.Request, key string) (*stripe.Event, error) {
+	b, err := io.ReadAll(r.Body)
+	if err != nil {
+		log.Printf("io.ReadAll: %v", err)
+		return nil, err
+	}
+	
+	event, err :=
+	webhook.ConstructEvent(b, r.Header.Get("Stripe-Signature"), key)
+	if err != nil {
+		log.Printf("webhook.ConstructEvent: %v", err)
+		return nil, err
+	}
+	
+	return &event, nil
+}
+
 // Fetch fees from the database
 func getFeesTemp(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 	var fees []FeeTemplate
@@ -3037,6 +3054,28 @@ func createSubscription(cid string) (*stripe.Subscription, error) {
     return s, err
 }
 
+func ( user *User ) SyncSub( sub *stripe.Subscription, db *sql.DB ) error {
+	var err error
+	
+	user.Sub.UserId = user.Id
+	user.Sub.StripeId = sub.ID
+	user.Sub.CustomerId = user.CustomerId
+	user.Sub.PriceId = standardPriceId
+	user.Sub.End = int(sub.CurrentPeriodEnd)
+	user.Sub.Start = int(sub.CurrentPeriodStart)
+	user.Sub.ClientSecret = sub.LatestInvoice.PaymentIntent.ClientSecret
+	user.Sub.PaymentStatus = string(sub.LatestInvoice.PaymentIntent.Status)
+	user.Sub.Status = string(sub.Status)
+	
+	if user.Sub.Id != 0 {
+		err = user.Sub.insertSub(db)
+	} else {
+		user.Sub.updateSub(db)
+	}
+	
+	return err
+}
+
 // Creates a new subscription instance for a new user or retrieves the
 // existing instance if possible. It's main purpose is to supply a
 // client secret used for sending billing information to stripe.
@@ -3164,25 +3203,14 @@ func invoiceFailed(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 }
 
 // Important for catching subscription creation through Stripe dashboard
-// although it already happens at subscribe(). It checks if the user already
-// has a subscription and replaces those fields if necessary so a seperate
-// subCreated() is not necessary.
-func subUpdated(w http.ResponseWriter, db *sql.DB, r *http.Request) {
-
+// although it already happens at subscribe().
+func subCreated(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 	var sub stripe.Subscription
-	b, err := io.ReadAll(r.Body)
-	if err != nil {
-		http.Error(w, err.Error(), http.StatusBadRequest)
-		log.Printf("io.ReadAll: %v", err)
-		return
-	}
-	
-	event, err := webhook.ConstructEvent(b,
-	r.Header.Get("Stripe-Signature"),
-	hookKeys.SubUpdated)
+	var err error
+
+	event, err := constructEvent(r, hookKeys.SubCreated)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusBadRequest)
-		log.Printf("webhook.ConstructEvent: %v", err)
 		return
 	}
 	
@@ -3191,7 +3219,7 @@ func subUpdated(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 	w.WriteHeader(http.StatusOK)
 	if event.Type != "customer.subscription.created" {
 		log.Println(
-		"Invalid event type sent to customer.subscription.created.")
+		"Invalid event type. Expecting customer.subscription.created.")
 		return
 	}
 	
@@ -3212,21 +3240,7 @@ func subUpdated(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 		user.update(db)
 	}
 	
-	user.Sub.UserId = user.Id
-	user.Sub.StripeId = sub.ID
-	user.Sub.CustomerId = user.CustomerId
-	user.Sub.PriceId = standardPriceId
-	user.Sub.End = int(sub.CurrentPeriodEnd)
-	user.Sub.Start = int(sub.CurrentPeriodStart)
-	user.Sub.ClientSecret = sub.LatestInvoice.PaymentIntent.ClientSecret
-	user.Sub.PaymentStatus = string(sub.LatestInvoice.PaymentIntent.Status)
-	user.Sub.Status = string(sub.Status)
-	
-	if user.Sub.Id != 0 {
-		err = user.Sub.insertSub(db)
-	} else {
-		user.Sub.updateSub(db)
-	}
+	err = user.SyncSub(&sub, db)
 	
 	if err != nil {
 		http.Error(w, err.Error(), 500)
@@ -3236,31 +3250,71 @@ func subUpdated(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 	log.Println("User subscription created:", user.Id, sub.ID)
 }
 
-// Handles changes to customer subscriptions sent by Stripe
-func subDeleted(w http.ResponseWriter, db *sql.DB, r *http.Request) {
+// Checks if the user already has a subscription and replaces those fields if
+// necessary.
+func subUpdated(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 	var sub stripe.Subscription
-	b, err := io.ReadAll(r.Body)
+	var err error
+
+	event, err := constructEvent(r, hookKeys.SubUpdated)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusBadRequest)
-		log.Printf("io.ReadAll: %v", err)
 		return
 	}
 	
-	event, err := webhook.ConstructEvent(b,
-	r.Header.Get("Stripe-Signature"),
-	hookKeys.SubUpdated)
+	// OK should be sent before any processing to confirm with Stripe that
+	// the hook was received
+	w.WriteHeader(http.StatusOK)
+	if event.Type != "customer.subscription.updated" {
+		log.Println(
+		"Invalid event type sent. Expecting customer.subscription.updated.")
+		return
+	}
+	
+	json.Unmarshal(event.Data.Raw, &sub)
+	log.Println(event.Type, sub.ID, sub.Customer.ID)
+	
+	user, err := queryCustomer(db, sub.Customer.ID)
+	if err != nil {
+		log.Printf("Could not query customer: %v", err)
+		return
+	}
+	
+	if statuses[user.Status] < 5 && sub.Status == "trialing" {
+		user.Status = "Trial"
+		user.update(db)
+	} else if sub.Status != "active" {
+		user.Status = "Unsubscribed"
+		user.update(db)
+	}
+	
+	err = user.SyncSub(&sub, db)
+	
+	if err != nil {
+		http.Error(w, err.Error(), 500)
+		return
+	}
+	
+	log.Println("User subscription created:", user.Id, sub.ID)
+}
+
+// Handles deleted subscriptions hooks sent by Stripe
+func subDeleted(w http.ResponseWriter, db *sql.DB, r *http.Request) {
+	var sub stripe.Subscription
+	var err error
+
+	event, err := constructEvent(r, hookKeys.SubDeleted)
 	if err != nil {
 		http.Error(w, err.Error(), http.StatusBadRequest)
-		log.Printf("webhook.ConstructEvent: %v", err)
 		return
 	}
 	
 	// OK should be sent before any processing to confirm with Stripe that
 	// the hook was received
 	w.WriteHeader(http.StatusOK)
-	if event.Type != "customer.subscription.updated" {
+	if event.Type != "customer.subscription.deleted" {
 		log.Println(
-		"Invalid event type sent to customer.subscription.updated.")
+		"Invalid event type sent. Expecting customer.subscription.deleted.")
 		return
 	}
 	
@@ -3281,21 +3335,9 @@ func subDeleted(w http.ResponseWriter, db *sql.DB, r *http.Request) {
 		user.update(db)
 	}
 	
-	user.Sub.UserId = user.Id
-	user.Sub.StripeId = sub.ID
-	user.Sub.CustomerId = user.CustomerId
-	user.Sub.PriceId = standardPriceId
-	user.Sub.End = int(sub.CurrentPeriodEnd)
-	user.Sub.Start = int(sub.CurrentPeriodStart)
-	user.Sub.ClientSecret = sub.LatestInvoice.PaymentIntent.ClientSecret
-	user.Sub.PaymentStatus = string(sub.LatestInvoice.PaymentIntent.Status)
-	user.Sub.Status = string(sub.Status)
+	user.Sub.Status = "canceled"
 	
-	if user.Sub.Id != 0 {
-		err = user.Sub.insertSub(db)
-	} else {
-		user.Sub.updateSub(db)
-	}
+	err = user.SyncSub(&sub, db)
 	
 	if err != nil {
 		http.Error(w, err.Error(), 500)
@@ -3435,13 +3477,13 @@ func api(w http.ResponseWriter, r *http.Request) {
 		invoiceFailed(w, db, r)
 	case match(p, "/api/stripe/sub-created", &args) &&
 		r.Method == http.MethodPost:
-		subUpdated(w, db, r)
+		subCreated(w, db, r)
 	case match(p, "/api/stripe/sub-updated", &args) &&
 		r.Method == http.MethodPost:
 		subUpdated(w, db, r)
-	case match(p, "/api/stripe/sub-updated", &args) &&
+	case match(p, "/api/stripe/sub-deleted", &args) &&
 		r.Method == http.MethodPost:
-		subUpdated(w, db, r)
+		subDeleted(w, db, r)
 	default:
 		http.Error(w, "Invalid route or token", 404)
 	}
@@ -3774,6 +3816,9 @@ func dev(args []string) {
 	hookKeys = HookKeys{
 		InvoicePaid: os.Getenv("DEV_WEBHOOK_KEY"),
 		InvoiceFailed: os.Getenv("DEV_WEBHOOK_KEY"),
+		SubCreated: os.Getenv("DEV_WEBHOOK_KEY"),
+		SubUpdated: os.Getenv("DEV_WEBHOOK_KEY"),
+		SubDeleted: os.Getenv("DEV_WEBHOOK_KEY"),
 	}
 
 	db, err := sql.Open("mysql",