diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex
index ce4826b23..9ebfd5cb0 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Notification do
   use Ecto.Schema
   alias Pleroma.{User, Activity, Notification, Repo}
   alias Pleroma.Web.CommonAPI.Utils
-  alias Pleroma.Web.ThreadMute
+  alias Pleroma.Web.CommonAPI
   import Ecto.Query
 
   schema "notifications" do
@@ -113,7 +113,7 @@ def create_notifications(_), do: {:ok, []}
   # TODO move to sql, too.
   def create_notification(%Activity{} = activity, %User{} = user) do
     unless User.blocks?(user, %{ap_id: activity.data["actor"]}) or
-             ThreadMute.muted?(user, activity) or user.ap_id == activity.data["actor"] or
+             CommonAPI.thread_muted?(user, activity) or user.ap_id == activity.data["actor"] or
              (activity.data["type"] == "Follow" and
                 Enum.any?(Notification.for_user(user), fn notif ->
                   notif.activity.data["type"] == "Follow" and
diff --git a/lib/pleroma/thread_mute.ex b/lib/pleroma/thread_mute.ex
new file mode 100644
index 000000000..0b577113d
--- /dev/null
+++ b/lib/pleroma/thread_mute.ex
@@ -0,0 +1,45 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.ThreadMute do
+  use Ecto.Schema
+  alias Pleroma.{Repo, User, ThreadMute}
+  require Ecto.Query
+
+  schema "thread_mutes" do
+    belongs_to(:user, User, type: Pleroma.FlakeId)
+    field(:context, :string)
+  end
+
+  def changeset(mute, params \\ %{}) do
+    mute
+    |> Ecto.Changeset.cast(params, [:user_id, :context])
+    |> Ecto.Changeset.foreign_key_constraint(:user_id)
+    |> Ecto.Changeset.unique_constraint(:user_id, name: :unique_index)
+  end
+
+  def query(user_id, context) do
+    user_id = Pleroma.FlakeId.from_string(user_id)
+
+    ThreadMute
+    |> Ecto.Query.where(user_id: ^user_id)
+    |> Ecto.Query.where(context: ^context)
+  end
+
+  def add_mute(user_id, context) do
+    %ThreadMute{}
+    |> changeset(%{user_id: user_id, context: context})
+    |> Repo.insert()
+  end
+
+  def remove_mute(user_id, context) do
+    query(user_id, context)
+    |> Repo.delete_all()
+  end
+
+  def check_muted(user_id, context) do
+    query(user_id, context)
+    |> Repo.all()
+  end
+end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 7084da6de..7782c64dd 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.CommonAPI do
-  alias Pleroma.{User, Repo, Activity, Object}
+  alias Pleroma.{User, Repo, Activity, Object, ThreadMute}
   alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Formatter
@@ -216,4 +216,27 @@ def unpin(id_or_ap_id, user) do
         {:error, "Could not unpin"}
     end
   end
+
+  def add_mute(user, activity) do
+    with {:ok, _} <- ThreadMute.add_mute(user.id, activity.data["context"]) do
+      {:ok, activity}
+    else
+      {:error, _} -> {:error, "conversation is already muted"}
+    end
+  end
+
+  def remove_mute(user, activity) do
+    ThreadMute.remove_mute(user.id, activity.data["context"])
+    {:ok, activity}
+  end
+
+  def thread_muted?(%{id: nil} = _user, _activity), do: false
+
+  def thread_muted?(user, activity) do
+    with [] <- ThreadMute.check_muted(user.id, activity.data["context"]) do
+      false
+    else
+      _ -> true
+    end
+  end
 end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
index 073e0a5ea..18fa16b03 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api_controller.ex
@@ -446,7 +446,8 @@ def unbookmark_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
   end
 
   def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    with {:ok, activity} <- Pleroma.Web.ThreadMute.add_mute(user, id) do
+    activity = Activity.get_by_id(id)
+    with {:ok, activity} <- CommonAPI.add_mute(user, activity) do
       conn
       |> put_view(StatusView)
       |> try_render("status.json", %{activity: activity, for: user, as: :activity})
@@ -459,7 +460,8 @@ def mute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
   end
 
   def unmute_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    with {:ok, activity} <- Pleroma.Web.ThreadMute.remove_mute(user, id) do
+    activity = Activity.get_by_id(id)
+    with {:ok, activity} <- CommonAPI.remove_mute(user, activity) do
       conn
       |> put_view(StatusView)
       |> try_render("status.json", %{activity: activity, for: user, as: :activity})
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index d6176a68a..368b79ea7 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
   alias Pleroma.HTML
   alias Pleroma.Repo
   alias Pleroma.User
+  alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.CommonAPI.Utils
   alias Pleroma.Web.MediaProxy
   alias Pleroma.Web.MastodonAPI.AccountView
@@ -160,7 +161,7 @@ def render("status.json", %{activity: %{data: %{"object" => object}} = activity}
       reblogged: present?(repeated),
       favourited: present?(favorited),
       bookmarked: present?(bookmarked),
-      muted: Pleroma.Web.ThreadMute.muted?(user, activity),
+      muted: CommonAPI.thread_muted?(user, activity),
       pinned: pinned?(activity, user),
       sensitive: sensitive,
       spoiler_text: object["summary"] || "",
diff --git a/lib/pleroma/web/thread_mute.ex b/lib/pleroma/web/thread_mute.ex
deleted file mode 100644
index 695ea2512..000000000
--- a/lib/pleroma/web/thread_mute.ex
+++ /dev/null
@@ -1,62 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ThreadMute do
-  use Ecto.Schema
-  alias Pleroma.Web.ThreadMute
-  alias Pleroma.{Activity, Repo, User}
-  require Ecto.Query
-
-  schema "thread_mutes" do
-    belongs_to(:user, User, type: Pleroma.FlakeId)
-    field(:context, :string)
-  end
-
-  def changeset(mute, params \\ %{}) do
-    mute
-    |> Ecto.Changeset.cast(params, [:user_id, :context])
-    |> Ecto.Changeset.foreign_key_constraint(:user_id)
-    |> Ecto.Changeset.unique_constraint(:user_id, name: :unique_index)
-  end
-
-  def query(user, context) do
-    user_id = Pleroma.FlakeId.from_string(user.id)
-
-    ThreadMute
-    |> Ecto.Query.where(user_id: ^user_id)
-    |> Ecto.Query.where(context: ^context)
-  end
-
-  def add_mute(user, id) do
-    activity = Activity.get_by_id(id)
-
-    with changeset <-
-           changeset(%ThreadMute{}, %{user_id: user.id, context: activity.data["context"]}),
-         {:ok, _} <- Repo.insert(changeset) do
-      {:ok, activity}
-    else
-      {:error, _} -> {:error, "conversation is already muted"}
-    end
-  end
-
-  def remove_mute(user, id) do
-    activity = Activity.get_by_id(id)
-
-    query(user, activity.data["context"])
-    |> Repo.delete_all()
-
-    {:ok, activity}
-  end
-
-  def muted?(%{id: nil} = _user, _), do: false
-
-  def muted?(user, activity) do
-    with query <- query(user, activity.data["context"]),
-         [] <- Repo.all(query) do
-      false
-    else
-      _ -> true
-    end
-  end
-end
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index a7d9e6161..d26b6e49c 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -164,4 +164,30 @@ test "should unpin when deleting a status", %{user: user, activity: activity} do
       assert %User{info: %{pinned_activities: []}} = user
     end
   end
+
+  describe "mute tests" do
+    setup do
+      user = insert(:user)
+
+      activity = insert(:note_activity)
+
+      [user: user, activity: activity]
+    end
+
+    test "add mute", %{user: user, activity: activity} do
+      {:ok, _} = CommonAPI.add_mute(user, activity)
+      assert CommonAPI.thread_muted?(user, activity)
+    end
+
+    test "remove mute", %{user: user, activity: activity} do
+      CommonAPI.add_mute(user, activity)
+      {:ok, _} = CommonAPI.remove_mute(user, activity)
+      refute CommonAPI.thread_muted?(user, activity)
+    end
+
+    test "check that mutes can't be duplicate", %{user: user, activity: activity} do
+      CommonAPI.add_mute(user, activity)
+      {:error, _} = CommonAPI.add_mute(user, activity)
+    end
+  end
 end
diff --git a/test/web/mastodon_api/mastodon_api_controller_test.exs b/test/web/mastodon_api/mastodon_api_controller_test.exs
index f8da86004..f7c059663 100644
--- a/test/web/mastodon_api/mastodon_api_controller_test.exs
+++ b/test/web/mastodon_api/mastodon_api_controller_test.exs
@@ -1749,4 +1749,37 @@ test "bookmarks" do
 
     assert [json_response(response2, 200)] == json_response(bookmarks, 200)
   end
+
+  describe "conversation muting" do
+    setup do
+
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
+
+      [user: user, activity: activity]
+    end
+
+    test "mute conversation", %{conn: conn, user: user, activity: activity} do
+      id_str = to_string(activity.id)
+
+      assert %{"id" => ^id_str, "muted" => true} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{activity.id}/mute")
+               |> json_response(200)
+    end
+
+    test "unmute conversation", %{conn: conn, user: user, activity: activity} do
+      {:ok, _} = CommonAPI.add_mute(user, activity)
+
+      id_str = to_string(activity.id)
+      user = refresh_record(user)
+
+      assert %{"id" => ^id_str, "muted" => false} =
+               conn
+               |> assign(:user, user)
+               |> post("/api/v1/statuses/#{activity.id}/unmute")
+               |> json_response(200)
+    end
+  end
 end
diff --git a/test/web/thread_mute_test.exs b/test/web/thread_mute_test.exs
deleted file mode 100644
index f3a24613c..000000000
--- a/test/web/thread_mute_test.exs
+++ /dev/null
@@ -1,37 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Web.ThreadMuteTest do
-  use Pleroma.DataCase
-  import Pleroma.Web.ThreadMute
-
-  import Pleroma.Factory
-
-  describe "mute tests" do
-    setup do
-      user = insert(:user)
-
-      activity = insert(:note_activity)
-
-      [user: user, activity: activity]
-    end
-
-    test "add mute", %{user: user, activity: activity} do
-      {:ok, _activity} = add_mute(user, activity.id)
-      assert muted?(user, activity)
-    end
-
-    test "remove mute", %{user: user, activity: activity} do
-      add_mute(user, activity.id)
-      {:ok, _activity} = remove_mute(user, activity.id)
-      refute muted?(user, activity)
-    end
-
-    test "check that mutes can't be duplicate", %{user: user, activity: activity} do
-      add_mute(user, activity.id)
-      assert muted?(user, activity)
-      {:error, _} = add_mute(user, activity.id)
-    end
-  end
-end