diff --git a/src/database/channel.rs b/src/database/channel.rs
index be88081674f577f6dae95b7607a1f56777bf9bcd..e60856b83db8af5a69a76dc428392118ec01c232 100644
--- a/src/database/channel.rs
+++ b/src/database/channel.rs
@@ -4,7 +4,10 @@ use serde::{ Deserialize, Serialize };
 pub struct Channel {
     #[serde(rename = "_id")]
     pub id: String,
+    #[serde(rename = "type")]
 	pub channel_type: u8,
+
+	pub last_message: Option<String>,
 	
 	// for Direct Messages
 	pub recipients: Option<Vec<String>>,
diff --git a/src/database/message.rs b/src/database/message.rs
index d65b2118e29611af733a3c2e02db9bf9ceabbd6f..9411b82e88c7993622b5745366a5722284f9d3fc 100644
--- a/src/database/message.rs
+++ b/src/database/message.rs
@@ -1,8 +1,13 @@
-
 use serde::{ Deserialize, Serialize };
+use bson::{ UtcDateTime };
 
 #[derive(Serialize, Deserialize, Debug)]
 pub struct Message {
     #[serde(rename = "_id")]
-    pub id: String,
+	pub id: String,
+	pub channel: String,
+	pub author: String,
+
+	pub content: String,
+	pub edited: Option<UtcDateTime>,
 }
diff --git a/src/guards/channel.rs b/src/guards/channel.rs
index daa277d5ced8aefd760ab31e77571414f47e1c99..fde2b82b7476f7b6a79ad3c83e146107853ab298 100644
--- a/src/guards/channel.rs
+++ b/src/guards/channel.rs
@@ -2,7 +2,7 @@ use rocket::http::{ RawStr };
 use rocket::request::{ FromParam };
 use bson::{ bson, doc, from_bson };
 
-use crate::database;
+use crate::database::{ self, user::User };
 
 use database::channel::Channel;
 use database::message::Message;
diff --git a/src/routes/channel.rs b/src/routes/channel.rs
index 81d3f07437e4255573b61ebe7193a1c9914c0739..66a90f6c7203bc127d132eb1cc3b31cd3efaa713 100644
--- a/src/routes/channel.rs
+++ b/src/routes/channel.rs
@@ -1,8 +1,11 @@
-use crate::database::{ user::User, channel::Channel };
+use crate::database::{ self, user::User, channel::Channel, message::Message };
 
-use rocket_contrib::json::{ JsonValue };
+use bson::{ bson, doc, from_bson, Bson::UtcDatetime };
+use rocket_contrib::json::{ JsonValue, Json };
+use serde::{ Serialize, Deserialize };
 use num_enum::TryFromPrimitive;
-use bson::{ doc };
+use chrono::prelude::*;
+use ulid::Ulid;
 
 #[derive(Debug, TryFromPrimitive)]
 #[repr(usize)]
@@ -46,3 +49,190 @@ pub fn channel(user: User, target: Channel) -> Option<JsonValue> {
 		}
 	))
 }
