Bug: [FEAT] add a macro to derive ToEncryptable trait




diff --git a/crates/api_models/src/customers.rs b/crates/api_models/src/customers.rs
index eb196a72074..4f6411a42cd 100644
--- a/crates/api_models/src/customers.rs
+++ b/crates/api_models/src/customers.rs
@@ -1,12 +1,5 @@
-use common_utils::{
-    crypto, custom_serde,
-    encryption::Encryption,
-    id_type,
-    pii::{self, EmailStrategy},
-    types::{keymanager::ToEncryptable, Description},
-};
-use masking::{ExposeInterface, Secret, SwitchStrategy};
-use rustc_hash::FxHashMap;
+use common_utils::{crypto, custom_serde, id_type, pii, types::Description};
+use masking::Secret;
 use serde::{Deserialize, Serialize};
 use utoipa::ToSchema;
 
@@ -129,85 +122,6 @@ impl CustomerRequest {
     }
 }
 
-pub struct CustomerRequestWithEmail {
-    pub name: Option<Secret<String>>,
-    pub email: Option<pii::Email>,
-    pub phone: Option<Secret<String>>,
-}
-
-pub struct CustomerRequestWithEncryption {
-    pub name: Option<Encryption>,
-    pub phone: Option<Encryption>,
-    pub email: Option<Encryption>,
-}
-
-pub struct EncryptableCustomer {
-    pub name: crypto::OptionalEncryptableName,
-    pub phone: crypto::OptionalEncryptablePhone,
-    pub email: crypto::OptionalEncryptableEmail,
-}
-
-impl ToEncryptable<EncryptableCustomer, Secret<String>, Encryption>
-    for CustomerRequestWithEncryption
-{
-    fn to_encryptable(self) -> FxHashMap<String, Encryption> {
-        let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default());
-        self.name.map(|x| map.insert("name".to_string(), x));
-        self.phone.map(|x| map.insert("phone".to_string(), x));
-        self.email.map(|x| map.insert("email".to_string(), x));
-        map
-    }
-
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, crypto::Encryptable<Secret<String>>>,
-    ) -> common_utils::errors::CustomResult<EncryptableCustomer, common_utils::errors::ParsingError>
-    {
-        Ok(EncryptableCustomer {
-            name: hashmap.remove("name"),
-            phone: hashmap.remove("phone"),
-            email: hashmap.remove("email").map(|email| {
-                let encryptable: crypto::Encryptable<Secret<String, EmailStrategy>> =
-                    crypto::Encryptable::new(
-                        email.clone().into_inner().switch_strategy(),
-                        email.into_encrypted(),
-                    );
-                encryptable
-            }),
-        })
-    }
-}
-
-impl ToEncryptable<EncryptableCustomer, Secret<String>, Secret<String>>
-    for CustomerRequestWithEmail
-{
-    fn to_encryptable(self) -> FxHashMap<String, Secret<String>> {
-        let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default());
-        self.name.map(|x| map.insert("name".to_string(), x));
-        self.phone.map(|x| map.insert("phone".to_string(), x));
-        self.email
-            .map(|x| map.insert("email".to_string(), x.expose().switch_strategy()));
-        map
-    }
-
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, crypto::Encryptable<Secret<String>>>,
-    ) -> common_utils::errors::CustomResult<EncryptableCustomer, common_utils::errors::ParsingError>
-    {
-        Ok(EncryptableCustomer {
-            name: hashmap.remove("name"),
-            email: hashmap.remove("email").map(|email| {
-                let encryptable: crypto::Encryptable<Secret<String, EmailStrategy>> =
-                    crypto::Encryptable::new(
-                        email.clone().into_inner().switch_strategy(),
-                        email.into_encrypted(),
-                    );
-                encryptable
-            }),
-            phone: hashmap.remove("phone"),
-        })
-    }
-}
-
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
 #[derive(Debug, Clone, Serialize, ToSchema)]
 pub struct CustomerResponse {
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index 2e31c0ba258..4efc2e8d960 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -12,13 +12,12 @@ use common_utils::{
     ext_traits::{ConfigExt, Encode, ValueExt},
     hashing::HashedString,
     id_type,
-    pii::{self, Email, EmailStrategy},
-    types::{keymanager::ToEncryptable, MinorUnit, StringMajorUnit},
+    pii::{self, Email},
+    types::{MinorUnit, StringMajorUnit},
 };
 use error_stack::ResultExt;
-use masking::{ExposeInterface, PeekInterface, Secret, SwitchStrategy, WithType};
+use masking::{PeekInterface, Secret, WithType};
 use router_derive::Setter;
-use rustc_hash::FxHashMap;
 use serde::{de, ser::Serializer, Deserialize, Deserializer, Serialize};
 use strum::Display;
 use time::{Date, PrimitiveDateTime};
@@ -3763,54 +3762,6 @@ pub struct EncryptableAddressDetails {
     pub email: crypto::OptionalEncryptableEmail,
 }
 
-impl ToEncryptable<EncryptableAddressDetails, Secret<String>, Secret<String>>
-    for AddressDetailsWithPhone
-{
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, crypto::Encryptable<Secret<String>>>,
-    ) -> common_utils::errors::CustomResult<
-        EncryptableAddressDetails,
-        common_utils::errors::ParsingError,
-    > {
-        Ok(EncryptableAddressDetails {
-            line1: hashmap.remove("line1"),
-            line2: hashmap.remove("line2"),
-            line3: hashmap.remove("line3"),
-            state: hashmap.remove("state"),
-            zip: hashmap.remove("zip"),
-            first_name: hashmap.remove("first_name"),
-            last_name: hashmap.remove("last_name"),
-            phone_number: hashmap.remove("phone_number"),
-            email: hashmap.remove("email").map(|x| {
-                let inner: Secret<String, EmailStrategy> = x.clone().into_inner().switch_strategy();
-                crypto::Encryptable::new(inner, x.into_encrypted())
-            }),
-        })
-    }
-
-    fn to_encryptable(self) -> FxHashMap<String, Secret<String>> {
-        let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default());
-        self.address.map(|address| {
-            address.line1.map(|x| map.insert("line1".to_string(), x));
-            address.line2.map(|x| map.insert("line2".to_string(), x));
-            address.line3.map(|x| map.insert("line3".to_string(), x));
-            address.state.map(|x| map.insert("state".to_string(), x));
-            address.zip.map(|x| map.insert("zip".to_string(), x));
-            address
-                .first_name
-                .map(|x| map.insert("first_name".to_string(), x));
-            address
-                .last_name
-                .map(|x| map.insert("last_name".to_string(), x));
-        });
-        self.email
-            .map(|x| map.insert("email".to_string(), x.expose().switch_strategy()));
-        self.phone_number
-            .map(|x| map.insert("phone_number".to_string(), x));
-        map
-    }
-}
-
 #[derive(Debug, Clone, Default, Eq, PartialEq, ToSchema, serde::Deserialize, serde::Serialize)]
 pub struct PhoneDetails {
     /// The contact number
diff --git a/crates/diesel_models/src/address.rs b/crates/diesel_models/src/address.rs
index a1cfb668716..06b82cb2c20 100644
--- a/crates/diesel_models/src/address.rs
+++ b/crates/diesel_models/src/address.rs
@@ -1,12 +1,5 @@
-use common_utils::{
-    crypto::{self, Encryptable},
-    encryption::Encryption,
-    pii::EmailStrategy,
-    types::keymanager::ToEncryptable,
-};
+use common_utils::{crypto, encryption::Encryption};
 use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};
-use masking::{Secret, SwitchStrategy};
-use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
 use time::PrimitiveDateTime;
 
@@ -74,48 +67,6 @@ pub struct EncryptableAddress {
     pub email: crypto::OptionalEncryptableEmail,
 }
 
