diff --git a/persistence/playqueue_repository.go b/persistence/playqueue_repository.go
index 8d588c0d9..d092a7748 100644
--- a/persistence/playqueue_repository.go
+++ b/persistence/playqueue_repository.go
@@ -77,7 +77,7 @@ func (r *playQueueRepository) AddBookmark(userId, id, comment string, position i
 		UpdatedAt: time.Now(),
 	}
 
-	sel := r.newSelect().Column("id").Where(And{
+	sel := r.newSelect().Column("*").Where(And{
 		Eq{"user_id": userId},
 		Eq{"items": ""},
 		Eq{"current": id},
@@ -89,11 +89,13 @@ func (r *playQueueRepository) AddBookmark(userId, id, comment string, position i
 		return err
 	}
 
-	if !prev.CreatedAt.IsZero() {
+	// If there is a previous bookmark, override
+	if prev.ID != "" {
+		bm.ID = prev.ID
 		bm.CreatedAt = prev.CreatedAt
 	}
 
-	_, err = r.put(prev.ID, bm)
+	_, err = r.put(bm.ID, bm)
 	if err != nil {
 		log.Error(r.ctx, "Error saving bookmark", "user", u.UserName, err, "mediaFileId", id, err)
 		return err
@@ -115,7 +117,7 @@ func (r *playQueueRepository) GetBookmarks(userId string) (model.Bookmarks, erro
 		items := r.loadTracks(model.MediaFiles{{ID: pqs[i].Current}})
 		bms[i].Item = items[0]
 		bms[i].Comment = pqs[i].Comment
-		bms[i].Position = int64(pqs[i].Position)
+		bms[i].Position = pqs[i].Position
 		bms[i].CreatedAt = pqs[i].CreatedAt
 		bms[i].UpdatedAt = pqs[i].UpdatedAt
 	}
@@ -217,7 +219,7 @@ func (r *playQueueRepository) loadTracks(tracks model.MediaFiles) model.MediaFil
 }
 
 func (r *playQueueRepository) clearPlayQueue(userId string) error {
-	return r.delete(Eq{"user_id": userId})
+	return r.delete(And{Eq{"user_id": userId}, NotEq{"items": ""}})
 }
 
 var _ model.PlayQueueRepository = (*playQueueRepository)(nil)
diff --git a/server/subsonic/api.go b/server/subsonic/api.go
index 65cfe9d97..158ccad94 100644
--- a/server/subsonic/api.go
+++ b/server/subsonic/api.go
@@ -113,6 +113,9 @@ func (api *Router) routes() http.Handler {
 	r.Group(func(r chi.Router) {
 		c := initBookmarksController(api)
 		withPlayer := r.With(getPlayer(api.Players))
+		H(withPlayer, "getBookmarks", c.GetBookmarks)
+		H(withPlayer, "createBookmark", c.CreateBookmark)
+		H(withPlayer, "deleteBookmark", c.DeleteBookmark)
 		H(withPlayer, "getPlayQueue", c.GetPlayQueue)
 		H(withPlayer, "savePlayQueue", c.SavePlayQueue)
 	})
diff --git a/server/subsonic/bookmarks.go b/server/subsonic/bookmarks.go
index 4fc24155d..1c1b54dde 100644
--- a/server/subsonic/bookmarks.go
+++ b/server/subsonic/bookmarks.go
@@ -18,6 +18,66 @@ func NewBookmarksController(ds model.DataStore) *BookmarksController {
 	return &BookmarksController{ds: ds}
 }
 
+func (c *BookmarksController) GetBookmarks(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
+	user, _ := request.UserFrom(r.Context())
+
+	repo := c.ds.PlayQueue(r.Context())
+	bmks, err := repo.GetBookmarks(user.ID)
+	if err != nil {
+		return nil, NewError(responses.ErrorGeneric, "Internal Error")
+	}
+
+	response := NewResponse()
+	response.Bookmarks = &responses.Bookmarks{}
+	for _, bmk := range bmks {
+		b := responses.Bookmark{
+			Entry:    []responses.Child{ChildFromMediaFile(r.Context(), bmk.Item)},
+			Position: bmk.Position,
+			Username: user.UserName,
+			Comment:  bmk.Comment,
+			Created:  bmk.CreatedAt,
+			Changed:  bmk.UpdatedAt,
+		}
+		response.Bookmarks.Bookmark = append(response.Bookmarks.Bookmark, b)
+	}
+	return response, nil
+}
+
+func (c *BookmarksController) CreateBookmark(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
+	id, err := RequiredParamString(r, "id", "id parameter required")
+	if err != nil {
+		return nil, err
+	}
+
+	comment := utils.ParamString(r, "comment")
+	position := utils.ParamInt64(r, "position", 0)
+
+	user, _ := request.UserFrom(r.Context())
+
+	repo := c.ds.PlayQueue(r.Context())
+	err = repo.AddBookmark(user.ID, id, comment, position)
+	if err != nil {
+		return nil, NewError(responses.ErrorGeneric, "Internal Error")
+	}
+	return NewResponse(), nil
+}
+
+func (c *BookmarksController) DeleteBookmark(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
+	id, err := RequiredParamString(r, "id", "id parameter required")
+	if err != nil {
+		return nil, err
+	}
+
+	user, _ := request.UserFrom(r.Context())
+
+	repo := c.ds.PlayQueue(r.Context())
+	err = repo.DeleteBookmark(user.ID, id)
+	if err != nil {
+		return nil, NewError(responses.ErrorGeneric, "Internal Error")
+	}
+	return NewResponse(), nil
+}
+
 func (c *BookmarksController) GetPlayQueue(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
 	user, _ := request.UserFrom(r.Context())
 
@@ -31,7 +91,7 @@ func (c *BookmarksController) GetPlayQueue(w http.ResponseWriter, r *http.Reques
 	response.PlayQueue = &responses.PlayQueue{
 		Entry:     ChildrenFromMediaFiles(r.Context(), pq.Items),
 		Current:   pq.Current,
-		Position:  int64(pq.Position),
+		Position:  pq.Position,
 		Username:  user.UserName,
 		Changed:   &pq.UpdatedAt,
 		ChangedBy: pq.ChangedBy,