+
+/// delete channel
+/// or leave group DM
+/// or close DM conversation
+#[delete("/<target>")]
+pub fn delete(user: User, target: Channel) -> Option<JsonValue> {
+	if !has_permission(&user, &target) {
+		return None
+	}
+
+	let col = database::get_collection("channels");
+	Some(match target.channel_type {
+		0 => {
+			col.update_one(
+				doc! { "_id": target.id },
+				doc! { "$set": { "active": false } },
+				None
+			).expect("Failed to update channel.");
+
+			json!({
+				"success": true
+			})
+		},
+		1 => {
+			// ? TODO: group dm
+
+			json!({
+				"success": true
+			})
+		},
+		2 => {
+			// ? TODO: guild
+
+			json!({
+				"success": true
+			})
+		},
+		_ => 
+			json!({
+				"success": false
+			})
+	})
+}
+
+/// fetch channel messages
+#[get("/<target>/messages")]
+pub fn messages(user: User, target: Channel) -> Option<JsonValue> {
+	if !has_permission(&user, &target) {
+		return None
+	}
+
+	let col = database::get_collection("messages");
+	let result = col.find(
+		doc! { "channel": target.id },
+		None
+	).unwrap();
+
+	let mut messages = Vec::new();
+	for item in result {
+		let message: Message = from_bson(bson::Bson::Document(item.unwrap())).expect("Failed to unwrap message.");
+		messages.push(
+			json!({
+				"id": message.id,
+				"author": message.author,
+				"content": message.content,
+				"edited": if let Some(t) = message.edited { Some(t.timestamp()) } else { None }
+			})
+		);
+	}
+
+	Some(json!(messages))
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct SendMessage {
+	content: String,
+}
+
+/// send a message to a channel
+#[post("/<target>/messages", data = "<message>")]
+pub fn send_message(user: User, target: Channel, message: Json<SendMessage>) -> Option<JsonValue> {
+	if !has_permission(&user, &target) {
+		return None
+	}
+
+	let col = database::get_collection("messages");
+	let id = Ulid::new().to_string();
+	Some(match col.insert_one(
+		doc! {
+			"_id": id.clone(),
+			"channel": target.id,
+			"author": user.id,
+			"content": message.content.clone(),
+		},
+		None
+	) {
+		Ok(_) =>
+			json!({
+				"success": true,
+				"id": id
+			}),
+		Err(_) =>
+			json!({
+				"success": false,
+				"error": "Failed database query."
+			})
+		})
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct EditMessage {
+	content: String,
+}
+
+/// edit a message
+#[patch("/<target>/messages/<message>", data = "<edit>")]
+pub fn edit_message(user: User, target: Channel, message: Message, edit: Json<SendMessage>) -> Option<JsonValue> {
+	if !has_permission(&user, &target) {
+		return None
+	}
+
+	Some(
+		if message.author != user.id {
+			json!({
+				"success": false,
+				"error": "You did not send this message."
+			})
+		} else {
+			let col = database::get_collection("messages");
+
+			match col.update_one(
+				doc! { "_id": message.id },
+				doc! {
+					"$set": {
+						"content": edit.content.clone(),
+						"edited": UtcDatetime(Utc::now())
+					}
+				},
+				None
+			) {
+				Ok(_) =>
+					json!({
+						"success": true
+					}),
+				Err(_) =>
+					json!({
+						"success": false,
+						"error": "Failed to update message."
+					})
+				}
+		}
+	)
+}
+
+/// delete a message
+#[delete("/<target>/messages/<message>")]
+pub fn delete_message(user: User, target: Channel, message: Message) -> Option<JsonValue> {
+	if !has_permission(&user, &target) {
+		return None
+	}
+
+	Some(
+		if message.author != user.id {
+			json!({
+				"success": false,
+				"error": "You did not send this message."
+			})
+		} else {
+			let col = database::get_collection("messages");
+
+			match col.delete_one(
+				doc! { "_id": message.id },
+				None
+			) {
+				Ok(_) =>
+					json!({
+						"success": true
+					}),
+				Err(_) =>
+					json!({
+						"success": false,
+						"error": "Failed to delete message."
+					})
+				}
+		}
+	)
+}
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
index b1890803fdaf8e5654b1ec430fd9dd2f37078709..ef4de3380303e526baaffdb6908e4d297fb93b2c 100644
--- a/src/routes/mod.rs
+++ b/src/routes/mod.rs
@@ -8,5 +8,5 @@ pub fn mount(rocket: Rocket) -> Rocket {
 	rocket
 		.mount("/api/account", routes![ account::create, account::verify_email, account::resend_email, account::login ])
 		.mount("/api/users", routes![ user::me, user::user, user::lookup, user::dms, user::dm, user::get_friends, user::get_friend, user::add_friend, user::remove_friend ])
-		.mount("/api/channels", routes![ channel::channel ])
+		.mount("/api/channels", routes![ channel::channel, channel::delete, channel::messages, channel::send_message, channel::edit_message, channel::delete_message ])
 }