diff --git a/Cargo.lock b/Cargo.lock
index 5a6fcf5686d33fa0c424f2a631b2f89845d348fe..f264925edd66bc75f88942a024458004baf74e6f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2454,7 +2454,7 @@ dependencies = [
 
 [[package]]
 name = "revolt"
-version = "0.3.3-alpha.3"
+version = "0.3.3-alpha.4"
 dependencies = [
  "async-std",
  "async-tungstenite",
diff --git a/Cargo.toml b/Cargo.toml
index 25ced133f8b4797141d861ff9f6344afbf8eca3d..98bfdd263abb0545cc62937a80b9cb38b80e89b1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "revolt"
-version = "0.3.3-alpha.3"
+version = "0.3.3-alpha.4"
 authors = ["Paul Makles <paulmakles@gmail.com>"]
 edition = "2018"
 
diff --git a/src/routes/channels/message_query_stale.rs b/src/routes/channels/message_query_stale.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d2ee19db597ff88333d37a1e31c74b4a7ae5d7b0
--- /dev/null
+++ b/src/routes/channels/message_query_stale.rs
@@ -0,0 +1,74 @@
+use crate::database::*;
+use crate::util::result::{Error, Result};
+
+use futures::StreamExt;
+use mongodb::bson::{doc, from_document};
+use rocket_contrib::json::{Json, JsonValue};
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize)]
+pub struct Options {
+    ids: Vec<String>
+}
+
+#[post("/<target>/messages/stale", data = "<data>")]
+pub async fn req(user: User, target: Ref, data: Json<Options>) -> Result<JsonValue> {
+    if data.ids.len() > 150 {
+        return Err(Error::LabelMe);
+    }
+
+    let target = target.fetch_channel().await?;
+
+    let perm = permissions::PermissionCalculator::new(&user)
+        .with_channel(&target)
+        .for_channel()
+        .await?;
+    if !perm.get_view() {
+        Err(Error::LabelMe)?
+    }
+
+    let mut cursor = get_collection("messages")
+        .find(
+            doc! {
+                "_id": {
+                    "$in": &data.ids
+                },
+                "channel": target.id()
+            },
+            None
+        )
+        .await
+        .map_err(|_| Error::DatabaseError {
+            operation: "find",
+            with: "messages",
+        })?;
+
+    let mut updated = vec![];
+    let mut found_ids = vec![];
+    while let Some(result) = cursor.next().await {
+        if let Ok(doc) = result {
+            let msg = from_document::<Message>(doc)
+                .map_err(|_| Error::DatabaseError {
+                    operation: "from_document",
+                    with: "message",
+                })?;
+            
+            found_ids.push(msg.id.clone());
+            if msg.edited.is_some() {
+                updated.push(msg);
+            }
+        }
+    }
+
+    let mut deleted = vec![];
+    for id in &data.ids {
+        if found_ids.iter().find(|x| *x == id).is_none() {
+            deleted.push(id);
+        }
+    }
+
+    Ok(json!({
+        "updated": updated,
+        "deleted": deleted
+    }))
+}
diff --git a/src/routes/channels/mod.rs b/src/routes/channels/mod.rs
index ccc138988c4db8ca24426c6ea94532e2bd33d0ba..b8f37fe9f27140d71006abd8da7ba123aafe9ed1 100644
--- a/src/routes/channels/mod.rs
+++ b/src/routes/channels/mod.rs
@@ -9,6 +9,7 @@ mod message_delete;
 mod message_edit;
 mod message_fetch;
 mod message_query;
+mod message_query_stale;
 mod message_send;
 
 pub fn routes() -> Vec<Route> {
@@ -17,6 +18,7 @@ pub fn routes() -> Vec<Route> {
         delete_channel::req,
         message_send::req,
         message_query::req,
+        message_query_stale::req,
         message_fetch::req,
         message_edit::req,
         message_delete::req,
diff --git a/src/routes/root.rs b/src/routes/root.rs
index 126479aadad45399c6082d64fe72488f0e8494fa..70ff4a51909c0a923c975817a32f89b555a6b199 100644
--- a/src/routes/root.rs
+++ b/src/routes/root.rs
@@ -8,7 +8,7 @@ use rocket_contrib::json::JsonValue;
 #[get("/")]
 pub async fn root() -> JsonValue {
     json!({
-        "revolt": "0.3.3-alpha.2",
+        "revolt": "0.3.3-alpha.4",
         "features": {
             "registration": !*DISABLE_REGISTRATION,
             "captcha": {
diff --git a/src/routes/users/find_mutual.rs b/src/routes/users/find_mutual.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e75c07e917d7061ca166b7ece4664062ff69249a
--- /dev/null
+++ b/src/routes/users/find_mutual.rs
@@ -0,0 +1,41 @@
+use crate::database::*;
+use crate::util::result::{Error, Result};
+
+use futures::StreamExt;
+use mongodb::options::FindOptions;
+use mongodb::bson::{Document, doc};
+use rocket_contrib::json::JsonValue;
+
+#[get("/<target>/mutual")]
+pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+    let channels = get_collection("channels")
+        .find(
+            doc! {
+                "$or": [
+                    { "type": "Group" },
+                ],
+                "$and": [
+                    { "recipients": &user.id },
+                    { "recipients": &target.id }
+                ]
+            },
+            FindOptions::builder()
+                .projection(doc! { "_id": 1 })
+                .build()
+        )
+        .await
+        .map_err(|_| Error::DatabaseError {
+            operation: "find",
+            with: "channels",
+        })?
+        .filter_map(async move |s| s.ok())
+        .collect::<Vec<Document>>()
+        .await
+        .into_iter()
+        .filter_map(|x| x.get_str("_id").ok().map(|x| x.to_string()))
+        .collect::<Vec<String>>();
+
+    Ok(json!({
+        "channels": channels
+    }))
+}
diff --git a/src/routes/users/mod.rs b/src/routes/users/mod.rs
index 2a0cd2f3c5362a3895546d4b9f7ad7a621dd8350..163978fdb0deba56f0cfa2fb552405501f88a61b 100644
--- a/src/routes/users/mod.rs
+++ b/src/routes/users/mod.rs
@@ -6,6 +6,7 @@ mod fetch_dms;
 mod fetch_relationship;
 mod fetch_relationships;
 mod fetch_user;
+mod find_mutual;
 mod get_avatar;
 mod get_default_avatar;
 mod open_dm;
@@ -22,6 +23,7 @@ pub fn routes() -> Vec<Route> {
         fetch_dms::req,
         open_dm::req,
         // Relationships
+        find_mutual::req,
         fetch_relationships::req,
         fetch_relationship::req,
         add_friend::req,