-impl ToEncryptable<EncryptableAddress, Secret<String>, Encryption> for Address {
-    fn to_encryptable(self) -> FxHashMap<String, Encryption> {
-        let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default());
-        self.line1.map(|x| map.insert("line1".to_string(), x));
-        self.line2.map(|x| map.insert("line2".to_string(), x));
-        self.line3.map(|x| map.insert("line3".to_string(), x));
-        self.zip.map(|x| map.insert("zip".to_string(), x));
-        self.state.map(|x| map.insert("state".to_string(), x));
-        self.first_name
-            .map(|x| map.insert("first_name".to_string(), x));
-        self.last_name
-            .map(|x| map.insert("last_name".to_string(), x));
-        self.phone_number
-            .map(|x| map.insert("phone_number".to_string(), x));
-        self.email.map(|x| map.insert("email".to_string(), x));
-        map
-    }
-
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, Encryptable<Secret<String>>>,
-    ) -> common_utils::errors::CustomResult<EncryptableAddress, common_utils::errors::ParsingError>
-    {
-        Ok(EncryptableAddress {
-            line1: hashmap.remove("line1"),
-            line2: hashmap.remove("line2"),
-            line3: hashmap.remove("line3"),
-            zip: hashmap.remove("zip"),
-            state: hashmap.remove("state"),
-            first_name: hashmap.remove("first_name"),
-            last_name: hashmap.remove("last_name"),
-            phone_number: hashmap.remove("phone_number"),
-            email: hashmap.remove("email").map(|email| {
-                let encryptable: Encryptable<Secret<String, EmailStrategy>> = Encryptable::new(
-                    email.clone().into_inner().switch_strategy(),
-                    email.into_encrypted(),
-                );
-                encryptable
-            }),
-        })
-    }
-}
-
 #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay, Serialize, Deserialize)]
 #[diesel(table_name = address)]
 pub struct AddressUpdateInternal {
diff --git a/crates/diesel_models/src/events.rs b/crates/diesel_models/src/events.rs
index b6c5efe0fd1..82b2b58f80b 100644
--- a/crates/diesel_models/src/events.rs
+++ b/crates/diesel_models/src/events.rs
@@ -1,11 +1,7 @@
-use common_utils::{
-    crypto::OptionalEncryptableSecretString, custom_serde, encryption::Encryption,
-    types::keymanager::ToEncryptable,
-};
+use common_utils::{custom_serde, encryption::Encryption};
 use diesel::{
     expression::AsExpression, AsChangeset, Identifiable, Insertable, Queryable, Selectable,
 };
-use masking::Secret;
 use serde::{Deserialize, Serialize};
 use time::PrimitiveDateTime;
 
@@ -63,38 +59,6 @@ pub struct Event {
     pub metadata: Option<EventMetadata>,
 }
 
-pub struct EventWithEncryption {
-    pub request: Option<Encryption>,
-    pub response: Option<Encryption>,
-}
-
-pub struct EncryptableEvent {
-    pub request: OptionalEncryptableSecretString,
-    pub response: OptionalEncryptableSecretString,
-}
-
-impl ToEncryptable<EncryptableEvent, Secret<String>, Encryption> for EventWithEncryption {
-    fn to_encryptable(self) -> rustc_hash::FxHashMap<String, Encryption> {
-        let mut map = rustc_hash::FxHashMap::default();
-        self.request.map(|x| map.insert("request".to_string(), x));
-        self.response.map(|x| map.insert("response".to_string(), x));
-        map
-    }
-
-    fn from_encryptable(
-        mut hashmap: rustc_hash::FxHashMap<
-            String,
-            common_utils::crypto::Encryptable<Secret<String>>,
-        >,
-    ) -> common_utils::errors::CustomResult<EncryptableEvent, common_utils::errors::ParsingError>
-    {
-        Ok(EncryptableEvent {
-            request: hashmap.remove("request"),
-            response: hashmap.remove("response"),
-        })
-    }
-}
-
 #[derive(Clone, Debug, Deserialize, Serialize, AsExpression, diesel::FromSqlRow)]
 #[diesel(sql_type = diesel::sql_types::Jsonb)]
 pub enum EventMetadata {
diff --git a/crates/hyperswitch_domain_models/src/customer.rs b/crates/hyperswitch_domain_models/src/customer.rs
index 9f079f1312e..71cb4ebc2f9 100644
--- a/crates/hyperswitch_domain_models/src/customer.rs
+++ b/crates/hyperswitch_domain_models/src/customer.rs
@@ -1,8 +1,8 @@
-use api_models::customers::CustomerRequestWithEncryption;
 #[cfg(all(feature = "v2", feature = "customer_v2"))]
 use common_enums::DeleteStatus;
 use common_utils::{
-    crypto, date_time,
+    crypto::{self, Encryptable},
+    date_time,
     encryption::Encryption,
     errors::{CustomResult, ValidationError},
     id_type, pii,
@@ -13,19 +13,23 @@ use common_utils::{
 };
 use diesel_models::customers::CustomerUpdateInternal;
 use error_stack::ResultExt;
-use masking::{PeekInterface, Secret};
+use masking::{PeekInterface, Secret, SwitchStrategy};
+use rustc_hash::FxHashMap;
 use time::PrimitiveDateTime;
 
 use crate::type_encryption as types;
 
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, router_derive::ToEncryption)]
 pub struct Customer {
     pub customer_id: id_type::CustomerId,
     pub merchant_id: id_type::MerchantId,
-    pub name: crypto::OptionalEncryptableName,
-    pub email: crypto::OptionalEncryptableEmail,
-    pub phone: crypto::OptionalEncryptablePhone,
+    #[encrypt]
+    pub name: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub email: Option<Encryptable<Secret<String, pii::EmailStrategy>>>,
+    #[encrypt]
+    pub phone: Option<Encryptable<Secret<String>>>,
     pub phone_country_code: Option<String>,
     pub description: Option<Description>,
     pub created_at: PrimitiveDateTime,
@@ -39,12 +43,15 @@ pub struct Customer {
 }
 
 #[cfg(all(feature = "v2", feature = "customer_v2"))]
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, router_derive::ToEncryption)]
 pub struct Customer {
     pub merchant_id: id_type::MerchantId,
-    pub name: crypto::OptionalEncryptableName,
-    pub email: crypto::OptionalEncryptableEmail,
-    pub phone: crypto::OptionalEncryptablePhone,
+    #[encrypt]
+    pub name: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub email: Option<Encryptable<Secret<String, pii::EmailStrategy>>>,
+    #[encrypt]
+    pub phone: Option<Encryptable<Secret<String>>>,
     pub phone_country_code: Option<String>,
     pub description: Option<Description>,
     pub created_at: PrimitiveDateTime,
@@ -98,8 +105,8 @@ impl super::behaviour::Conversion for Customer {
         let decrypted = types::crypto_operation(
             state,
             common_utils::type_name!(Self::DstType),
-            types::CryptoOperation::BatchDecrypt(CustomerRequestWithEncryption::to_encryptable(
-                CustomerRequestWithEncryption {
+            types::CryptoOperation::BatchDecrypt(EncryptedCustomer::to_encryptable(
+                EncryptedCustomer {
                     name: item.name.clone(),
                     phone: item.phone.clone(),
                     email: item.email.clone(),
@@ -113,16 +120,23 @@ impl super::behaviour::Conversion for Customer {
         .change_context(ValidationError::InvalidValue {
             message: "Failed while decrypting customer data".to_string(),
         })?;
-        let encryptable_customer = CustomerRequestWithEncryption::from_encryptable(decrypted)
-            .change_context(ValidationError::InvalidValue {
+        let encryptable_customer = EncryptedCustomer::from_encryptable(decrypted).change_context(
+            ValidationError::InvalidValue {
                 message: "Failed while decrypting customer data".to_string(),
-            })?;
+            },
+        )?;
 
         Ok(Self {
             customer_id: item.customer_id,
             merchant_id: item.merchant_id,
             name: encryptable_customer.name,
-            email: encryptable_customer.email,
+            email: encryptable_customer.email.map(|email| {
+                let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> = Encryptable::new(
+                    email.clone().into_inner().switch_strategy(),
+                    email.into_encrypted(),
+                );
+                encryptable
+            }),
             phone: encryptable_customer.phone,
             phone_country_code: item.phone_country_code,
             description: item.description,
@@ -198,8 +212,8 @@ impl super::behaviour::Conversion for Customer {
         let decrypted = types::crypto_operation(
             state,
             common_utils::type_name!(Self::DstType),
-            types::CryptoOperation::BatchDecrypt(CustomerRequestWithEncryption::to_encryptable(
-                CustomerRequestWithEncryption {
+            types::CryptoOperation::BatchDecrypt(EncryptedCustomer::to_encryptable(
+                EncryptedCustomer {
                     name: item.name.clone(),
                     phone: item.phone.clone(),
                     email: item.email.clone(),
@@ -213,17 +227,24 @@ impl super::behaviour::Conversion for Customer {
         .change_context(ValidationError::InvalidValue {
             message: "Failed while decrypting customer data".to_string(),
         })?;
-        let encryptable_customer = CustomerRequestWithEncryption::from_encryptable(decrypted)
-            .change_context(ValidationError::InvalidValue {
+        let encryptable_customer = EncryptedCustomer::from_encryptable(decrypted).change_context(
+            ValidationError::InvalidValue {
                 message: "Failed while decrypting customer data".to_string(),
-            })?;
+            },
+        )?;
 
         Ok(Self {
             id: item.id,
             merchant_reference_id: item.merchant_reference_id,
             merchant_id: item.merchant_id,
             name: encryptable_customer.name,
-            email: encryptable_customer.email,
+            email: encryptable_customer.email.map(|email| {
+                let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> = Encryptable::new(
+                    email.clone().into_inner().switch_strategy(),
+                    email.into_encrypted(),
+                );
+                encryptable
+            }),
             phone: encryptable_customer.phone,
             phone_country_code: item.phone_country_code,
             description: item.description,
diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs
index 9418f6f8f1e..0d730be203b 100644
--- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs
+++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs
@@ -10,16 +10,18 @@ use diesel_models::{enums, merchant_connector_account::MerchantConnectorAccountU
 use error_stack::ResultExt;
 use masking::{PeekInterface, Secret};
 use rustc_hash::FxHashMap;
+use serde_json::Value;
 
 use super::behaviour;
 use crate::type_encryption::{crypto_operation, CryptoOperation};
 
 #[cfg(feature = "v1")]
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, router_derive::ToEncryption)]
 pub struct MerchantConnectorAccount {
     pub merchant_id: id_type::MerchantId,
     pub connector_name: String,
-    pub connector_account_details: Encryptable<pii::SecretSerdeValue>,
+    #[encrypt]
+    pub connector_account_details: Encryptable<Secret<Value>>,
     pub test_mode: Option<bool>,
     pub disabled: Option<bool>,
     pub merchant_connector_id: id_type::MerchantConnectorAccountId,
@@ -38,8 +40,10 @@ pub struct MerchantConnectorAccount {
     pub applepay_verified_domains: Option<Vec<String>>,
     pub pm_auth_config: Option<pii::SecretSerdeValue>,
     pub status: enums::ConnectorStatus,
-    pub connector_wallets_details: Option<Encryptable<pii::SecretSerdeValue>>,
-    pub additional_merchant_data: Option<Encryptable<pii::SecretSerdeValue>>,
+    #[encrypt]
+    pub connector_wallets_details: Option<Encryptable<Secret<Value>>>,
+    #[encrypt]
+    pub additional_merchant_data: Option<Encryptable<Secret<Value>>>,
     pub version: common_enums::ApiVersion,
 }
 
@@ -51,12 +55,13 @@ impl MerchantConnectorAccount {
 }
 
 #[cfg(feature = "v2")]
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, router_derive::ToEncryption)]
 pub struct MerchantConnectorAccount {
     pub id: id_type::MerchantConnectorAccountId,
     pub merchant_id: id_type::MerchantId,
     pub connector_name: String,
-    pub connector_account_details: Encryptable<pii::SecretSerdeValue>,
+    #[encrypt]
+    pub connector_account_details: Encryptable<Secret<Value>>,
     pub disabled: Option<bool>,
     pub payment_methods_enabled: Option<Vec<pii::SecretSerdeValue>>,
     pub connector_type: enums::ConnectorType,
@@ -70,8 +75,10 @@ pub struct MerchantConnectorAccount {
     pub applepay_verified_domains: Option<Vec<String>>,
     pub pm_auth_config: Option<pii::SecretSerdeValue>,
     pub status: enums::ConnectorStatus,
-    pub connector_wallets_details: Option<Encryptable<pii::SecretSerdeValue>>,
-    pub additional_merchant_data: Option<Encryptable<pii::SecretSerdeValue>>,
+    #[encrypt]
+    pub connector_wallets_details: Option<Encryptable<Secret<Value>>>,
+    #[encrypt]
+    pub additional_merchant_data: Option<Encryptable<Secret<Value>>>,
     pub version: common_enums::ApiVersion,
 }
 
@@ -179,11 +186,13 @@ impl behaviour::Conversion for MerchantConnectorAccount {
         let decrypted_data = crypto_operation(
             state,
             type_name!(Self::DstType),
-            CryptoOperation::BatchDecrypt(EncryptedMca::to_encryptable(EncryptedMca {
-                connector_account_details: other.connector_account_details,
-                additional_merchant_data: other.additional_merchant_data,
-                connector_wallets_details: other.connector_wallets_details,
-            })),
+            CryptoOperation::BatchDecrypt(EncryptedMerchantConnectorAccount::to_encryptable(
+                EncryptedMerchantConnectorAccount {
+                    connector_account_details: other.connector_account_details,
+                    additional_merchant_data: other.additional_merchant_data,
+                    connector_wallets_details: other.connector_wallets_details,
+                },
+            )),
             identifier.clone(),
             key.peek(),
         )
@@ -193,11 +202,10 @@ impl behaviour::Conversion for MerchantConnectorAccount {
             message: "Failed while decrypting connector account details".to_string(),
         })?;
 
-        let decrypted_data = EncryptedMca::from_encryptable(decrypted_data).change_context(
-            ValidationError::InvalidValue {
+        let decrypted_data = EncryptedMerchantConnectorAccount::from_encryptable(decrypted_data)
+            .change_context(ValidationError::InvalidValue {
                 message: "Failed while decrypting connector account details".to_string(),
-            },
-        )?;
+            })?;
 
         Ok(Self {
             merchant_id: other.merchant_id,
@@ -308,11 +316,13 @@ impl behaviour::Conversion for MerchantConnectorAccount {
         let decrypted_data = crypto_operation(
             state,
             type_name!(Self::DstType),
-            CryptoOperation::BatchDecrypt(EncryptedMca::to_encryptable(EncryptedMca {
-                connector_account_details: other.connector_account_details,
-                additional_merchant_data: other.additional_merchant_data,
-                connector_wallets_details: other.connector_wallets_details,
-            })),
+            CryptoOperation::BatchDecrypt(EncryptedMerchantConnectorAccount::to_encryptable(
+                EncryptedMerchantConnectorAccount {
+                    connector_account_details: other.connector_account_details,
+                    additional_merchant_data: other.additional_merchant_data,
+                    connector_wallets_details: other.connector_wallets_details,
+                },
+            )),
             identifier.clone(),
             key.peek(),
         )
@@ -322,11 +332,10 @@ impl behaviour::Conversion for MerchantConnectorAccount {
             message: "Failed while decrypting connector account details".to_string(),
         })?;
 
-        let decrypted_data = EncryptedMca::from_encryptable(decrypted_data).change_context(
-            ValidationError::InvalidValue {
+        let decrypted_data = EncryptedMerchantConnectorAccount::from_encryptable(decrypted_data)
+            .change_context(ValidationError::InvalidValue {
                 message: "Failed while decrypting connector account details".to_string(),
-            },
-        )?;
+            })?;
 
         Ok(Self {
             id: other.id,
@@ -502,121 +511,3 @@ impl From<MerchantConnectorAccountUpdate> for MerchantConnectorAccountUpdateInte
         }
     }
 }
-
-pub struct McaFromRequestfromUpdate {
-    pub connector_account_details: Option<pii::SecretSerdeValue>,
-    pub connector_wallets_details: Option<pii::SecretSerdeValue>,
-    pub additional_merchant_data: Option<pii::SecretSerdeValue>,
-}
-pub struct McaFromRequest {
-    pub connector_account_details: pii::SecretSerdeValue,
-    pub connector_wallets_details: Option<pii::SecretSerdeValue>,
-    pub additional_merchant_data: Option<pii::SecretSerdeValue>,
-}
-
-pub struct DecryptedMca {
-    pub connector_account_details: Encryptable<pii::SecretSerdeValue>,
-    pub connector_wallets_details: Option<Encryptable<pii::SecretSerdeValue>>,
-    pub additional_merchant_data: Option<Encryptable<pii::SecretSerdeValue>>,
-}
-
-pub struct EncryptedMca {
-    pub connector_account_details: Encryption,
-    pub connector_wallets_details: Option<Encryption>,
-    pub additional_merchant_data: Option<Encryption>,
-}
-
-pub struct DecryptedUpdateMca {
-    pub connector_account_details: Option<Encryptable<pii::SecretSerdeValue>>,
-    pub connector_wallets_details: Option<Encryptable<pii::SecretSerdeValue>>,
-    pub additional_merchant_data: Option<Encryptable<pii::SecretSerdeValue>>,
-}
-
-impl ToEncryptable<DecryptedMca, Secret<serde_json::Value>, Encryption> for EncryptedMca {
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, Encryptable<Secret<serde_json::Value>>>,
-    ) -> CustomResult<DecryptedMca, common_utils::errors::ParsingError> {
-        Ok(DecryptedMca {
-            connector_account_details: hashmap.remove("connector_account_details").ok_or(
-                error_stack::report!(common_utils::errors::ParsingError::EncodeError(
-                    "Unable to convert from HashMap to DecryptedMca",
-                )),
-            )?,
-            connector_wallets_details: hashmap.remove("connector_wallets_details"),
-            additional_merchant_data: hashmap.remove("additional_merchant_data"),
-        })
-    }
-
-    fn to_encryptable(self) -> FxHashMap<String, Encryption> {
-        let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default());
-
-        map.insert(
-            "connector_account_details".to_string(),
-            self.connector_account_details,
-        );
-        self.connector_wallets_details
-            .map(|s| map.insert("connector_wallets_details".to_string(), s));
-        self.additional_merchant_data
-            .map(|s| map.insert("additional_merchant_data".to_string(), s));
-        map
-    }
-}
-
-impl ToEncryptable<DecryptedUpdateMca, Secret<serde_json::Value>, Secret<serde_json::Value>>
-    for McaFromRequestfromUpdate
-{
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, Encryptable<Secret<serde_json::Value>>>,
-    ) -> CustomResult<DecryptedUpdateMca, common_utils::errors::ParsingError> {
-        Ok(DecryptedUpdateMca {
-            connector_account_details: hashmap.remove("connector_account_details"),
-            connector_wallets_details: hashmap.remove("connector_wallets_details"),
-            additional_merchant_data: hashmap.remove("additional_merchant_data"),
-        })
-    }
-
-    fn to_encryptable(self) -> FxHashMap<String, Secret<serde_json::Value>> {
-        let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default());
-
-        self.connector_account_details
-            .map(|cad| map.insert("connector_account_details".to_string(), cad));
-
-        self.connector_wallets_details
-            .map(|s| map.insert("connector_wallets_details".to_string(), s));
-        self.additional_merchant_data
-            .map(|s| map.insert("additional_merchant_data".to_string(), s));
-        map
-    }
-}
-
-impl ToEncryptable<DecryptedMca, Secret<serde_json::Value>, Secret<serde_json::Value>>
-    for McaFromRequest
-{
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, Encryptable<Secret<serde_json::Value>>>,
-    ) -> CustomResult<DecryptedMca, common_utils::errors::ParsingError> {
-        Ok(DecryptedMca {
-            connector_account_details: hashmap.remove("connector_account_details").ok_or(
-                error_stack::report!(common_utils::errors::ParsingError::EncodeError(
-                    "Unable to convert from HashMap to DecryptedMca",
-                )),
-            )?,
-            connector_wallets_details: hashmap.remove("connector_wallets_details"),
-            additional_merchant_data: hashmap.remove("additional_merchant_data"),
-        })
-    }
-
-    fn to_encryptable(self) -> FxHashMap<String, Secret<serde_json::Value>> {
-        let mut map = FxHashMap::with_capacity_and_hasher(3, Default::default());
-
-        map.insert(
-            "connector_account_details".to_string(),
-            self.connector_account_details,
-        );
-        self.connector_wallets_details
-            .map(|s| map.insert("connector_wallets_details".to_string(), s));
-        self.additional_merchant_data
-            .map(|s| map.insert("additional_merchant_data".to_string(), s));
-        map
-    }
-}
diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs
index 933c13416f2..cd41458dfbf 100644
--- a/crates/hyperswitch_domain_models/src/payments.rs
+++ b/crates/hyperswitch_domain_models/src/payments.rs
@@ -5,11 +5,21 @@ use std::marker::PhantomData;
 use api_models::payments::Address;
 #[cfg(feature = "v2")]
 use api_models::payments::OrderDetailsWithAmount;
-use common_utils::{self, crypto::Encryptable, id_type, pii, types::MinorUnit};
+use common_utils::{
+    self,
+    crypto::Encryptable,
+    encryption::Encryption,
+    errors::CustomResult,
+    id_type, pii,
+    types::{keymanager::ToEncryptable, MinorUnit},
+};
 use diesel_models::payment_intent::TaxDetails;
 #[cfg(feature = "v2")]
 use error_stack::ResultExt;
 use masking::Secret;
+use router_derive::ToEncryption;
+use rustc_hash::FxHashMap;
+use serde_json::Value;
 use time::PrimitiveDateTime;
 
 pub mod payment_attempt;
@@ -25,7 +35,7 @@ use crate::{business_profile, merchant_account};
 use crate::{errors, payment_method_data, ApiModelToDieselModelConvertor};
 
 #[cfg(feature = "v1")]
-#[derive(Clone, Debug, PartialEq, serde::Serialize)]
+#[derive(Clone, Debug, PartialEq, serde::Serialize, ToEncryption)]
 pub struct PaymentIntent {
     pub payment_id: id_type::PaymentId,
     pub merchant_id: id_type::MerchantId,
@@ -37,7 +47,7 @@ pub struct PaymentIntent {
     pub customer_id: Option<id_type::CustomerId>,
     pub description: Option<String>,
     pub return_url: Option<String>,
-    pub metadata: Option<serde_json::Value>,
+    pub metadata: Option<Value>,
     pub connector_id: Option<String>,
     pub shipping_address_id: Option<String>,
     pub billing_address_id: Option<String>,
@@ -56,9 +66,9 @@ pub struct PaymentIntent {
     pub business_country: Option<storage_enums::CountryAlpha2>,
     pub business_label: Option<String>,
     pub order_details: Option<Vec<pii::SecretSerdeValue>>,
-    pub allowed_payment_method_types: Option<serde_json::Value>,
-    pub connector_metadata: Option<serde_json::Value>,
-    pub feature_metadata: Option<serde_json::Value>,
+    pub allowed_payment_method_types: Option<Value>,
+    pub connector_metadata: Option<Value>,
+    pub feature_metadata: Option<Value>,
     pub attempt_count: i16,
     pub profile_id: Option<id_type::ProfileId>,
     pub payment_link_id: Option<String>,
@@ -78,10 +88,13 @@ pub struct PaymentIntent {
     pub request_external_three_ds_authentication: Option<bool>,
     pub charges: Option<pii::SecretSerdeValue>,
     pub frm_metadata: Option<pii::SecretSerdeValue>,
-    pub customer_details: Option<Encryptable<Secret<serde_json::Value>>>,
-    pub billing_details: Option<Encryptable<Secret<serde_json::Value>>>,
+    #[encrypt]
+    pub customer_details: Option<Encryptable<Secret<Value>>>,
+    #[encrypt]
+    pub billing_details: Option<Encryptable<Secret<Value>>>,
     pub merchant_order_reference_id: Option<String>,
-    pub shipping_details: Option<Encryptable<Secret<serde_json::Value>>>,
+    #[encrypt]
+    pub shipping_details: Option<Encryptable<Secret<Value>>>,
     pub is_payment_processor_token_flow: Option<bool>,
     pub organization_id: id_type::OrganizationId,
     pub tax_details: Option<TaxDetails>,
@@ -225,7 +238,7 @@ impl AmountDetails {
 }
 
 #[cfg(feature = "v2")]
-#[derive(Clone, Debug, PartialEq, serde::Serialize)]
+#[derive(Clone, Debug, PartialEq, serde::Serialize, ToEncryption)]
 pub struct PaymentIntent {
     /// The global identifier for the payment intent. This is generated by the system.
     /// The format of the global id is `{cell_id:5}_pay_{time_ordered_uuid:32}`.
@@ -292,19 +305,22 @@ pub struct PaymentIntent {
     /// Metadata related to fraud and risk management
     pub frm_metadata: Option<pii::SecretSerdeValue>,
     /// The details of the customer in a denormalized form. Only a subset of fields are stored.
-    pub customer_details: Option<Encryptable<Secret<serde_json::Value>>>,
+    #[encrypt]
+    pub customer_details: Option<Encryptable<Secret<Value>>>,
     /// The reference id for the order in the merchant's system. This value can be passed by the merchant.
     pub merchant_reference_id: Option<id_type::PaymentReferenceId>,
     /// The billing address for the order in a denormalized form.
+    #[encrypt(ty = Value)]
     pub billing_address: Option<Encryptable<Secret<Address>>>,
     /// The shipping address for the order in a denormalized form.
+    #[encrypt(ty = Value)]
     pub shipping_address: Option<Encryptable<Secret<Address>>>,
     /// Capture method for the payment
     pub capture_method: storage_enums::CaptureMethod,
     /// Authentication type that is requested by the merchant for this payment.
     pub authentication_type: common_enums::AuthenticationType,
     /// This contains the pre routing results that are done when routing is done during listing the payment methods.
-    pub prerouting_algorithm: Option<serde_json::Value>,
+    pub prerouting_algorithm: Option<Value>,
     /// The organization id for the payment. This is derived from the merchant account
     pub organization_id: id_type::OrganizationId,
     /// Denotes the request by the merchant whether to enable a payment link for this payment.
@@ -323,7 +339,7 @@ pub struct PaymentIntent {
 impl PaymentIntent {
     fn get_request_incremental_authorization_value(
         request: &api_models::payments::PaymentsCreateIntentRequest,
-    ) -> common_utils::errors::CustomResult<
+    ) -> CustomResult<
         common_enums::RequestIncrementalAuthorization,
         errors::api_error_response::ApiErrorResponse,
     > {
@@ -364,8 +380,7 @@ impl PaymentIntent {
         request: api_models::payments::PaymentsCreateIntentRequest,
         billing_address: Option<Encryptable<Secret<Address>>>,
         shipping_address: Option<Encryptable<Secret<Address>>>,
-    ) -> common_utils::errors::CustomResult<Self, errors::api_error_response::ApiErrorResponse>
-    {
+    ) -> CustomResult<Self, errors::api_error_response::ApiErrorResponse> {
         let allowed_payment_method_types = request
             .get_allowed_payment_method_types_as_value()
             .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError)
diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs
index f1e4de499e6..c9f7a5e2ae5 100644
--- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs
+++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs
@@ -3,7 +3,7 @@ use common_enums as storage_enums;
 use common_utils::ext_traits::{Encode, ValueExt};
 use common_utils::{
     consts::{PAYMENTS_LIST_MAX_LIMIT_V1, PAYMENTS_LIST_MAX_LIMIT_V2},
-    crypto::{self, Encryptable},
+    crypto::Encryptable,
     encryption::Encryption,
     errors::{CustomResult, ValidationError},
     id_type,
@@ -21,7 +21,6 @@ use error_stack::ResultExt;
 #[cfg(feature = "v2")]
 use masking::ExposeInterface;
 use masking::{Deserialize, PeekInterface, Secret};
-use rustc_hash::FxHashMap;
 use serde::Serialize;
 use time::PrimitiveDateTime;
 
@@ -1241,10 +1240,10 @@ impl behaviour::Conversion for PaymentIntent {
             let decrypted_data = crypto_operation(
                 state,
                 type_name!(Self::DstType),
-                CryptoOperation::BatchDecrypt(EncryptedPaymentIntentAddress::to_encryptable(
-                    EncryptedPaymentIntentAddress {
-                        billing: storage_model.billing_address,
-                        shipping: storage_model.shipping_address,
+                CryptoOperation::BatchDecrypt(super::EncryptedPaymentIntent::to_encryptable(
+                    super::EncryptedPaymentIntent {
+                        billing_address: storage_model.billing_address,
+                        shipping_address: storage_model.shipping_address,
                         customer_details: storage_model.customer_details,
                     },
                 )),
@@ -1254,7 +1253,7 @@ impl behaviour::Conversion for PaymentIntent {
             .await
             .and_then(|val| val.try_into_batchoperation())?;
 
-            let data = EncryptedPaymentIntentAddress::from_encryptable(decrypted_data)
+            let data = super::EncryptedPaymentIntent::from_encryptable(decrypted_data)
                 .change_context(common_utils::errors::CryptoError::DecodingFailed)
                 .attach_printable("Invalid batch operation data")?;
 
@@ -1275,7 +1274,7 @@ impl behaviour::Conversion for PaymentIntent {
             };
 
             let billing_address = data
-                .billing
+                .billing_address
                 .map(|billing| {
                     billing.deserialize_inner_value(|value| value.parse_value("Address"))
                 })
@@ -1284,7 +1283,7 @@ impl behaviour::Conversion for PaymentIntent {
                 .attach_printable("Error while deserializing Address")?;
 
             let shipping_address = data
-                .shipping
+                .shipping_address
                 .map(|shipping| {
                     shipping.deserialize_inner_value(|value| value.parse_value("Address"))
                 })
@@ -1513,10 +1512,10 @@ impl behaviour::Conversion for PaymentIntent {
             let decrypted_data = crypto_operation(
                 state,
                 type_name!(Self::DstType),
-                CryptoOperation::BatchDecrypt(EncryptedPaymentIntentAddress::to_encryptable(
-                    EncryptedPaymentIntentAddress {
-                        billing: storage_model.billing_details,
-                        shipping: storage_model.shipping_details,
+                CryptoOperation::BatchDecrypt(super::EncryptedPaymentIntent::to_encryptable(
+                    super::EncryptedPaymentIntent {
+                        billing_details: storage_model.billing_details,
+                        shipping_details: storage_model.shipping_details,
                         customer_details: storage_model.customer_details,
                     },
                 )),
@@ -1526,7 +1525,7 @@ impl behaviour::Conversion for PaymentIntent {
             .await
             .and_then(|val| val.try_into_batchoperation())?;
 
-            let data = EncryptedPaymentIntentAddress::from_encryptable(decrypted_data)
+            let data = super::EncryptedPaymentIntent::from_encryptable(decrypted_data)
                 .change_context(common_utils::errors::CryptoError::DecodingFailed)
                 .attach_printable("Invalid batch operation data")?;
 
@@ -1578,9 +1577,9 @@ impl behaviour::Conversion for PaymentIntent {
                 shipping_cost: storage_model.shipping_cost,
                 tax_details: storage_model.tax_details,
                 customer_details: data.customer_details,
-                billing_details: data.billing,
+                billing_details: data.billing_details,
                 merchant_order_reference_id: storage_model.merchant_order_reference_id,
-                shipping_details: data.shipping,
+                shipping_details: data.shipping_details,
                 is_payment_processor_token_flow: storage_model.is_payment_processor_token_flow,
                 organization_id: storage_model.organization_id,
                 skip_external_tax_calculation: storage_model.skip_external_tax_calculation,
@@ -1649,73 +1648,3 @@ impl behaviour::Conversion for PaymentIntent {
         })
     }
 }
-
-pub struct EncryptedPaymentIntentAddress {
-    pub shipping: Option<Encryption>,
-    pub billing: Option<Encryption>,
-    pub customer_details: Option<Encryption>,
-}
-
-pub struct PaymentAddressFromRequest {
-    pub shipping: Option<Secret<serde_json::Value>>,
-    pub billing: Option<Secret<serde_json::Value>>,
-    pub customer_details: Option<Secret<serde_json::Value>>,
-}
-
-pub struct DecryptedPaymentIntentAddress {
-    pub shipping: crypto::OptionalEncryptableValue,
-    pub billing: crypto::OptionalEncryptableValue,
-    pub customer_details: crypto::OptionalEncryptableValue,
-}
-
-impl ToEncryptable<DecryptedPaymentIntentAddress, Secret<serde_json::Value>, Encryption>
-    for EncryptedPaymentIntentAddress
-{
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, Encryptable<Secret<serde_json::Value>>>,
-    ) -> CustomResult<DecryptedPaymentIntentAddress, common_utils::errors::ParsingError> {
-        Ok(DecryptedPaymentIntentAddress {
-            shipping: hashmap.remove("shipping"),
-            billing: hashmap.remove("billing"),
-            customer_details: hashmap.remove("customer_details"),
-        })
-    }
-
-    fn to_encryptable(self) -> FxHashMap<String, Encryption> {
-        let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default());
-
-        self.shipping.map(|s| map.insert("shipping".to_string(), s));
-        self.billing.map(|s| map.insert("billing".to_string(), s));
-        self.customer_details
-            .map(|s| map.insert("customer_details".to_string(), s));
-        map
-    }
-}
-
-impl
-    ToEncryptable<
-        DecryptedPaymentIntentAddress,
-        Secret<serde_json::Value>,
-        Secret<serde_json::Value>,
-    > for PaymentAddressFromRequest
-{
-    fn from_encryptable(
-        mut hashmap: FxHashMap<String, Encryptable<Secret<serde_json::Value>>>,
-    ) -> CustomResult<DecryptedPaymentIntentAddress, common_utils::errors::ParsingError> {
-        Ok(DecryptedPaymentIntentAddress {
-            shipping: hashmap.remove("shipping"),
-            billing: hashmap.remove("billing"),
-            customer_details: hashmap.remove("customer_details"),
-        })
-    }
-
-    fn to_encryptable(self) -> FxHashMap<String, Secret<serde_json::Value>> {
-        let mut map = FxHashMap::with_capacity_and_hasher(9, Default::default());
-
-        self.shipping.map(|s| map.insert("shipping".to_string(), s));
-        self.billing.map(|s| map.insert("billing".to_string(), s));
-        self.customer_details
-            .map(|s| map.insert("customer_details".to_string(), s));
-        map
-    }
-}
diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs
index f49f4096340..cffb8267bff 100644
--- a/crates/router/src/core/admin.rs
+++ b/crates/router/src/core/admin.rs
@@ -15,7 +15,7 @@ use diesel_models::configs;
 use diesel_models::organization::OrganizationBridge;
 use error_stack::{report, FutureExt, ResultExt};
 use hyperswitch_domain_models::merchant_connector_account::{
-    McaFromRequest, McaFromRequestfromUpdate,
+    FromRequestEncryptableMerchantConnectorAccount, UpdateEncryptableMerchantConnectorAccount,
 };
 use masking::{ExposeInterface, PeekInterface, Secret};
 use pm_auth::{connector::plaid::transformers::PlaidAuthType, types as pm_auth_types};
@@ -2095,18 +2095,20 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect
         let encrypted_data = domain_types::crypto_operation(
             key_manager_state,
             type_name!(domain::MerchantConnectorAccount),
-            domain_types::CryptoOperation::BatchEncrypt(McaFromRequestfromUpdate::to_encryptable(
-                McaFromRequestfromUpdate {
-                    connector_account_details: self.connector_account_details,
-                    connector_wallets_details:
-                        helpers::get_connector_wallets_details_with_apple_pay_certificates(
-                            &self.metadata,
-                            &self.connector_wallets_details,
-                        )
-                        .await?,
-                    additional_merchant_data: merchant_recipient_data.map(Secret::new),
-                },
-            )),
+            domain_types::CryptoOperation::BatchEncrypt(
+                UpdateEncryptableMerchantConnectorAccount::to_encryptable(
+                    UpdateEncryptableMerchantConnectorAccount {
+                        connector_account_details: self.connector_account_details,
+                        connector_wallets_details:
+                            helpers::get_connector_wallets_details_with_apple_pay_certificates(
+                                &self.metadata,
+                                &self.connector_wallets_details,
+                            )
+                            .await?,
+                        additional_merchant_data: merchant_recipient_data.map(Secret::new),
+                    },
+                ),
+            ),
             km_types::Identifier::Merchant(key_store.merchant_id.clone()),
             key_store.key.peek(),
         )
@@ -2115,9 +2117,10 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Failed while decrypting connector account details".to_string())?;
 
-        let encrypted_data = McaFromRequestfromUpdate::from_encryptable(encrypted_data)
-            .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed while decrypting connector account details")?;
+        let encrypted_data =
+            UpdateEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data)
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed while decrypting connector account details")?;
 
         Ok(storage::MerchantConnectorAccountUpdate::Update {
             connector_type: Some(self.connector_type),
@@ -2262,18 +2265,20 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect
         let encrypted_data = domain_types::crypto_operation(
             key_manager_state,
             type_name!(domain::MerchantConnectorAccount),
-            domain_types::CryptoOperation::BatchEncrypt(McaFromRequestfromUpdate::to_encryptable(
-                McaFromRequestfromUpdate {
-                    connector_account_details: self.connector_account_details,
-                    connector_wallets_details:
-                        helpers::get_connector_wallets_details_with_apple_pay_certificates(
-                            &self.metadata,
-                            &self.connector_wallets_details,
-                        )
-                        .await?,
-                    additional_merchant_data: merchant_recipient_data.map(Secret::new),
-                },
-            )),
+            domain_types::CryptoOperation::BatchEncrypt(
+                UpdateEncryptableMerchantConnectorAccount::to_encryptable(
+                    UpdateEncryptableMerchantConnectorAccount {
+                        connector_account_details: self.connector_account_details,
+                        connector_wallets_details:
+                            helpers::get_connector_wallets_details_with_apple_pay_certificates(
+                                &self.metadata,
+                                &self.connector_wallets_details,
+                            )
+                            .await?,
+                        additional_merchant_data: merchant_recipient_data.map(Secret::new),
+                    },
+                ),
+            ),
             km_types::Identifier::Merchant(key_store.merchant_id.clone()),
             key_store.key.peek(),
         )
@@ -2282,9 +2287,10 @@ impl MerchantConnectorAccountUpdateBridge for api_models::admin::MerchantConnect
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Failed while decrypting connector account details".to_string())?;
 
-        let encrypted_data = McaFromRequestfromUpdate::from_encryptable(encrypted_data)
-            .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed while decrypting connector account details")?;
+        let encrypted_data =
+            UpdateEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data)
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed while decrypting connector account details")?;
 
         Ok(storage::MerchantConnectorAccountUpdate::Update {
             connector_type: Some(self.connector_type),
@@ -2404,22 +2410,24 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate {
         let encrypted_data = domain_types::crypto_operation(
             key_manager_state,
             type_name!(domain::MerchantConnectorAccount),
-            domain_types::CryptoOperation::BatchEncrypt(McaFromRequest::to_encryptable(
-                McaFromRequest {
-                    connector_account_details: self.connector_account_details.ok_or(
-                        errors::ApiErrorResponse::MissingRequiredField {
-                            field_name: "connector_account_details",
-                        },
-                    )?,
-                    connector_wallets_details:
-                        helpers::get_connector_wallets_details_with_apple_pay_certificates(
-                            &self.metadata,
-                            &self.connector_wallets_details,
-                        )
-                        .await?,
-                    additional_merchant_data: merchant_recipient_data.map(Secret::new),
-                },
-            )),
+            domain_types::CryptoOperation::BatchEncrypt(
+                FromRequestEncryptableMerchantConnectorAccount::to_encryptable(
+                    FromRequestEncryptableMerchantConnectorAccount {
+                        connector_account_details: self.connector_account_details.ok_or(
+                            errors::ApiErrorResponse::MissingRequiredField {
+                                field_name: "connector_account_details",
+                            },
+                        )?,
+                        connector_wallets_details:
+                            helpers::get_connector_wallets_details_with_apple_pay_certificates(
+                                &self.metadata,
+                                &self.connector_wallets_details,
+                            )
+                            .await?,
+                        additional_merchant_data: merchant_recipient_data.map(Secret::new),
+                    },
+                ),
+            ),
             identifier.clone(),
             key_store.key.peek(),
         )
@@ -2428,9 +2436,10 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate {
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Failed while decrypting connector account details".to_string())?;
 
-        let encrypted_data = McaFromRequest::from_encryptable(encrypted_data)
-            .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed while decrypting connector account details")?;
+        let encrypted_data =
+            FromRequestEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data)
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed while decrypting connector account details")?;
 
         Ok(domain::MerchantConnectorAccount {
             merchant_id: business_profile.merchant_id.clone(),
@@ -2573,22 +2582,24 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate {
         let encrypted_data = domain_types::crypto_operation(
             key_manager_state,
             type_name!(domain::MerchantConnectorAccount),
-            domain_types::CryptoOperation::BatchEncrypt(McaFromRequest::to_encryptable(
-                McaFromRequest {
-                    connector_account_details: self.connector_account_details.ok_or(
-                        errors::ApiErrorResponse::MissingRequiredField {
-                            field_name: "connector_account_details",
-                        },
-                    )?,
-                    connector_wallets_details:
-                        helpers::get_connector_wallets_details_with_apple_pay_certificates(
-                            &self.metadata,
-                            &self.connector_wallets_details,
-                        )
-                        .await?,
-                    additional_merchant_data: merchant_recipient_data.map(Secret::new),
-                },
-            )),
+            domain_types::CryptoOperation::BatchEncrypt(
+                FromRequestEncryptableMerchantConnectorAccount::to_encryptable(
+                    FromRequestEncryptableMerchantConnectorAccount {
+                        connector_account_details: self.connector_account_details.ok_or(
+                            errors::ApiErrorResponse::MissingRequiredField {
+                                field_name: "connector_account_details",
+                            },
+                        )?,
+                        connector_wallets_details:
+                            helpers::get_connector_wallets_details_with_apple_pay_certificates(
+                                &self.metadata,
+                                &self.connector_wallets_details,
+                            )
+                            .await?,
+                        additional_merchant_data: merchant_recipient_data.map(Secret::new),
+                    },
+                ),
+            ),
             identifier.clone(),
             key_store.key.peek(),
         )
@@ -2597,9 +2608,10 @@ impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate {
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Failed while decrypting connector account details".to_string())?;
 
-        let encrypted_data = McaFromRequest::from_encryptable(encrypted_data)
-            .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed while decrypting connector account details")?;
+        let encrypted_data =
+            FromRequestEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data)
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed while decrypting connector account details")?;
 
         Ok(domain::MerchantConnectorAccount {
             merchant_id: business_profile.merchant_id.clone(),
diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs
index 18cc8682eee..6d47ac174f3 100644
--- a/crates/router/src/core/customers.rs
+++ b/crates/router/src/core/customers.rs
@@ -1,16 +1,15 @@
-use api_models::customers::CustomerRequestWithEmail;
 use common_utils::{
     crypto::Encryptable,
     errors::ReportSwitchExt,
     ext_traits::{AsyncExt, OptionExt},
-    id_type, type_name,
+    id_type, pii, type_name,
     types::{
         keymanager::{Identifier, KeyManagerState, ToEncryptable},
         Description,
     },
 };
 use error_stack::{report, ResultExt};
-use masking::{Secret, SwitchStrategy};
+use masking::{ExposeInterface, Secret, SwitchStrategy};
 use router_env::{instrument, tracing};
 
 #[cfg(all(feature = "v2", feature = "customer_v2"))]
@@ -145,13 +144,15 @@ impl CustomerCreateBridge for customers::CustomerRequest {
         let encrypted_data = types::crypto_operation(
             key_manager_state,
             type_name!(domain::Customer),
-            types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable(
-                CustomerRequestWithEmail {
-                    name: self.name.clone(),
-                    email: self.email.clone(),
-                    phone: self.phone.clone(),
-                },
-            )),
+            types::CryptoOperation::BatchEncrypt(
+                domain::FromRequestEncryptableCustomer::to_encryptable(
+                    domain::FromRequestEncryptableCustomer {
+                        name: self.name.clone(),
+                        email: self.email.clone().map(|a| a.expose().switch_strategy()),
+                        phone: self.phone.clone(),
+                    },
+                ),
+            ),
             Identifier::Merchant(key_store.merchant_id.clone()),
             key,
         )
@@ -160,8 +161,9 @@ impl CustomerCreateBridge for customers::CustomerRequest {
         .switch()
         .attach_printable("Failed while encrypting Customer")?;
 
-        let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data)
-            .change_context(errors::CustomersErrorResponse::InternalServerError)?;
+        let encryptable_customer =
+            domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data)
+                .change_context(errors::CustomersErrorResponse::InternalServerError)?;
 
         Ok(domain::Customer {
             customer_id: merchant_reference_id
@@ -169,7 +171,13 @@ impl CustomerCreateBridge for customers::CustomerRequest {
                 .ok_or(errors::CustomersErrorResponse::InternalServerError)?,
             merchant_id: merchant_id.to_owned(),
             name: encryptable_customer.name,
-            email: encryptable_customer.email,
+            email: encryptable_customer.email.map(|email| {
+                let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> = Encryptable::new(
+                    email.clone().into_inner().switch_strategy(),
+                    email.into_encrypted(),
+                );
+                encryptable
+            }),
             phone: encryptable_customer.phone,
             description: self.description.clone(),
             phone_country_code: self.phone_country_code.clone(),
@@ -234,13 +242,15 @@ impl CustomerCreateBridge for customers::CustomerRequest {
         let encrypted_data = types::crypto_operation(
             key_state,
             type_name!(domain::Customer),
-            types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable(
-                CustomerRequestWithEmail {
-                    name: Some(self.name.clone()),
-                    email: Some(self.email.clone()),
-                    phone: self.phone.clone(),
-                },
-            )),
+            types::CryptoOperation::BatchEncrypt(
+                domain::FromRequestEncryptableCustomer::to_encryptable(
+                    domain::FromRequestEncryptableCustomer {
+                        name: Some(self.name.clone()),
+                        email: Some(self.email.clone().expose().switch_strategy()),
+                        phone: self.phone.clone(),
+                    },
+                ),
+            ),
             Identifier::Merchant(key_store.merchant_id.clone()),
             key,
         )
@@ -249,15 +259,22 @@ impl CustomerCreateBridge for customers::CustomerRequest {
         .switch()
         .attach_printable("Failed while encrypting Customer")?;
 
-        let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data)
-            .change_context(errors::CustomersErrorResponse::InternalServerError)?;
+        let encryptable_customer =
+            domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data)
+                .change_context(errors::CustomersErrorResponse::InternalServerError)?;
 
         Ok(domain::Customer {
             id: common_utils::generate_time_ordered_id("cus"),
             merchant_reference_id: merchant_reference_id.to_owned(),
             merchant_id,
             name: encryptable_customer.name,
-            email: encryptable_customer.email,
+            email: encryptable_customer.email.map(|email| {
+                let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> = Encryptable::new(
+                    email.clone().into_inner().switch_strategy(),
+                    email.into_encrypted(),
+                );
+                encryptable
+            }),
             phone: encryptable_customer.phone,
             description: self.description.clone(),
             phone_country_code: self.phone_country_code.clone(),
@@ -1174,13 +1191,18 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest {
         let encrypted_data = types::crypto_operation(
             key_manager_state,
             type_name!(domain::Customer),
-            types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable(
-                CustomerRequestWithEmail {
-                    name: self.name.clone(),
-                    email: self.email.clone(),
-                    phone: self.phone.clone(),
-                },
-            )),
+            types::CryptoOperation::BatchEncrypt(
+                domain::FromRequestEncryptableCustomer::to_encryptable(
+                    domain::FromRequestEncryptableCustomer {
+                        name: self.name.clone(),
+                        email: self
+                            .email
+                            .as_ref()
+                            .map(|a| a.clone().expose().switch_strategy()),
+                        phone: self.phone.clone(),
+                    },
+                ),
+            ),
             Identifier::Merchant(key_store.merchant_id.clone()),
             key,
         )
@@ -1188,8 +1210,9 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest {
         .and_then(|val| val.try_into_batchoperation())
         .switch()?;
 
-        let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data)
-            .change_context(errors::CustomersErrorResponse::InternalServerError)?;
+        let encryptable_customer =
+            domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data)
+                .change_context(errors::CustomersErrorResponse::InternalServerError)?;
 
         let response = db
             .update_customer_by_customer_id_merchant_id(
@@ -1199,7 +1222,14 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest {
                 domain_customer.to_owned(),
                 storage::CustomerUpdate::Update {
                     name: encryptable_customer.name,
-                    email: encryptable_customer.email,
+                    email: encryptable_customer.email.map(|email| {
+                        let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> =
+                            Encryptable::new(
+                                email.clone().into_inner().switch_strategy(),
+                                email.into_encrypted(),
+                            );
+                        encryptable
+                    }),
                     phone: Box::new(encryptable_customer.phone),
                     phone_country_code: self.phone_country_code.clone(),
                     metadata: self.metadata.clone(),
@@ -1266,13 +1296,18 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest {
         let encrypted_data = types::crypto_operation(
             key_manager_state,
             type_name!(domain::Customer),
-            types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable(
-                CustomerRequestWithEmail {
-                    name: self.name.clone(),
-                    email: self.email.clone(),
-                    phone: self.phone.clone(),
-                },
-            )),
+            types::CryptoOperation::BatchEncrypt(
+                domain::FromRequestEncryptableCustomer::to_encryptable(
+                    domain::FromRequestEncryptableCustomer {
+                        name: self.name.clone(),
+                        email: self
+                            .email
+                            .as_ref()
+                            .map(|a| a.clone().expose().switch_strategy()),
+                        phone: self.phone.clone(),
+                    },
+                ),
+            ),
             Identifier::Merchant(key_store.merchant_id.clone()),
             key,
         )
@@ -1280,8 +1315,9 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest {
         .and_then(|val| val.try_into_batchoperation())
         .switch()?;
 
-        let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data)
-            .change_context(errors::CustomersErrorResponse::InternalServerError)?;
+        let encryptable_customer =
+            domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data)
+                .change_context(errors::CustomersErrorResponse::InternalServerError)?;
 
         let response = db
             .update_customer_by_global_id(
@@ -1291,7 +1327,14 @@ impl CustomerUpdateBridge for customers::CustomerUpdateRequest {
                 merchant_account.get_id(),
                 storage::CustomerUpdate::Update {
                     name: encryptable_customer.name,
-                    email: Box::new(encryptable_customer.email),
+                    email: Box::new(encryptable_customer.email.map(|email| {
+                        let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> =
+                            Encryptable::new(
+                                email.clone().into_inner().switch_strategy(),
+                                email.into_encrypted(),
+                            );
+                        encryptable
+                    })),
                     phone: Box::new(encryptable_customer.phone),
                     phone_country_code: self.phone_country_code.clone(),
                     metadata: self.metadata.clone(),
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 1f67e8066c9..ea7af3c7578 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -1,12 +1,9 @@
 use std::{borrow::Cow, str::FromStr};
 
-#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
-use api_models::customers::CustomerRequestWithEmail;
 use api_models::{
     mandates::RecurringDetails,
     payments::{
-        additional_info as payment_additional_types, AddressDetailsWithPhone, PaymentChargeRequest,
-        RequestSurchargeDetails,
+        additional_info as payment_additional_types, PaymentChargeRequest, RequestSurchargeDetails,
     },
 };
 use base64::Engine;
@@ -39,7 +36,7 @@ use hyperswitch_domain_models::{
 };
 use hyperswitch_interfaces::integrity::{CheckIntegrity, FlowIntegrity, GetIntegrityObject};
 use josekit::jwe;
-use masking::{ExposeInterface, PeekInterface};
+use masking::{ExposeInterface, PeekInterface, SwitchStrategy};
 use openssl::{
     derive::Deriver,
     pkey::PKey,
@@ -126,16 +123,33 @@ pub async fn create_or_update_address_for_payment_by_request(
                 let encrypted_data = types::crypto_operation(
                     &session_state.into(),
                     type_name!(domain::Address),
-                    types::CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable(
-                        AddressDetailsWithPhone {
-                            address: address.address.clone(),
-                            phone_number: address
-                                .phone
-                                .as_ref()
-                                .and_then(|phone| phone.number.clone()),
-                            email: address.email.clone(),
-                        },
-                    )),
+                    types::CryptoOperation::BatchEncrypt(
+                        domain::FromRequestEncryptableAddress::to_encryptable(
+                            domain::FromRequestEncryptableAddress {
+                                line1: address.address.as_ref().and_then(|a| a.line1.clone()),
+                                line2: address.address.as_ref().and_then(|a| a.line2.clone()),
+                                line3: address.address.as_ref().and_then(|a| a.line3.clone()),
+                                state: address.address.as_ref().and_then(|a| a.state.clone()),
+                                first_name: address
+                                    .address
+                                    .as_ref()
+                                    .and_then(|a| a.first_name.clone()),
+                                last_name: address
+                                    .address
+                                    .as_ref()
+                                    .and_then(|a| a.last_name.clone()),
+                                zip: address.address.as_ref().and_then(|a| a.zip.clone()),
+                                phone_number: address
+                                    .phone
+                                    .as_ref()
+                                    .and_then(|phone| phone.number.clone()),
+                                email: address
+                                    .email
+                                    .as_ref()
+                                    .map(|a| a.clone().expose().switch_strategy()),
+                            },
+                        ),
+                    ),
                     Identifier::Merchant(merchant_key_store.merchant_id.clone()),
                     key,
                 )
@@ -143,9 +157,10 @@ pub async fn create_or_update_address_for_payment_by_request(
                 .and_then(|val| val.try_into_batchoperation())
                 .change_context(errors::ApiErrorResponse::InternalServerError)
                 .attach_printable("Failed while encrypting address")?;
-                let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data)
-                    .change_context(errors::ApiErrorResponse::InternalServerError)
-                    .attach_printable("Failed while encrypting address")?;
+                let encryptable_address =
+                    domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
+                        .change_context(errors::ApiErrorResponse::InternalServerError)
+                        .attach_printable("Failed while encrypting address")?;
                 let address_update = storage::AddressUpdate::Update {
                     city: address
                         .address
@@ -165,7 +180,14 @@ pub async fn create_or_update_address_for_payment_by_request(
                         .as_ref()
                         .and_then(|value| value.country_code.clone()),
                     updated_by: storage_scheme.to_string(),
-                    email: encryptable_address.email,
+                    email: encryptable_address.email.map(|email| {
+                        let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
+                            Encryptable::new(
+                                email.clone().into_inner().switch_strategy(),
+                                email.into_encrypted(),
+                            );
+                        encryptable
+                    }),
                 };
                 let address = db
                     .find_address_by_merchant_id_payment_id_address_id(
@@ -317,23 +339,35 @@ pub async fn get_domain_address(
         let encrypted_data = types::crypto_operation(
             &session_state.into(),
             type_name!(domain::Address),
-            types::CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable(
-                AddressDetailsWithPhone {
-                    address: address_details.cloned(),
-                    phone_number: address
-                        .phone
-                        .as_ref()
-                        .and_then(|phone| phone.number.clone()),
-                    email: address.email.clone(),
-                },
-            )),
+            types::CryptoOperation::BatchEncrypt(
+                domain::FromRequestEncryptableAddress::to_encryptable(
+                    domain::FromRequestEncryptableAddress {
+                        line1: address.address.as_ref().and_then(|a| a.line1.clone()),
+                        line2: address.address.as_ref().and_then(|a| a.line2.clone()),
+                        line3: address.address.as_ref().and_then(|a| a.line3.clone()),
+                        state: address.address.as_ref().and_then(|a| a.state.clone()),
+                        first_name: address.address.as_ref().and_then(|a| a.first_name.clone()),
+                        last_name: address.address.as_ref().and_then(|a| a.last_name.clone()),
+                        zip: address.address.as_ref().and_then(|a| a.zip.clone()),
+                        phone_number: address
+                            .phone
+                            .as_ref()
+                            .and_then(|phone| phone.number.clone()),
+                        email: address
+                            .email
+                            .as_ref()
+                            .map(|a| a.clone().expose().switch_strategy()),
+                    },
+                ),
+            ),
             Identifier::Merchant(merchant_id.to_owned()),
             key,
         )
         .await
         .and_then(|val| val.try_into_batchoperation())?;
-        let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data)
-            .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
+        let encryptable_address =
+            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
+                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
         Ok(domain::Address {
             phone_number: encryptable_address.phone_number,
             country_code: address.phone.as_ref().and_then(|a| a.country_code.clone()),
@@ -351,7 +385,14 @@ pub async fn get_domain_address(
             modified_at: common_utils::date_time::now(),
             zip: encryptable_address.zip,
             updated_by: storage_scheme.to_string(),
-            email: encryptable_address.email,
+            email: encryptable_address.email.map(|email| {
+                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
+                    Encryptable::new(
+                        email.clone().into_inner().switch_strategy(),
+                        email.into_encrypted(),
+                    );
+                encryptable
+            }),
         })
     }
     .await
@@ -1589,13 +1630,18 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>(
             let encrypted_data = types::crypto_operation(
                 key_manager_state,
                 type_name!(domain::Customer),
-                types::CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable(
-                    CustomerRequestWithEmail {
-                        name: request_customer_details.name.clone(),
-                        email: request_customer_details.email.clone(),
-                        phone: request_customer_details.phone.clone(),
-                    },
-                )),
+                types::CryptoOperation::BatchEncrypt(
+                    domain::FromRequestEncryptableCustomer::to_encryptable(
+                        domain::FromRequestEncryptableCustomer {
+                            name: request_customer_details.name.clone(),
+                            email: request_customer_details
+                                .email
+                                .as_ref()
+                                .map(|e| e.clone().expose().switch_strategy()),
+                            phone: request_customer_details.phone.clone(),
+                        },
+                    ),
+                ),
                 Identifier::Merchant(key_store.merchant_id.clone()),
                 key,
             )
@@ -1603,9 +1649,10 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>(
             .and_then(|val| val.try_into_batchoperation())
             .change_context(errors::StorageError::SerializationFailed)
             .attach_printable("Failed while encrypting Customer while Update")?;
-            let encryptable_customer = CustomerRequestWithEmail::from_encryptable(encrypted_data)
-                .change_context(errors::StorageError::SerializationFailed)
-                .attach_printable("Failed while encrypting Customer while Update")?;
+            let encryptable_customer =
+                domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data)
+                    .change_context(errors::StorageError::SerializationFailed)
+                    .attach_printable("Failed while encrypting Customer while Update")?;
             Some(match customer_data {
                 Some(c) => {
                     // Update the customer data if new data is passed in the request
@@ -1616,7 +1663,15 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>(
                     {
                         let customer_update = Update {
                             name: encryptable_customer.name,
-                            email: encryptable_customer.email,
+                            email: encryptable_customer.email.map(|email| {
+                                let encryptable: Encryptable<
+                                    masking::Secret<String, pii::EmailStrategy>,
+                                > = Encryptable::new(
+                                    email.clone().into_inner().switch_strategy(),
+                                    email.into_encrypted(),
+                                );
+                                encryptable
+                            }),
                             phone: Box::new(encryptable_customer.phone),
                             phone_country_code: request_customer_details.phone_country_code,
                             description: None,
@@ -1644,7 +1699,15 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>(
                         customer_id,
                         merchant_id: merchant_id.to_owned(),
                         name: encryptable_customer.name,
-                        email: encryptable_customer.email,
+                        email: encryptable_customer.email.map(|email| {
+                            let encryptable: Encryptable<
+                                masking::Secret<String, pii::EmailStrategy>,
+                            > = Encryptable::new(
+                                email.clone().into_inner().switch_strategy(),
+                                email.into_encrypted(),
+                            );
+                            encryptable
+                        }),
                         phone: encryptable_customer.phone,
                         phone_country_code: request_customer_details.phone_country_code.clone(),
                         description: None,
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index 696bd1468e4..13c589c11cc 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -18,8 +18,8 @@ use error_stack::{self, ResultExt};
 use hyperswitch_domain_models::{
     mandates::{MandateData, MandateDetails},
     payments::{
-        payment_attempt::PaymentAttempt,
-        payment_intent::{CustomerData, PaymentAddressFromRequest},
+        payment_attempt::PaymentAttempt, payment_intent::CustomerData,
+        FromRequestEncryptablePaymentIntent,
     },
 };
 use masking::{ExposeInterface, PeekInterface, Secret};
@@ -1340,11 +1340,13 @@ impl PaymentCreate {
             &key_manager_state,
             type_name!(storage::PaymentIntent),
             domain::types::CryptoOperation::BatchEncrypt(
-                PaymentAddressFromRequest::to_encryptable(PaymentAddressFromRequest {
-                    shipping: shipping_details_encoded,
-                    billing: billing_details_encoded,
-                    customer_details: customer_details_encoded,
-                }),
+                FromRequestEncryptablePaymentIntent::to_encryptable(
+                    FromRequestEncryptablePaymentIntent {
+                        shipping_details: shipping_details_encoded,
+                        billing_details: billing_details_encoded,
+                        customer_details: customer_details_encoded,
+                    },
+                ),
             ),
             identifier.clone(),
             key,
@@ -1354,7 +1356,7 @@ impl PaymentCreate {
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Unable to encrypt data")?;
 
-        let encrypted_data = PaymentAddressFromRequest::from_encryptable(encrypted_data)
+        let encrypted_data = FromRequestEncryptablePaymentIntent::from_encryptable(encrypted_data)
             .change_context(errors::ApiErrorResponse::InternalServerError)
             .attach_printable("Unable to encrypt the payment intent data")?;
 
@@ -1407,10 +1409,10 @@ impl PaymentCreate {
                 .request_external_three_ds_authentication,
             charges,
             frm_metadata: request.frm_metadata.clone(),
-            billing_details: encrypted_data.billing,
+            billing_details: encrypted_data.billing_details,
             customer_details: encrypted_data.customer_details,
             merchant_order_reference_id: request.merchant_order_reference_id.clone(),
-            shipping_details: encrypted_data.shipping,
+            shipping_details: encrypted_data.shipping_details,
             is_payment_processor_token_flow,
             organization_id: merchant_account.organization_id.clone(),
             shipping_cost: request.shipping_cost,
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index 46f45905448..49b18e53a0c 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -1,11 +1,10 @@
-#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
-use api_models::customers::CustomerRequestWithEmail;
 use api_models::{enums, payment_methods::Card, payouts};
 use common_utils::{
+    crypto::Encryptable,
     encryption::Encryption,
     errors::CustomResult,
     ext_traits::{AsyncExt, StringExt},
-    fp_utils, id_type, payout_method_utils as payout_additional, type_name,
+    fp_utils, id_type, payout_method_utils as payout_additional, pii, type_name,
     types::{
         keymanager::{Identifier, KeyManagerState},
         MinorUnit, UnifiedCode, UnifiedMessage,
@@ -15,7 +14,7 @@ use common_utils::{
 use common_utils::{generate_customer_id_of_default_length, types::keymanager::ToEncryptable};
 use error_stack::{report, ResultExt};
 use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation};
-use masking::{PeekInterface, Secret};
+use masking::{ExposeInterface, PeekInterface, Secret, SwitchStrategy};
 use router_env::logger;
 
 use super::PayoutData;
@@ -696,13 +695,18 @@ pub(super) async fn get_or_create_customer_details(
                 let encrypted_data = crypto_operation(
                     &state.into(),
                     type_name!(domain::Customer),
-                    CryptoOperation::BatchEncrypt(CustomerRequestWithEmail::to_encryptable(
-                        CustomerRequestWithEmail {
-                            name: customer_details.name.clone(),
-                            email: customer_details.email.clone(),
-                            phone: customer_details.phone.clone(),
-                        },
-                    )),
+                    CryptoOperation::BatchEncrypt(
+                        domain::FromRequestEncryptableCustomer::to_encryptable(
+                            domain::FromRequestEncryptableCustomer {
+                                name: customer_details.name.clone(),
+                                email: customer_details
+                                    .email
+                                    .clone()
+                                    .map(|a| a.expose().switch_strategy()),
+                                phone: customer_details.phone.clone(),
+                            },
+                        ),
+                    ),
                     Identifier::Merchant(key_store.merchant_id.clone()),
                     key,
                 )
@@ -711,7 +715,7 @@ pub(super) async fn get_or_create_customer_details(
                 .change_context(errors::ApiErrorResponse::InternalServerError)
                 .attach_printable("Failed to encrypt customer")?;
                 let encryptable_customer =
-                    CustomerRequestWithEmail::from_encryptable(encrypted_data)
+                    domain::FromRequestEncryptableCustomer::from_encryptable(encrypted_data)
                         .change_context(errors::ApiErrorResponse::InternalServerError)
                         .attach_printable("Failed to form EncryptableCustomer")?;
 
@@ -719,7 +723,14 @@ pub(super) async fn get_or_create_customer_details(
                     customer_id: customer_id.clone(),
                     merchant_id: merchant_id.to_owned().clone(),
                     name: encryptable_customer.name,
-                    email: encryptable_customer.email,
+                    email: encryptable_customer.email.map(|email| {
+                        let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> =
+                            Encryptable::new(
+                                email.clone().into_inner().switch_strategy(),
+                                email.into_encrypted(),
+                            );
+                        encryptable
+                    }),
                     phone: encryptable_customer.phone,
                     description: None,
                     phone_country_code: customer_details.phone_country_code.to_owned(),
diff --git a/crates/router/src/types/domain/address.rs b/crates/router/src/types/domain/address.rs
index 5d9af527cd4..2d1e98ec1b8 100644
--- a/crates/router/src/types/domain/address.rs
+++ b/crates/router/src/types/domain/address.rs
@@ -4,30 +4,38 @@ use common_utils::{
     date_time,
     encryption::Encryption,
     errors::{CustomResult, ValidationError},
-    id_type, type_name,
+    id_type, pii, type_name,
     types::keymanager::{Identifier, KeyManagerState, ToEncryptable},
 };
 use diesel_models::{address::AddressUpdateInternal, enums};
 use error_stack::ResultExt;
-use masking::{PeekInterface, Secret};
+use masking::{PeekInterface, Secret, SwitchStrategy};
 use rustc_hash::FxHashMap;
 use time::{OffsetDateTime, PrimitiveDateTime};
 
 use super::{behaviour, types};
 
-#[derive(Clone, Debug, serde::Serialize)]
+#[derive(Clone, Debug, serde::Serialize, router_derive::ToEncryption)]
 pub struct Address {
     pub address_id: String,
     pub city: Option<String>,
     pub country: Option<enums::CountryAlpha2>,
-    pub line1: crypto::OptionalEncryptableSecretString,
-    pub line2: crypto::OptionalEncryptableSecretString,
-    pub line3: crypto::OptionalEncryptableSecretString,
-    pub state: crypto::OptionalEncryptableSecretString,
-    pub zip: crypto::OptionalEncryptableSecretString,
-    pub first_name: crypto::OptionalEncryptableSecretString,
-    pub last_name: crypto::OptionalEncryptableSecretString,
-    pub phone_number: crypto::OptionalEncryptableSecretString,
+    #[encrypt]
+    pub line1: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub line2: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub line3: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub state: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub zip: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub first_name: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub last_name: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub phone_number: Option<Encryptable<Secret<String>>>,
     pub country_code: Option<String>,
     #[serde(skip_serializing)]
     #[serde(with = "custom_serde::iso8601")]
@@ -37,7 +45,8 @@ pub struct Address {
     pub modified_at: PrimitiveDateTime,
     pub merchant_id: id_type::MerchantId,
     pub updated_by: String,
-    pub email: crypto::OptionalEncryptableEmail,
+    #[encrypt]
+    pub email: Option<Encryptable<Secret<String, pii::EmailStrategy>>>,
 }
 
 /// Based on the flow, appropriate address has to be used
@@ -191,8 +200,18 @@ impl behaviour::Conversion for Address {
         let decrypted: FxHashMap<String, Encryptable<Secret<String>>> = types::crypto_operation(
             state,
             type_name!(Self::DstType),
-            types::CryptoOperation::BatchDecrypt(diesel_models::Address::to_encryptable(
-                other.clone(),
+            types::CryptoOperation::BatchDecrypt(EncryptedAddress::to_encryptable(
+                EncryptedAddress {
+                    line1: other.line1,
+                    line2: other.line2,
+                    line3: other.line3,
+                    state: other.state,
+                    zip: other.zip,
+                    first_name: other.first_name,
+                    last_name: other.last_name,
+                    phone_number: other.phone_number,
+                    email: other.email,
+                },
             )),
             identifier.clone(),
             key.peek(),
@@ -202,10 +221,11 @@ impl behaviour::Conversion for Address {
         .change_context(ValidationError::InvalidValue {
             message: "Failed while decrypting".to_string(),
         })?;
-        let encryptable_address = diesel_models::Address::from_encryptable(decrypted)
-            .change_context(ValidationError::InvalidValue {
+        let encryptable_address = EncryptedAddress::from_encryptable(decrypted).change_context(
+            ValidationError::InvalidValue {
                 message: "Failed while decrypting".to_string(),
-            })?;
+            },
+        )?;
         Ok(Self {
             address_id: other.address_id,
             city: other.city,
@@ -223,7 +243,13 @@ impl behaviour::Conversion for Address {
             modified_at: other.modified_at,
             updated_by: other.updated_by,
             merchant_id: other.merchant_id,
-            email: encryptable_address.email,
+            email: encryptable_address.email.map(|email| {
+                let encryptable: Encryptable<Secret<String, pii::EmailStrategy>> = Encryptable::new(
+                    email.clone().into_inner().switch_strategy(),
+                    email.into_encrypted(),
+                );
+                encryptable
+            }),
         })
     }
 
diff --git a/crates/router/src/types/domain/event.rs b/crates/router/src/types/domain/event.rs
index badbb9df7b4..db2d7530164 100644
--- a/crates/router/src/types/domain/event.rs
+++ b/crates/router/src/types/domain/event.rs
@@ -1,22 +1,23 @@
 use common_utils::{
-    crypto::OptionalEncryptableSecretString,
+    crypto::{Encryptable, OptionalEncryptableSecretString},
+    encryption::Encryption,
     type_name,
     types::keymanager::{KeyManagerState, ToEncryptable},
 };
 use diesel_models::{
     enums::{EventClass, EventObjectType, EventType, WebhookDeliveryAttempt},
     events::{EventMetadata, EventUpdateInternal},
-    EventWithEncryption,
 };
 use error_stack::ResultExt;
 use masking::{PeekInterface, Secret};
+use rustc_hash::FxHashMap;
 
 use crate::{
     errors::{CustomResult, ValidationError},
     types::domain::types,
 };
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, router_derive::ToEncryption)]
 pub struct Event {
     pub event_id: String,
     pub event_type: EventType,
@@ -30,8 +31,10 @@ pub struct Event {
     pub primary_object_created_at: Option<time::PrimitiveDateTime>,
     pub idempotent_event_id: Option<String>,
     pub initial_attempt_id: Option<String>,
-    pub request: OptionalEncryptableSecretString,
-    pub response: OptionalEncryptableSecretString,
+    #[encrypt]
+    pub request: Option<Encryptable<Secret<String>>>,
+    #[encrypt]
+    pub response: Option<Encryptable<Secret<String>>>,
     pub delivery_attempt: Option<WebhookDeliveryAttempt>,
     pub metadata: Option<EventMetadata>,
 }
@@ -96,12 +99,10 @@ impl super::behaviour::Conversion for Event {
         let decrypted = types::crypto_operation(
             state,
             type_name!(Self::DstType),
-            types::CryptoOperation::BatchDecrypt(EventWithEncryption::to_encryptable(
-                EventWithEncryption {
-                    request: item.request.clone(),
-                    response: item.response.clone(),
-                },
-            )),
+            types::CryptoOperation::BatchDecrypt(EncryptedEvent::to_encryptable(EncryptedEvent {
+                request: item.request.clone(),
+                response: item.response.clone(),
+            })),
             key_manager_identifier,
             key.peek(),
         )
@@ -110,7 +111,7 @@ impl super::behaviour::Conversion for Event {
         .change_context(ValidationError::InvalidValue {
             message: "Failed while decrypting event data".to_string(),
         })?;
-        let encryptable_event = EventWithEncryption::from_encryptable(decrypted).change_context(
+        let encryptable_event = EncryptedEvent::from_encryptable(decrypted).change_context(
             ValidationError::InvalidValue {
                 message: "Failed while decrypting event data".to_string(),
             },
diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs
index f56a741dc1a..515c9a94ce8 100644
--- a/crates/router/src/utils.rs
+++ b/crates/router/src/utils.rs
@@ -13,8 +13,6 @@ pub mod user_role;
 pub mod verify_connector;
 use std::fmt::Debug;
 
-#[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
-use api_models::payments::AddressDetailsWithPhone;
 use api_models::{
     enums,
     payments::{self},
@@ -22,10 +20,10 @@ use api_models::{
 };
 use common_utils::types::keymanager::KeyManagerState;
 pub use common_utils::{
-    crypto,
+    crypto::{self, Encryptable},
     ext_traits::{ByteSliceExt, BytesExt, Encode, StringExt, ValueExt},
     fp_utils::when,
-    id_type,
+    id_type, pii,
     validation::validate_email,
 };
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
@@ -38,6 +36,7 @@ pub use hyperswitch_connectors::utils::QrImage;
 use hyperswitch_domain_models::payments::PaymentIntent;
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
 use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation};
+use masking::{ExposeInterface, SwitchStrategy};
 use nanoid::nanoid;
 use router_env::metrics::add_attributes;
 use serde::de::DeserializeOwned;
@@ -779,20 +778,32 @@ impl CustomerAddress for api_models::customers::CustomerRequest {
         let encrypted_data = crypto_operation(
             &state.into(),
             type_name!(storage::Address),
-            CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable(
-                AddressDetailsWithPhone {
-                    address: Some(address_details.clone()),
+            CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable(
+                domain::FromRequestEncryptableAddress {
+                    line1: address_details.line1.clone(),
+                    line2: address_details.line2.clone(),
+                    line3: address_details.line3.clone(),
+                    state: address_details.state.clone(),
+                    first_name: address_details.first_name.clone(),
+                    last_name: address_details.last_name.clone(),
+                    zip: address_details.zip.clone(),
                     phone_number: self.phone.clone(),
-                    email: self.email.clone(),
+                    email: self
+                        .email
+                        .as_ref()
+                        .map(|a| a.clone().expose().switch_strategy()),
                 },
             )),
-            Identifier::Merchant(merchant_id),
+            Identifier::Merchant(merchant_id.to_owned()),
             key,
         )
         .await
         .and_then(|val| val.try_into_batchoperation())?;
-        let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data)
-            .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
+
+        let encryptable_address =
+            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
+                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
+
         Ok(storage::AddressUpdate::Update {
             city: address_details.city,
             country: address_details.country,
@@ -806,7 +817,14 @@ impl CustomerAddress for api_models::customers::CustomerRequest {
             phone_number: encryptable_address.phone_number,
             country_code: self.phone_country_code.clone(),
             updated_by: storage_scheme.to_string(),
-            email: encryptable_address.email,
+            email: encryptable_address.email.map(|email| {
+                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
+                    Encryptable::new(
+                        email.clone().into_inner().switch_strategy(),
+                        email.into_encrypted(),
+                    );
+                encryptable
+            }),
         })
     }
 
@@ -822,11 +840,20 @@ impl CustomerAddress for api_models::customers::CustomerRequest {
         let encrypted_data = crypto_operation(
             &state.into(),
             type_name!(storage::Address),
-            CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable(
-                AddressDetailsWithPhone {
-                    address: Some(address_details.clone()),
+            CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable(
+                domain::FromRequestEncryptableAddress {
+                    line1: address_details.line1.clone(),
+                    line2: address_details.line2.clone(),
+                    line3: address_details.line3.clone(),
+                    state: address_details.state.clone(),
+                    first_name: address_details.first_name.clone(),
+                    last_name: address_details.last_name.clone(),
+                    zip: address_details.zip.clone(),
                     phone_number: self.phone.clone(),
-                    email: self.email.clone(),
+                    email: self
+                        .email
+                        .as_ref()
+                        .map(|a| a.clone().expose().switch_strategy()),
                 },
             )),
             Identifier::Merchant(merchant_id.to_owned()),
@@ -834,8 +861,11 @@ impl CustomerAddress for api_models::customers::CustomerRequest {
         )
         .await
         .and_then(|val| val.try_into_batchoperation())?;
-        let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data)
-            .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
+
+        let encryptable_address =
+            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
+                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
+
         let address = domain::Address {
             city: address_details.city,
             country: address_details.country,
@@ -853,7 +883,14 @@ impl CustomerAddress for api_models::customers::CustomerRequest {
             created_at: common_utils::date_time::now(),
             modified_at: common_utils::date_time::now(),
             updated_by: storage_scheme.to_string(),
-            email: encryptable_address.email,
+            email: encryptable_address.email.map(|email| {
+                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
+                    Encryptable::new(
+                        email.clone().into_inner().switch_strategy(),
+                        email.into_encrypted(),
+                    );
+                encryptable
+            }),
         };
 
         Ok(domain::CustomerAddress {
@@ -877,20 +914,31 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest {
         let encrypted_data = crypto_operation(
             &state.into(),
             type_name!(storage::Address),
-            CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable(
-                AddressDetailsWithPhone {
-                    address: Some(address_details.clone()),
+            CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable(
+                domain::FromRequestEncryptableAddress {
+                    line1: address_details.line1.clone(),
+                    line2: address_details.line2.clone(),
+                    line3: address_details.line3.clone(),
+                    state: address_details.state.clone(),
+                    first_name: address_details.first_name.clone(),
+                    last_name: address_details.last_name.clone(),
+                    zip: address_details.zip.clone(),
                     phone_number: self.phone.clone(),
-                    email: self.email.clone(),
+                    email: self
+                        .email
+                        .as_ref()
+                        .map(|a| a.clone().expose().switch_strategy()),
                 },
             )),
-            Identifier::Merchant(merchant_id),
+            Identifier::Merchant(merchant_id.to_owned()),
             key,
         )
         .await
         .and_then(|val| val.try_into_batchoperation())?;
-        let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data)
-            .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
+
+        let encryptable_address =
+            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
+                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
         Ok(storage::AddressUpdate::Update {
             city: address_details.city,
             country: address_details.country,
@@ -904,7 +952,14 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest {
             phone_number: encryptable_address.phone_number,
             country_code: self.phone_country_code.clone(),
             updated_by: storage_scheme.to_string(),
-            email: encryptable_address.email,
+            email: encryptable_address.email.map(|email| {
+                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
+                    Encryptable::new(
+                        email.clone().into_inner().switch_strategy(),
+                        email.into_encrypted(),
+                    );
+                encryptable
+            }),
         })
     }
 
@@ -920,11 +975,20 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest {
         let encrypted_data = crypto_operation(
             &state.into(),
             type_name!(storage::Address),
-            CryptoOperation::BatchEncrypt(AddressDetailsWithPhone::to_encryptable(
-                AddressDetailsWithPhone {
-                    address: Some(address_details.clone()),
+            CryptoOperation::BatchEncrypt(domain::FromRequestEncryptableAddress::to_encryptable(
+                domain::FromRequestEncryptableAddress {
+                    line1: address_details.line1.clone(),
+                    line2: address_details.line2.clone(),
+                    line3: address_details.line3.clone(),
+                    state: address_details.state.clone(),
+                    first_name: address_details.first_name.clone(),
+                    last_name: address_details.last_name.clone(),
+                    zip: address_details.zip.clone(),
                     phone_number: self.phone.clone(),
-                    email: self.email.clone(),
+                    email: self
+                        .email
+                        .as_ref()
+                        .map(|a| a.clone().expose().switch_strategy()),
                 },
             )),
             Identifier::Merchant(merchant_id.to_owned()),
@@ -932,8 +996,10 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest {
         )
         .await
         .and_then(|val| val.try_into_batchoperation())?;
-        let encryptable_address = AddressDetailsWithPhone::from_encryptable(encrypted_data)
-            .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
+
+        let encryptable_address =
+            domain::FromRequestEncryptableAddress::from_encryptable(encrypted_data)
+                .change_context(common_utils::errors::CryptoError::EncodingFailed)?;
         let address = domain::Address {
             city: address_details.city,
             country: address_details.country,
@@ -951,7 +1017,14 @@ impl CustomerAddress for api_models::customers::CustomerUpdateRequest {
             created_at: common_utils::date_time::now(),
             modified_at: common_utils::date_time::now(),
             updated_by: storage_scheme.to_string(),
-            email: encryptable_address.email,
+            email: encryptable_address.email.map(|email| {
+                let encryptable: Encryptable<masking::Secret<String, pii::EmailStrategy>> =
+                    Encryptable::new(
+                        email.clone().into_inner().switch_strategy(),
+                        email.into_encrypted(),
+                    );
+                encryptable
+            }),
         };
 
         Ok(domain::CustomerAddress {
diff --git a/crates/router_derive/src/lib.rs b/crates/router_derive/src/lib.rs
index 69865512a37..33edd5e215e 100644
--- a/crates/router_derive/src/lib.rs
+++ b/crates/router_derive/src/lib.rs
@@ -644,6 +644,7 @@ pub fn try_get_enum_variant(input: proc_macro::TokenStream) -> proc_macro::Token
 ///     ("address.zip", "941222"),
 ///     ("email", "test@example.com"),
 /// ]
+///
 #[proc_macro_derive(FlatStruct)]
 pub fn flat_struct_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
     let input = parse_macro_input!(input as syn::DeriveInput);
@@ -749,3 +750,18 @@ pub fn flat_struct_derive(input: proc_macro::TokenStream) -> proc_macro::TokenSt
 pub fn generate_permissions(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
     macros::generate_permissions_inner(input)
 }
+
+/// Generates the ToEncryptable trait for a type
+///
+/// This macro generates the temporary structs which has the fields that needs to be encrypted
+///
+/// fn to_encryptable: Convert the temp struct to a hashmap that can be sent over the network
+/// fn from_encryptable: Convert the hashmap back to temp struct
+#[proc_macro_derive(ToEncryption, attributes(encrypt))]
+pub fn derive_to_encryption_attr(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let input = syn::parse_macro_input!(input as syn::DeriveInput);
+
+    macros::derive_to_encryption(input)
+        .unwrap_or_else(|err| err.into_compile_error())
+        .into()
+}
diff --git a/crates/router_derive/src/macros.rs b/crates/router_derive/src/macros.rs
index 32e6c213ca6..e227c6533e9 100644
--- a/crates/router_derive/src/macros.rs
+++ b/crates/router_derive/src/macros.rs
@@ -4,6 +4,7 @@ pub(crate) mod generate_permissions;
 pub(crate) mod generate_schema;
 pub(crate) mod misc;
 pub(crate) mod operation;
+pub(crate) mod to_encryptable;
 pub(crate) mod try_get_enum;
 
 mod helpers;
@@ -17,6 +18,7 @@ pub(crate) use self::{
     diesel::{diesel_enum_derive_inner, diesel_enum_text_derive_inner},
     generate_permissions::generate_permissions_inner,
     generate_schema::polymorphic_macro_derive_inner,
+    to_encryptable::derive_to_encryption,
 };
 
 pub(crate) fn debug_as_display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
diff --git a/crates/router_derive/src/macros/to_encryptable.rs b/crates/router_derive/src/macros/to_encryptable.rs
new file mode 100644
index 00000000000..dfcfb72169b
--- /dev/null
+++ b/crates/router_derive/src/macros/to_encryptable.rs
@@ -0,0 +1,326 @@
+use std::iter::Iterator;
+
+use quote::{format_ident, quote};
+use syn::{parse::Parse, punctuated::Punctuated, token::Comma, Field, Ident, Type as SynType};
+
+use crate::macros::{helpers::get_struct_fields, misc::get_field_type};
+
+pub struct FieldMeta {
+    _meta_type: Ident,
+    pub value: Ident,
+}
+
+impl Parse for FieldMeta {
+    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
+        let _meta_type: Ident = input.parse()?;
+        input.parse::<syn::Token![=]>()?;
+        let value: Ident = input.parse()?;
+        Ok(Self { _meta_type, value })
+    }
+}
+
+impl quote::ToTokens for FieldMeta {
+    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
+        self.value.to_tokens(tokens);
+    }
+}
+
+fn get_encryption_ty_meta(field: &Field) -> Option<FieldMeta> {
+    let attrs = &field.attrs;
+
+    attrs
+        .iter()
+        .flat_map(|s| s.parse_args::<FieldMeta>())
+        .find(|s| s._meta_type.eq("ty"))
+}
+
+fn get_inner_type(path: &syn::TypePath) -> syn::Result<syn::TypePath> {
+    path.path
+        .segments
+        .last()
+        .and_then(|segment| match &segment.arguments {
+            syn::PathArguments::AngleBracketed(args) => args.args.first(),
+            _ => None,
+        })
+        .and_then(|arg| match arg {
+            syn::GenericArgument::Type(SynType::Path(path)) => Some(path.clone()),
+            _ => None,
+        })
+        .ok_or_else(|| {
+            syn::Error::new(
+                proc_macro2::Span::call_site(),
+                "Only path fields are supported",
+            )
+        })
+}
+
+/// This function returns the inner most type recursively
+/// For example:
+///
+/// In the case of `Encryptable<Secret<String>>> this returns String
+fn get_inner_most_type(ty: SynType) -> syn::Result<Ident> {
+    fn get_inner_type_recursive(path: syn::TypePath) -> syn::Result<syn::TypePath> {
+        match get_inner_type(&path) {
+            Ok(inner_path) => get_inner_type_recursive(inner_path),
+            Err(_) => Ok(path),
+        }
+    }
+
+    match ty {
+        SynType::Path(path) => {
+            let inner_path = get_inner_type_recursive(path)?;
+            inner_path
+                .path
+                .segments
+                .last()
+                .map(|last_segment| last_segment.ident.to_owned())
+                .ok_or_else(|| {
+                    syn::Error::new(
+                        proc_macro2::Span::call_site(),
+                        "At least one ident must be specified",
+                    )
+                })
+        }
+        _ => Err(syn::Error::new(
+            proc_macro2::Span::call_site(),
+            "Only path fields are supported",
+        )),
+    }
+}
+
+/// This returns the field which implement #[encrypt] attribute
+fn get_encryptable_fields(fields: Punctuated<Field, Comma>) -> Vec<Field> {
+    fields
+        .into_iter()
+        .filter(|field| {
+            field
+                .attrs
+                .iter()
+                .any(|attr| attr.path().is_ident("encrypt"))
+        })
+        .collect()
+}
+
+/// This function returns the inner most type of a field
+fn get_field_and_inner_types(fields: &[Field]) -> Vec<(Field, Ident)> {
+    fields
+        .iter()
+        .flat_map(|field| {
+            get_inner_most_type(field.ty.clone()).map(|field_name| (field.to_owned(), field_name))
+        })
+        .collect()
+}
+
+/// The type of the struct for which the batch encryption/decryption needs to be implemented
+#[derive(PartialEq, Copy, Clone)]
+enum StructType {
+    Encrypted,
+    Decrypted,
+    DecryptedUpdate,
+    FromRequest,
+    Updated,
+}
+
+impl StructType {
+    /// Generates the fields for temporary structs which consists of the fields that should be
+    /// encrypted/decrypted
+    fn generate_struct_fields(&self, fields: &[(Field, Ident)]) -> Vec<proc_macro2::TokenStream> {
+        fields
+            .iter()
+            .map(|(field, inner_ty)| {
+                let provided_ty = get_encryption_ty_meta(field);
+                let is_option = get_field_type(field.ty.clone())
+                    .map(|f| f.eq("Option"))
+                    .unwrap_or_default();
+                let ident = &field.ident;
+                let inner_ty = if let Some(ref ty) = provided_ty {
+                    &ty.value
+                } else {
+                    inner_ty
+                };
+                match (self, is_option) {
+                    (Self::Encrypted, true) => quote! { pub #ident: Option<Encryption> },
+                    (Self::Encrypted, false) => quote! { pub #ident: Encryption },
+                    (Self::Decrypted, true) => {
+                        quote! { pub #ident: Option<Encryptable<Secret<#inner_ty>>> }
+                    }
+                    (Self::Decrypted, false) => {
+                        quote! { pub #ident: Encryptable<Secret<#inner_ty>> }
+                    }
+                    (Self::DecryptedUpdate, _) => {
+                        quote! { pub #ident: Option<Encryptable<Secret<#inner_ty>>> }
+                    }
+                    (Self::FromRequest, true) => {
+                        quote! { pub #ident: Option<Secret<#inner_ty>> }
+                    }
+                    (Self::FromRequest, false) => quote! { pub #ident: Secret<#inner_ty> },
+                    (Self::Updated, _) => quote! { pub #ident: Option<Secret<#inner_ty>> },
+                }
+            })
+            .collect()
+    }
+
+    /// Generates the ToEncryptable trait implementation
+    fn generate_impls(
+        &self,
+        gen1: proc_macro2::TokenStream,
+        gen2: proc_macro2::TokenStream,
+        gen3: proc_macro2::TokenStream,
+        impl_st: proc_macro2::TokenStream,
+        inner: &[Field],
+    ) -> proc_macro2::TokenStream {
+        let map_length = inner.len();
+
+        let to_encryptable_impl = inner.iter().flat_map(|field| {
+            get_field_type(field.ty.clone()).map(|field_ty| {
+                let is_option = field_ty.eq("Option");
+                let field_ident = &field.ident;
+                let field_ident_string = field_ident.as_ref().map(|s| s.to_string());
+
+                if is_option || *self == Self::Updated {
+                    quote! { self.#field_ident.map(|s| map.insert(#field_ident_string.to_string(), s)) }
+                } else {
+                    quote! { map.insert(#field_ident_string.to_string(), self.#field_ident) }
+                }
+            })
+        });
+
+        let from_encryptable_impl = inner.iter().flat_map(|field| {
+            get_field_type(field.ty.clone()).map(|field_ty| {
+                let is_option = field_ty.eq("Option");
+                let field_ident = &field.ident;
+                let field_ident_string = field_ident.as_ref().map(|s| s.to_string());
+
+                if is_option || *self == Self::Updated {
+                    quote! { #field_ident: map.remove(#field_ident_string) }
+                } else {
+                    quote! {
+                        #field_ident: map.remove(#field_ident_string).ok_or(
+                            error_stack::report!(common_utils::errors::ParsingError::EncodeError(
+                                "Unable to convert from HashMap",
+                            ))
+                        )?
+                    }
+                }
+            })
+        });
+
+        quote! {
+            impl ToEncryptable<#gen1, #gen2, #gen3> for #impl_st {
+                fn to_encryptable(self) -> FxHashMap<String, #gen3> {
+                    let mut map = FxHashMap::with_capacity_and_hasher(#map_length, Default::default());
+                    #(#to_encryptable_impl;)*
+                    map
+                }
+
+                fn from_encryptable(
+                    mut map: FxHashMap<String, Encryptable<#gen2>>,
+                ) -> CustomResult<#gen1, common_utils::errors::ParsingError> {
+                    Ok(#gen1 {
+                        #(#from_encryptable_impl,)*
+                    })
+                }
+            }
+        }
+    }
+}
+
+/// This function generates the temporary struct and ToEncryptable impls for the temporary structs
+fn generate_to_encryptable(
+    struct_name: Ident,
+    fields: Vec<Field>,
+) -> syn::Result<proc_macro2::TokenStream> {
+    let struct_types = [
+        // The first two are to be used as return types we do not need to implement ToEncryptable
+        // on it
+        ("Decrypted", StructType::Decrypted),
+        ("DecryptedUpdate", StructType::DecryptedUpdate),
+        ("FromRequestEncryptable", StructType::FromRequest),
+        ("Encrypted", StructType::Encrypted),
+        ("UpdateEncryptable", StructType::Updated),
+    ];
+
+    let inner_types = get_field_and_inner_types(&fields);
+
+    let inner_type = inner_types.first().map(|(_, ty)| ty).ok_or_else(|| {
+        syn::Error::new(
+            proc_macro2::Span::call_site(),
+            "Please use the macro with attribute #[encrypt] on the fields you want to encrypt",
+        )
+    })?;
+
+    let structs = struct_types.iter().map(|(prefix, struct_type)| {
+        let name = format_ident!("{}{}", prefix, struct_name);
+        let temp_fields = struct_type.generate_struct_fields(&inner_types);
+        quote! {
+            pub struct #name {
+                #(#temp_fields,)*
+            }
+        }
+    });
+
+    // These implementations shouldn't be implemented Decrypted and DecryptedUpdate temp structs
+    // So skip the first two entries in the list
+    let impls = struct_types
+        .iter()
+        .skip(2)
+        .map(|(prefix, struct_type)| {
+            let name = format_ident!("{}{}", prefix, struct_name);
+
+            let impl_block = if *struct_type != StructType::DecryptedUpdate
+                || *struct_type != StructType::Decrypted
+            {
+                let (gen1, gen2, gen3) = match struct_type {
+                    StructType::FromRequest => {
+                        let decrypted_name = format_ident!("Decrypted{}", struct_name);
+                        (
+                            quote! { #decrypted_name },
+                            quote! { Secret<#inner_type> },
+                            quote! { Secret<#inner_type> },
+                        )
+                    }
+                    StructType::Encrypted => {
+                        let decrypted_name = format_ident!("Decrypted{}", struct_name);
+                        (
+                            quote! { #decrypted_name },
+                            quote! { Secret<#inner_type> },
+                            quote! { Encryption },
+                        )
+                    }
+                    StructType::Updated => {
+                        let decrypted_update_name = format_ident!("DecryptedUpdate{}", struct_name);
+                        (
+                            quote! { #decrypted_update_name },
+                            quote! { Secret<#inner_type> },
+                            quote! { Secret<#inner_type> },
+                        )
+                    }
+                    //Unreachable statement
+                    _ => (quote! {}, quote! {}, quote! {}),
+                };
+
+                struct_type.generate_impls(gen1, gen2, gen3, quote! { #name }, &fields)
+            } else {
+                quote! {}
+            };
+
+            Ok(quote! {
+                #impl_block
+            })
+        })
+        .collect::<syn::Result<Vec<_>>>()?;
+
+    Ok(quote! {
+        #(#structs)*
+        #(#impls)*
+    })
+}
+
+pub fn derive_to_encryption(
+    input: syn::DeriveInput,
+) -> Result<proc_macro2::TokenStream, syn::Error> {
+    let struct_name = input.ident;
+    let fields = get_encryptable_fields(get_struct_fields(input.data)?);
+
+    generate_to_encryptable(struct_name, fields)
+}

## Type of Change
<!-- Put an `x` in the boxes that apply -->
- [x] Enhancement

## Description
<!-- Describe your changes in detail -->
This PR adds a macro to generate ToEncryptable trait on different types

## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->
This PR removes the effort of repetitively implementing ToEncryptable trait which is used for batch encryption/decryption in the encryption service by adding a macro which generates code upon deriving it

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
**THIS CANNOT BE TESTED ON SANDBOX**
- Compiler guided. Since this does not change any core flow
- Basic test of MerchantCreate and Payments for sanity

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code