diff --git a/neveko-auth/src/controller.rs b/neveko-auth/src/controller.rs
index f52e013..350b4a3 100644
--- a/neveko-auth/src/controller.rs
+++ b/neveko-auth/src/controller.rs
@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 use rocket::{
     get,
     http::Status,
diff --git a/neveko-contact/src/controller.rs b/neveko-contact/src/controller.rs
index 4323688..7f6eb13 100644
--- a/neveko-contact/src/controller.rs
+++ b/neveko-contact/src/controller.rs
@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 use rocket::{
     get,
     http::Status,
diff --git a/neveko-core/src/order.rs b/neveko-core/src/order.rs
index cf5bf43..30bbc3e 100644
--- a/neveko-core/src/order.rs
+++ b/neveko-core/src/order.rs
@@ -5,15 +5,11 @@ use crate::{
     db,
     gpg,
     i2p,
-
     models::*,
     monero,
     order,
     product,
-    reqres::{
-        self,
-        FinalizeOrderResponse,
-    },
+    reqres,
     utils,
 };
 use log::{
@@ -24,7 +20,7 @@ use log::{
 use rocket::serde::json::Json;
 
 pub enum StatusType {
-    _Cancelled,
+    Cancelled,
     Delivered,
     MultisigMissing,
     MulitsigComplete,
@@ -34,7 +30,7 @@ pub enum StatusType {
 impl StatusType {
     pub fn value(&self) -> String {
         match *self {
-            StatusType::_Cancelled => String::from("Cancelled"),
+            StatusType::Cancelled => String::from("Cancelled"),
             StatusType::Delivered => String::from("Delivered"),
             StatusType::MultisigMissing => String::from("MultisigMissing"),
             StatusType::MulitsigComplete => String::from("MulitsigComplete"),
@@ -163,7 +159,10 @@ pub fn find_all_backup() -> Vec<Order> {
     let mut orders: Vec<Order> = Vec::new();
     for o in i_v {
         let order: Order = find(&o);
-        if order.orid != utils::empty_string() {
+        let visible = order.orid != utils::empty_string()
+            && order.status != order::StatusType::Delivered.value()
+            && order.status != order::StatusType::Cancelled.value();
+        if visible {
             orders.push(order);
         }
     }
@@ -256,6 +255,39 @@ pub async fn secure_retrieval(orid: &String, signature: &String) -> Order {
     m_order
 }
 
+/// In order for the order (...ha) to only be cancelled by the customer
+///
+/// they must sign the order id with their NEVEKO wallet instance.
+pub async fn cancel_order(orid: &String, signature: &String) -> Order {
+    info!("cancel order {}", orid);
+    // get customer address for NEVEKO NOT order wallet
+    let mut m_order: Order = find(&orid);
+    let mut xmr_address: String = String::new();
+    let a_customers: Vec<Contact> = contact::find_all();
+    for customer in a_customers {
+        if customer.i2p_address == m_order.cid {
+            xmr_address = customer.xmr_address;
+            break;
+        }
+    }
+    // send address, orid and signature to verify()
+    let id: String = String::from(&m_order.orid);
+    let sig: String = String::from(signature);
+    let wallet_password =
+        std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
+    let wallet_name = String::from(crate::APP_NAME);
+    monero::open_wallet(&wallet_name, &wallet_password).await;
+    let is_valid_signature = monero::verify(xmr_address, id, sig).await;
+    monero::close_wallet(&wallet_name, &wallet_password).await;
+    if !is_valid_signature {
+        return Default::default();
+    }
+    // update the order status and send to customer
+    m_order.status = order::StatusType::Cancelled.value();
+    order::modify(Json(m_order));
+    order::find(&orid)
+}
+
 /// Check for import multisig info, validate block time and that the
 ///
 /// order wallet has been funded properly. Update the order to multisig complete
@@ -375,7 +407,7 @@ pub async fn upload_delivery_info(
     if nasr_order.is_err() {
         return Default::default();
     }
-    FinalizeOrderResponse {
+    reqres::FinalizeOrderResponse {
         delivery_info: delivery_info.to_vec(),
         orid: String::from(orid),
         vendor_update_success: false,
@@ -383,14 +415,13 @@ pub async fn upload_delivery_info(
 }
 
 /// Vendor will very txset submission and then update the order to `Delivered`
-/// 
+///
 /// status type. Then customer will update the status on the neveko instanced
-/// 
+///
 /// upon a `vendor_update_success: true`  response
 pub async fn finalize_order(orid: &String) -> reqres::FinalizeOrderResponse {
     info!("finalizing order: {}", orid);
 
-
     reqres::FinalizeOrderResponse {
         ..Default::default()
     }
@@ -433,7 +464,7 @@ pub async fn transmit_ship_request(
     contact: &String,
     jwp: &String,
     orid: &String,
-) -> Result<FinalizeOrderResponse, Box<dyn Error>> {
+) -> Result<reqres::FinalizeOrderResponse, Box<dyn Error>> {
     info!("executing transmit_ship_request");
     let host = utils::get_i2p_http_proxy();
     let proxy = reqwest::Proxy::http(&host)?;
@@ -445,7 +476,7 @@ pub async fn transmit_ship_request(
         .await
     {
         Ok(response) => {
-            let res = response.json::<FinalizeOrderResponse>().await;
+            let res = response.json::<reqres::FinalizeOrderResponse>().await;
             debug!("ship request response: {:?}", res);
             match res {
                 Ok(r) => Ok(r),
@@ -520,6 +551,28 @@ pub async fn trigger_ship_request(contact: &String, jwp: &String, orid: &String)
     unwrap_order
 }
 
+/// A post-decomposition trigger for the cancel request so that the logic
+///
+/// can be executed from the gui.
+pub async fn trigger_cancel_request(contact: &String, jwp: &String, orid: &String) -> Order {
+    info!("executing trigger_cancel_request");
+    let data = String::from(orid);
+    let wallet_password =
+        std::env::var(crate::MONERO_WALLET_PASSWORD).unwrap_or(String::from("password"));
+    monero::open_wallet(&String::from(crate::APP_NAME), &wallet_password).await;
+    let pre_sign = monero::sign(data).await;
+    monero::close_wallet(&String::from(crate::APP_NAME), &wallet_password).await;
+    let order = transmit_cancel_request(contact, jwp, orid, &pre_sign.result.signature).await;
+    // cache order request to db
+    if order.is_err() {
+        log::error!("failed to trigger cancel request");
+        return Default::default();
+    }
+    let unwrap_order: Order = order.unwrap();
+    backup(&unwrap_order);
+    unwrap_order
+}
+
 /// Decomposition trigger for the shipping request
 pub async fn d_trigger_ship_request(contact: &String, orid: &String) -> Order {
     // ugh, sorry seems we need to get jwp for vendor from fts cache
@@ -544,6 +597,66 @@ pub async fn d_trigger_ship_request(contact: &String, orid: &String) -> Order {
     trigger
 }
 
+/// Executes POST /order/cancel/orid/signature
+///
+/// cancelling the order on the vendor side.
+///
+/// Customer needs to verify the response and update their lmdb.
+///
+/// see `cancel_order`
+pub async fn transmit_cancel_request(
+    contact: &String,
+    jwp: &String,
+    orid: &String,
+    signature: &String,
+) -> Result<Order, Box<dyn Error>> {
+    info!("executing transmit_cancel_request");
+    let host = utils::get_i2p_http_proxy();
+    let proxy = reqwest::Proxy::http(&host)?;
+    let client = reqwest::Client::builder().proxy(proxy).build();
+    match client?
+        .post(format!(
+            "http://{}/market/order/cancel/{}/{}",
+            contact, orid, signature
+        ))
+        .header("proof", jwp)
+        .send()
+        .await
+    {
+        Ok(response) => {
+            let res = response.json::<Order>().await;
+            debug!("cancel order response: {:?}", res);
+            match res {
+                Ok(r) => Ok(r),
+                _ => Ok(Default::default()),
+            }
+        }
+        Err(e) => {
+            error!("failed to cancel order due to: {:?}", e);
+            Ok(Default::default())
+        }
+    }
+}
+
+/// Decomposition trigger for the shipping request
+pub async fn d_trigger_cancel_request(contact: &String, orid: &String) -> Order {
+    // ugh, sorry seems we need to get jwp for vendor from fts cache
+    // get jwp from db
+    let s = db::Interface::async_open().await;
+    let k = format!("{}-{}", crate::FTS_JWP_DB_KEY, &contact);
+    let jwp = db::Interface::async_read(&s.env, &s.handle, &k).await;
+    info!("executing d_trigger_cancel_request");
+    // request cancel if the order status is not MultisigComplete
+    let order: Order = order::find(&orid);
+    if order.status != order::StatusType::MulitsigComplete.value() {
+        let trigger = trigger_cancel_request(contact, &jwp, orid).await;
+        if trigger.status == order::StatusType::Cancelled.value() {
+            return trigger;
+        }
+    }
+    Default::default()
+}
+
 pub async fn init_mediator_wallet(orid: &String) {
     let password = utils::empty_string();
     let m_wallet = monero::create_wallet(orid, &password).await;
diff --git a/neveko-gui/src/apps/market.rs b/neveko-gui/src/apps/market.rs
index d3377df..6536135 100644
--- a/neveko-gui/src/apps/market.rs
+++ b/neveko-gui/src/apps/market.rs
@@ -113,6 +113,8 @@ pub struct MarketApp {
     submit_order_rx: Receiver<models::Order>,
     _submit_txset_tx: Sender<bool>,
     _submit_txset_rx: Receiver<bool>,
+    cancel_request_tx: Sender<models::Order>,
+    cancel_request_rx: Receiver<models::Order>,
     // ship_request_tx: Sender<models::Order>,
     // ship_request_rx: Receiver<models::Order>,
     s_contact: models::Contact,
@@ -137,6 +139,7 @@ impl Default for MarketApp {
         let (get_vendor_product_tx, get_vendor_product_rx) = std::sync::mpsc::channel();
         let (submit_order_tx, submit_order_rx) = std::sync::mpsc::channel();
         // let (ship_request_tx, ship_request_rx) = std::sync::mpsc::channel();
+        let (cancel_request_tx, cancel_request_rx) = std::sync::mpsc::channel();
         let (our_prepare_info_tx, our_prepare_info_rx) = std::sync::mpsc::channel();
         let (our_make_info_tx, our_make_info_rx) = std::sync::mpsc::channel();
         let (order_xmr_address_tx, order_xmr_address_rx) = std::sync::mpsc::channel();
@@ -208,6 +211,8 @@ impl Default for MarketApp {
             _refresh_on_delete_product_rx,
             s_contact: Default::default(),
             s_order: Default::default(),
+            cancel_request_rx,
+            cancel_request_tx,
             // ship_request_rx,
             // ship_request_tx,
             submit_order_rx,
@@ -312,7 +317,7 @@ impl eframe::App for MarketApp {
 
         // TODO(c2m): automated trigger for nasr worked successfully
         //            doesn't seem like this is really needed anymore?
-        
+
         // if let Ok(shipped) = self.ship_request_rx.try_recv() {
         //     if shipped.status != order::StatusType::Shipped.value() {
         //         log::error!("failure to obtain shipment please contact vendor")
@@ -320,6 +325,13 @@ impl eframe::App for MarketApp {
         //     self.is_loading = false;
         // }
 
+        if let Ok(cancelled) = self.cancel_request_rx.try_recv() {
+            if cancelled.status != order::StatusType::Cancelled.value() {
+                log::error!("failure to cancel shipment please contact vendor")
+            }
+            self.is_loading = false;
+        }
+
         // Vendor status window
         //-----------------------------------------------------------------------------------
         let mut is_showing_vendor_status = self.is_showing_vendor_status;
@@ -689,11 +701,11 @@ impl eframe::App for MarketApp {
                             // async trigger for signing and submitted the txset
                             // do something
                             release_txset(
-                                utils::empty_string(), 
+                                utils::empty_string(),
                                 utils::empty_string(),
                                 ctx.clone(),
                                 utils::empty_string(),
-                                self._submit_txset_tx.clone()
+                                self._submit_txset_tx.clone(),
                             );
                         }
                         if ui.button("Check").clicked() {
@@ -833,12 +845,14 @@ impl eframe::App for MarketApp {
                                     if ui.button("DINFO").clicked() {
                                         let e_info: String = utils::search_gui_db(
                                             String::from(neveko_core::DELIVERY_INFO_DB_KEY),
-                                            String::from(&o.orid)
+                                            String::from(&o.orid),
                                         );
-                                        let bytes = hex::decode(e_info.into_bytes()).unwrap_or(Vec::new());
+                                        let bytes =
+                                            hex::decode(e_info.into_bytes()).unwrap_or(Vec::new());
                                         let d_bytes = gpg::decrypt(&String::from(&o.orid), &bytes);
-                                        let dinfo: String = String::from_utf8(d_bytes.unwrap_or(Vec::new()))
-                                            .unwrap_or(utils::empty_string());
+                                        let dinfo: String =
+                                            String::from_utf8(d_bytes.unwrap_or(Vec::new()))
+                                                .unwrap_or(utils::empty_string());
                                         self.decrypted_delivery_info = dinfo;
                                         self.is_showing_decrypted_delivery_info = true;
                                     }
@@ -847,7 +861,18 @@ impl eframe::App for MarketApp {
                                     ui.style_mut().wrap = Some(false);
                                     ui.horizontal(|ui| {
                                         if ui.button("Cancel").clicked() {
-                                            // TODO(c2m): Cancel order logic
+                                            let vendor_prefix = String::from(crate::GUI_OVL_DB_KEY);
+                                            let vendor = utils::search_gui_db(
+                                                vendor_prefix,
+                                                self.m_order.orid.clone(),
+                                            );
+                                            self.is_loading = true;
+                                            cancel_order_req(
+                                                self.cancel_request_tx.clone(),
+                                                ctx.clone(),
+                                                &self.m_order.orid,
+                                                &vendor,
+                                            )
                                         }
                                     });
                                 });
@@ -1704,7 +1729,6 @@ fn send_prepare_info_req(
         );
         // Request mediator and vendor while we're at it
         // Will coordinating send this on make requests next
-
         let s = db::Interface::async_open().await;
         let m_msig_key = format!(
             "{}-{}-{}",
@@ -2217,7 +2241,6 @@ fn send_import_info_req(tx: Sender<String>, ctx: egui::Context, orid: &String, v
     ctx.request_repaint();
 }
 
-
 // TODO(c2m): do we need a manual trigger for the shipping request?
 
 // fn shipping_req(
@@ -2239,6 +2262,23 @@ fn send_import_info_req(tx: Sender<String>, ctx: egui::Context, orid: &String, v
 // }
 // End Async fn requests
 
+fn cancel_order_req(
+    tx: Sender<models::Order>,
+    ctx: egui::Context,
+    orid: &String,
+    contact: &String,
+) {
+    let ship_orid = String::from(orid);
+    let vendor_i2p = String::from(contact);
+    tokio::spawn(async move {
+        log::info!("cancel order req: {}", ship_orid);
+        let order = order::d_trigger_cancel_request(&vendor_i2p, &ship_orid).await;
+        let _ = tx.send(order);
+        ctx.request_repaint();
+    });
+}
+// End Async fn requests
+
 fn validate_msig_step(
     mediator: &String,
     orid: &String,
@@ -2263,7 +2303,7 @@ fn release_txset(
     tx: Sender<bool>,
 ) {
     tokio::spawn(async move {
-        log::info!("async release txset"); 
+        log::info!("async release txset");
         let lookup = order::find(&orid);
         let submit = order::sign_and_submit_multisig(&orid, &lookup.vend_msig_txset).await;
         if submit.result.tx_hash_list.is_empty() {
@@ -2271,7 +2311,7 @@ fn release_txset(
             let _ = tx.send(false);
             return;
         }
-        // TODO(next commit): we need to build an API that tells the vendor
+        // TODO(c2m): we need to build an API that tells the vendor
         //                    to verify the txset was submitted successfully
         //                    return boolean.
 
@@ -2280,4 +2320,4 @@ fn release_txset(
         ctx.request_repaint();
         todo!()
     });
-}
\ No newline at end of file
+}
diff --git a/neveko-market/src/controller.rs b/neveko-market/src/controller.rs
index 5b6584f..566cd3a 100644
--- a/neveko-market/src/controller.rs
+++ b/neveko-market/src/controller.rs
@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 use rocket::{
     get,
     http::Status,
diff --git a/neveko-message/src/controller.rs b/neveko-message/src/controller.rs
index 9c82e6c..355bb4b 100644
--- a/neveko-message/src/controller.rs
+++ b/neveko-message/src/controller.rs
@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 use rocket::{
     get,
     http::Status,
diff --git a/src/controller.rs b/src/controller.rs
index 8d4deae..79fa4c4 100644
--- a/src/controller.rs
+++ b/src/controller.rs
@@ -1,3 +1,5 @@
+#![allow(non_snake_case)]
+
 use rocket::{
     catch,
     get,
@@ -219,6 +221,24 @@ pub async fn trigger_nasr(
     Custom(Status::Ok, Json(order))
 }
 
+/// Customer cancel order logic. Must send `signature`
+///
+/// which is the order id signed by the NEVEKO wallet.
+///
+/// Protected: true
+#[post("/order/cancel/<orid>/<signature>")]
+pub async fn cancel_order(
+    orid: String,
+    signature: String,
+    _jwp: proof::PaymentProof,
+) -> Custom<Json<models::Order>> {
+    let m_order = order::cancel_order(&orid, &signature).await;
+    if m_order.cid == utils::empty_string() {
+        return Custom(Status::BadRequest, Json(Default::default()));
+    }
+    Custom(Status::Created, Json(m_order))
+}
+
 /// Create a dispute (customer)
 #[post("/create", data = "<dispute>")]
 pub async fn create_dispute(