diff --git a/src/database/entities/channel.rs b/src/database/entities/channel.rs
index 1f66d5199e0eb024280193377b4929557c817a50..37736dc54656482da49f38d3ec5b552c0a7e2199 100644
--- a/src/database/entities/channel.rs
+++ b/src/database/entities/channel.rs
@@ -1,4 +1,6 @@
 use serde::{Deserialize, Serialize};
+use crate::{database::get_collection, util::result::{Error, Result}};
+use mongodb::bson::to_document;
 
 /*#[derive(Serialize, Deserialize, Debug, Clone)]
 pub struct LastMessage {
@@ -33,6 +35,11 @@ pub struct Channel {
 #[derive(Serialize, Deserialize, Debug)]
 #[serde(tag = "type")]
 pub enum Channel {
+    SavedMessages {
+        #[serde(rename = "_id")]
+        id: String,
+        user: String
+    },
     DirectMessage {
         #[serde(rename = "_id")]
         id: String,
@@ -48,3 +55,18 @@ pub enum Channel {
         recipients: Vec<String>,
     }
 }
+
+impl Channel {
+    pub async fn save(&self) -> Result<()> {
+        get_collection("channels")
+            .insert_one(
+                to_document(&self)
+                    .map_err(|_| Error::DatabaseError { operation: "to_bson", with: "channel" })?,
+                None
+            )
+            .await
+            .map_err(|_| Error::DatabaseError { operation: "insert_one", with: "channel" })?;
+        
+        Ok(())
+    }
+}
diff --git a/src/database/entities/user.rs b/src/database/entities/user.rs
index 722c1bf56e095b86e38075522ce6a7bb1f567302..b55a8f88739e6cad9fbdf581cf9d594fc866b736 100644
--- a/src/database/entities/user.rs
+++ b/src/database/entities/user.rs
@@ -7,6 +7,7 @@ use rocket::request::{self, FromRequest, Outcome, Request};
 
 #[derive(Serialize, Deserialize, Debug)]
 pub struct Relationship {
+    #[serde(rename = "_id")]
     pub id: String,
     pub status: u8,
 }
diff --git a/src/database/guards/reference.rs b/src/database/guards/reference.rs
index 1f9a36ec0105cce6d47179cb5c2d520aa819064d..a4282a1287878f52848f3135ecb1749c916538f7 100644
--- a/src/database/guards/reference.rs
+++ b/src/database/guards/reference.rs
@@ -10,7 +10,7 @@ use validator::Validate;
 #[derive(Validate, Serialize, Deserialize)]
 pub struct Ref {
     #[validate(length(min = 26, max = 26))]
-    id: String,
+    pub id: String,
 }
 
 impl Ref {
diff --git a/src/database/permissions/mod.rs b/src/database/permissions/mod.rs
index 3b0f4382561fc43f90f00d8dc043fadef14bea31..899aea7b62f1b31b9f97c81da4555e44bc9b1528 100644
--- a/src/database/permissions/mod.rs
+++ b/src/database/permissions/mod.rs
@@ -18,8 +18,8 @@ bitfield! {
     pub get_invite, _: 29;
 }
 
-impl_op_ex!(+ |a: &UserPermission, b: &UserPermission| -> u32 { *a + *b });
-impl_op_ex!(+ |a: &u32, b: &UserPermission| -> u32 { *a + *b });
+impl_op_ex!(+ |a: &UserPermission, b: &UserPermission| -> u32 { *a as u32 | *b as u32 });
+impl_op_ex_commutative!(+ |a: &u32, b: &UserPermission| -> u32 { *a | *b as u32 });
 
 pub async fn temp_calc_perm(_user: &User, _target: &User) -> UserPermissions<[u32; 1]> {
     // if friends; Access + Message + Invite
diff --git a/src/routes/users/fetch_dms.rs b/src/routes/users/fetch_dms.rs
index beeb5e75a988c86a6894b108deced83a35e6d6ff..2eda25e263ef027c81f2af7450a3f72fb454852b 100644
--- a/src/routes/users/fetch_dms.rs
+++ b/src/routes/users/fetch_dms.rs
@@ -26,13 +26,10 @@ pub async fn req(user: User) -> Result<JsonValue> {
         .await
         .map_err(|_| Error::DatabaseError { operation: "find", with: "channels" })?;
     
-    let mut channels: Vec<Channel> = vec![];
+    let mut channels = vec![];
     while let Some(result) = cursor.next().await {
         if let Ok(doc) = result {
-            channels.push(
-                from_bson(Bson::Document(doc))
-                    .map_err(|_| Error::DatabaseError { operation: "from_bson", with: "channel" })?
-            );
+            channels.push(doc);
         }
     }
 
diff --git a/src/routes/users/mod.rs b/src/routes/users/mod.rs
index 7b92a3f98fa30cc71ba22b97960aaf57ea205c0e..fd5b017e53a9ce1de27011dfaeb35beb0eb8df2f 100644
--- a/src/routes/users/mod.rs
+++ b/src/routes/users/mod.rs
@@ -2,10 +2,12 @@ use rocket::Route;
 
 mod fetch_user;
 mod fetch_dms;
+mod open_dm;
 
 pub fn routes() -> Vec<Route> {
     routes! [
         fetch_user::req,
-        fetch_dms::req
+        fetch_dms::req,
+        open_dm::req,
     ]
 }
diff --git a/src/routes/users/open_dm.rs b/src/routes/users/open_dm.rs
new file mode 100644
index 0000000000000000000000000000000000000000..32f7496fcef22c9f00e5043b75f051d8d7bfd99a
--- /dev/null
+++ b/src/routes/users/open_dm.rs
@@ -0,0 +1,53 @@
+use crate::database::entities::{Channel, User};
+use crate::database::guards::reference::Ref;
+use crate::util::result::{Error, Result};
+use crate::database::get_collection;
+use rocket_contrib::json::JsonValue;
+use mongodb::bson::doc;
+use ulid::Ulid;
+
+#[get("/<target>/dm")]
+pub async fn req(user: User, target: Ref) -> Result<JsonValue> {
+    let query = if user.id == target.id {
+        doc! {
+            "type": "SavedMessages",
+            "user": &user.id
+        }
+    } else {
+        doc! {
+            "type": "DirectMessage",
+            "recipients": {
+                "$all": [ &user.id, &target.id ]
+            }
+        }
+    };
+
+    let existing_channel = get_collection("channels")
+        .find_one(query, None)
+        .await
+        .map_err(|_| Error::DatabaseError { operation: "find_one", with: "channel" })?;
+
+    if let Some(doc) = existing_channel {
+        Ok(json!(doc))
+    } else {
+        let id = Ulid::new().to_string();
+        let channel = if user.id == target.id {
+            Channel::SavedMessages {
+                id,
+                user: user.id
+            }
+        } else {
+            Channel::DirectMessage {
+                id,
+                active: false,
+                recipients: vec! [
+                    user.id,
+                    target.id
+                ]
+            }
+        };
+
+        channel.save().await?;
+        Ok(json!(channel))
+    }
+}