Bug: Add debit routing support for apple pay



In the Apple Pay decryption flow, if debit routing is enabled by the merchant and the card type is debit, a call will be made to the decision engine to retrieve the supported card networks and the potential debit routing savings. Among these networks, the lowest-cost network will be selected to process the Apple Pay payment.
diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs
index 49f6d15a6da..687e42728f2 100644
--- a/crates/common_enums/src/enums.rs
+++ b/crates/common_enums/src/enums.rs
@@ -190,6 +190,30 @@ impl AttemptStatus {
     }
 }
 
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    Hash,
+    Eq,
+    PartialEq,
+    serde::Deserialize,
+    serde::Serialize,
+    strum::Display,
+    strum::EnumString,
+    strum::EnumIter,
+    ToSchema,
+)]
+#[router_derive::diesel_enum(storage_type = "db_enum")]
+#[serde(rename_all = "snake_case")]
+#[strum(serialize_all = "snake_case")]
+pub enum ApplePayPaymentMethodType {
+    Debit,
+    Credit,
+    Prepaid,
+    Store,
+}
+
 /// Indicates the method by which a card is discovered during a payment
 #[derive(
     Clone,
diff --git a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs
index bafbc7920af..d972c958b71 100644
--- a/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs
@@ -2218,7 +2218,7 @@ impl TryFrom<(&WalletData, &PaymentsAuthorizeRouterData)> for AdyenPaymentMethod
                         number: apple_pay_decrypte.application_primary_account_number,
                         expiry_month: exp_month,
                         expiry_year: expiry_year_4_digit,
-                        brand: "applepay".to_string(),
+                        brand: data.payment_method.network.clone(),
                         payment_type: PaymentType::Scheme,
                     };
                     Ok(AdyenPaymentMethod::ApplePayDecrypt(Box::new(
diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs
index 0a5ca7705b8..f2f86479362 100644
--- a/crates/hyperswitch_domain_models/src/payment_method_data.rs
+++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs
@@ -10,6 +10,7 @@ use common_enums::enums as api_enums;
 #[cfg(feature = "v2")]
 use common_utils::ext_traits::OptionExt;
 use common_utils::{
+    ext_traits::StringExt,
     id_type,
     new_type::{
         MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode, MaskedUpiVpaId,
@@ -75,6 +76,14 @@ impl PaymentMethodData {
         }
     }
 
+    pub fn get_wallet_data(&self) -> Option<&WalletData> {
+        if let Self::Wallet(wallet_data) = self {
+            Some(wallet_data)
+        } else {
+            None
+        }
+    }
+
     pub fn is_network_token_payment_method_data(&self) -> bool {
         matches!(self, Self::NetworkToken(_))
     }
@@ -263,6 +272,32 @@ pub enum WalletData {
     RevolutPay(RevolutPayData),
 }
 
+impl WalletData {
+    pub fn get_paze_wallet_data(&self) -> Option<&PazeWalletData> {
+        if let Self::Paze(paze_wallet_data) = self {
+            Some(paze_wallet_data)
+        } else {
+            None
+        }
+    }
+
+    pub fn get_apple_pay_wallet_data(&self) -> Option<&ApplePayWalletData> {
+        if let Self::ApplePay(apple_pay_wallet_data) = self {
+            Some(apple_pay_wallet_data)
+        } else {
+            None
+        }
+    }
+
+    pub fn get_google_pay_wallet_data(&self) -> Option<&GooglePayWalletData> {
+        if let Self::GooglePay(google_pay_wallet_data) = self {
+            Some(google_pay_wallet_data)
+        } else {
+            None
+        }
+    }
+}
+
 #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)]
 pub struct MifinityData {
     pub date_of_birth: Secret<Date>,
@@ -432,6 +467,26 @@ pub struct ApplePayWalletData {
     pub transaction_identifier: String,
 }
 
+impl ApplePayWalletData {
+    pub fn get_payment_method_type(&self) -> Option<api_enums::PaymentMethodType> {
+        self.payment_method
+            .pm_type
+            .clone()
+            .parse_enum("ApplePayPaymentMethodType")
+            .ok()
+            .and_then(|payment_type| match payment_type {
+                common_enums::ApplePayPaymentMethodType::Debit => {
+                    Some(api_enums::PaymentMethodType::Debit)
+                }
+                common_enums::ApplePayPaymentMethodType::Credit => {
+                    Some(api_enums::PaymentMethodType::Credit)
+                }
+                common_enums::ApplePayPaymentMethodType::Prepaid
+                | common_enums::ApplePayPaymentMethodType::Store => None,
+            })
+    }
+}
+
 #[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize)]
 pub struct ApplepayPaymentMethod {
     pub display_name: String,
diff --git a/crates/router/src/core/debit_routing.rs b/crates/router/src/core/debit_routing.rs
index 651f1ea04c3..0aeb2b9777b 100644
--- a/crates/router/src/core/debit_routing.rs
+++ b/crates/router/src/core/debit_routing.rs
@@ -6,7 +6,7 @@ use common_utils::{
     errors::CustomResult, ext_traits::ValueExt, id_type, types::keymanager::KeyManagerState,
 };
 use error_stack::ResultExt;
-use masking::Secret;
+use masking::{PeekInterface, Secret};
 
 use super::{
     payments::{OperationSessionGetters, OperationSessionSetters},
@@ -157,33 +157,76 @@ where
     match format!("{operation:?}").as_str() {
         "PaymentConfirm" => {
             logger::info!("Checking if debit routing is required");
-            let payment_intent = payment_data.get_payment_intent();
-            let payment_attempt = payment_data.get_payment_attempt();
 
-            request_validation(payment_intent, payment_attempt, debit_routing_config)
+            request_validation(payment_data, debit_routing_config)
         }
         _ => false,
     }
 }
 
-pub fn request_validation(
-    payment_intent: &hyperswitch_domain_models::payments::PaymentIntent,
-    payment_attempt: &hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt,
+fn request_validation<F: Clone, D>(
+    payment_data: &D,
     debit_routing_config: &settings::DebitRoutingConfig,
-) -> bool {
-    logger::debug!("Validating request for debit routing");
-    let is_currency_supported = payment_intent.currency.map(|currency| {
-        debit_routing_config
-            .supported_currencies
-            .contains(&currency)
-    });
+) -> bool
+where
+    D: OperationSessionGetters<F> + Send + Sync + Clone,
+{
+    let payment_intent = payment_data.get_payment_intent();
+    let payment_attempt = payment_data.get_payment_attempt();
+
+    let is_currency_supported = is_currency_supported(payment_intent, debit_routing_config);
+
+    let is_valid_payment_method = validate_payment_method_for_debit_routing(payment_data);
 
     payment_intent.setup_future_usage != Some(enums::FutureUsage::OffSession)
         && payment_intent.amount.is_greater_than(0)
-        && is_currency_supported == Some(true)
-        && payment_attempt.authentication_type != Some(enums::AuthenticationType::ThreeDs)
-        && payment_attempt.payment_method == Some(enums::PaymentMethod::Card)
-        && payment_attempt.payment_method_type == Some(enums::PaymentMethodType::Debit)
+        && is_currency_supported
+        && payment_attempt.authentication_type == Some(enums::AuthenticationType::NoThreeDs)
+        && is_valid_payment_method
+}
+
+fn is_currency_supported(
+    payment_intent: &hyperswitch_domain_models::payments::PaymentIntent,
+    debit_routing_config: &settings::DebitRoutingConfig,
+) -> bool {
+    payment_intent
+        .currency
+        .map(|currency| {
+            debit_routing_config
+                .supported_currencies
+                .contains(&currency)
+        })
+        .unwrap_or(false)
+}
+
+fn validate_payment_method_for_debit_routing<F: Clone, D>(payment_data: &D) -> bool
+where
+    D: OperationSessionGetters<F> + Send + Sync + Clone,
+{
+    let payment_attempt = payment_data.get_payment_attempt();
+    match payment_attempt.payment_method {
+        Some(enums::PaymentMethod::Card) => {
+            payment_attempt.payment_method_type == Some(enums::PaymentMethodType::Debit)
+        }
+        Some(enums::PaymentMethod::Wallet) => {
+            payment_attempt.payment_method_type == Some(enums::PaymentMethodType::ApplePay)
+                && payment_data
+                    .get_payment_method_data()
+                    .and_then(|data| data.get_wallet_data())
+                    .and_then(|data| data.get_apple_pay_wallet_data())
+                    .and_then(|data| data.get_payment_method_type())
+                    == Some(enums::PaymentMethodType::Debit)
+                && matches!(
+                    payment_data.get_payment_method_token().cloned(),
+                    Some(
+                        hyperswitch_domain_models::router_data::PaymentMethodToken::ApplePayDecrypt(
+                            _
+                        )
+                    )
+                )
+        }
+        _ => false,
+    }
 }
 
 pub async fn check_for_debit_routing_connector_in_profile<
@@ -318,8 +361,11 @@ pub async fn get_debit_routing_output<
 ) -> Option<open_router::DebitRoutingOutput> {
     logger::debug!("Fetching sorted card networks");
 
-    let (saved_co_badged_card_data, saved_card_type, card_isin) =
-        extract_saved_card_info(payment_data);
+    let card_info = extract_card_info(payment_data);
+
+    let saved_co_badged_card_data = card_info.co_badged_card_data;
+    let saved_card_type = card_info.card_type;
+    let card_isin = card_info.card_isin;
 
     match (
         saved_co_badged_card_data
@@ -370,48 +416,133 @@ pub async fn get_debit_routing_output<
     }
 }
 
-fn extract_saved_card_info<F, D>(
-    payment_data: &D,
-) -> (
-    Option<api_models::payment_methods::CoBadgedCardData>,
-    Option<String>,
-    Option<Secret<String>>,
-)
+#[derive(Debug, Clone)]
+struct ExtractedCardInfo {
+    co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
+    card_type: Option<String>,
+    card_isin: Option<Secret<String>>,
+}
+
+impl ExtractedCardInfo {
+    fn new(
+        co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
+        card_type: Option<String>,
+        card_isin: Option<Secret<String>>,
+    ) -> Self {
+        Self {
+            co_badged_card_data,
+            card_type,
+            card_isin,
+        }
+    }
+
+    fn empty() -> Self {
+        Self::new(None, None, None)
+    }
+}
+
+fn extract_card_info<F, D>(payment_data: &D) -> ExtractedCardInfo
+where
+    D: OperationSessionGetters<F>,
+{
+    extract_from_saved_payment_method(payment_data)
+        .unwrap_or_else(|| extract_from_payment_method_data(payment_data))
+}
+
+fn extract_from_saved_payment_method<F, D>(payment_data: &D) -> Option<ExtractedCardInfo>
 where
     D: OperationSessionGetters<F>,
 {
-    let payment_method_data_optional = payment_data.get_payment_method_data();
-    match payment_data
-        .get_payment_method_info()
-        .and_then(|info| info.get_payment_methods_data())
+    let payment_methods_data = payment_data
+        .get_payment_method_info()?
+        .get_payment_methods_data()?;
+
+    if let hyperswitch_domain_models::payment_method_data::PaymentMethodsData::Card(card) =
+        payment_methods_data
     {
-        Some(hyperswitch_domain_models::payment_method_data::PaymentMethodsData::Card(card)) => {
-            match (&card.co_badged_card_data, &card.card_isin) {
-                (Some(co_badged), _) => {
-                    logger::debug!("Co-badged card data found in saved payment method");
-                    (Some(co_badged.clone()), card.card_type, None)
-                }
-                (None, Some(card_isin)) => {
-                    logger::debug!("No co-badged data; using saved card ISIN");
-                    (None, None, Some(Secret::new(card_isin.clone())))
-                }
-                _ => (None, None, None),
-            }
+        return Some(extract_card_info_from_saved_card(&card));
+    }
+
+    None
+}
+
+fn extract_card_info_from_saved_card(
+    card: &hyperswitch_domain_models::payment_method_data::CardDetailsPaymentMethod,
+) -> ExtractedCardInfo {
+    match (&card.co_badged_card_data, &card.card_isin) {
+        (Some(co_badged), _) => {
+            logger::debug!("Co-badged card data found in saved payment method");
+            ExtractedCardInfo::new(Some(co_badged.clone()), card.card_type.clone(), None)
         }
-        _ => match payment_method_data_optional {
-            Some(hyperswitch_domain_models::payment_method_data::PaymentMethodData::Card(card)) => {
-                logger::debug!("Using card data from payment request");
-                (
-                    None,
-                    None,
-                    Some(Secret::new(card.card_number.get_card_isin())),
-                )
-            }
-            _ => (None, None, None),
-        },
+        (None, Some(card_isin)) => {
+            logger::debug!("No co-badged data; using saved card ISIN");
+            ExtractedCardInfo::new(None, None, Some(Secret::new(card_isin.clone())))
+        }
+        _ => ExtractedCardInfo::empty(),
+    }
+}
+
+fn extract_from_payment_method_data<F, D>(payment_data: &D) -> ExtractedCardInfo
+where
+    D: OperationSessionGetters<F>,
+{
+    match payment_data.get_payment_method_data() {
+        Some(hyperswitch_domain_models::payment_method_data::PaymentMethodData::Card(card)) => {
+            logger::debug!("Using card data from payment request");
+            ExtractedCardInfo::new(
+                None,
+                None,
+                Some(Secret::new(card.card_number.get_extended_card_bin())),
+            )
+        }
+        Some(hyperswitch_domain_models::payment_method_data::PaymentMethodData::Wallet(
+            wallet_data,
+        )) => extract_from_wallet_data(wallet_data, payment_data),
+        _ => ExtractedCardInfo::empty(),
+    }
+}
+
+fn extract_from_wallet_data<F, D>(
+    wallet_data: &hyperswitch_domain_models::payment_method_data::WalletData,
+    payment_data: &D,
+) -> ExtractedCardInfo
+where
+    D: OperationSessionGetters<F>,
+{
+    match wallet_data {
+        hyperswitch_domain_models::payment_method_data::WalletData::ApplePay(_) => {
+            logger::debug!("Using Apple Pay data from payment request");
+            let apple_pay_isin = extract_apple_pay_isin(payment_data);
+            ExtractedCardInfo::new(None, None, apple_pay_isin)
+        }
+        _ => ExtractedCardInfo::empty(),
     }
 }
 
+fn extract_apple_pay_isin<F, D>(payment_data: &D) -> Option<Secret<String>>
+where
+    D: OperationSessionGetters<F>,
+{
+    payment_data.get_payment_method_token().and_then(|token| {
+        if let hyperswitch_domain_models::router_data::PaymentMethodToken::ApplePayDecrypt(
+            apple_pay_decrypt_data,
+        ) = token
+        {
+            logger::debug!("Using Apple Pay decrypt data from payment method token");
+            Some(Secret::new(
+                apple_pay_decrypt_data
+                    .application_primary_account_number
+                    .peek()
+                    .chars()
+                    .take(8)
+                    .collect::<String>(),
+            ))
+        } else {
+            None
+        }
+    })
+}
+
 async fn handle_retryable_connector<F, D>(
     state: &SessionState,
     debit_routing_supported_connectors: HashSet<api_enums::Connector>,
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index cf45d15a5a1..a8f718e2391 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -613,6 +613,17 @@ where
     )
     .await?;
 
+    let payment_method_token = get_decrypted_wallet_payment_method_token(
+        &operation,
+        state,
+        merchant_context,
+        &mut payment_data,
+        connector.as_ref(),
+    )
+    .await?;
+
+    payment_method_token.map(|token| payment_data.set_payment_method_token(Some(token)));
+
     let (connector, debit_routing_output) = debit_routing::perform_debit_routing(
         &operation,
         state,
@@ -3522,6 +3533,101 @@ impl PaymentRedirectFlow for PaymentAuthenticateCompleteAuthorize {
     }
 }
 
+#[cfg(feature = "v1")]
+pub async fn get_decrypted_wallet_payment_method_token<F, Req, D>(
+    operation: &BoxedOperation<'_, F, Req, D>,
+    state: &SessionState,
+    merchant_context: &domain::MerchantContext,
+    payment_data: &mut D,
+    connector_call_type_optional: Option<&ConnectorCallType>,
+) -> CustomResult<Option<PaymentMethodToken>, errors::ApiErrorResponse>
+where
+    F: Send + Clone + Sync,
+    D: OperationSessionGetters<F> + Send + Sync + Clone,
+{
+    if is_operation_confirm(operation) {
+        let wallet_type = payment_data
+            .get_payment_attempt()
+            .payment_method_type
+            .get_required_value("payment_method_type")?;
+
+        let wallet: Box<dyn WalletFlow<F, D>> = match wallet_type {
+            storage_enums::PaymentMethodType::ApplePay => Box::new(ApplePayWallet),
+            storage_enums::PaymentMethodType::Paze => Box::new(PazeWallet),
+            storage_enums::PaymentMethodType::GooglePay => Box::new(GooglePayWallet),
+            _ => return Ok(None),
+        };
+
+        let merchant_connector_account =
+            get_merchant_connector_account_for_wallet_decryption_flow::<F, D>(
+                state,
+                merchant_context,
+                payment_data,
+                connector_call_type_optional,
+            )
+            .await?;
+
+        let decide_wallet_flow = &wallet
+            .decide_wallet_flow(state, payment_data, &merchant_connector_account)
+            .attach_printable("Failed to decide wallet flow")?
+            .async_map(|payment_proce_data| async move {
+                wallet
+                    .decrypt_wallet_token(&payment_proce_data, payment_data)
+                    .await
+            })
+            .await
+            .transpose()
+            .attach_printable("Failed to decrypt Wallet token")?;
+        Ok(decide_wallet_flow.clone())
+    } else {
+        Ok(None)
+    }
+}
+
+#[cfg(feature = "v1")]
+pub async fn get_merchant_connector_account_for_wallet_decryption_flow<F, D>(
+    state: &SessionState,
+    merchant_context: &domain::MerchantContext,
+    payment_data: &mut D,
+    connector_call_type_optional: Option<&ConnectorCallType>,
+) -> RouterResult<helpers::MerchantConnectorAccountType>
+where
+    F: Send + Clone + Sync,
+    D: OperationSessionGetters<F> + Send + Sync + Clone,
+{
+    let connector_call_type = connector_call_type_optional
+        .get_required_value("connector_call_type")
+        .change_context(errors::ApiErrorResponse::InternalServerError)?;
+    let connector_routing_data = match connector_call_type {
+        ConnectorCallType::PreDetermined(connector_routing_data) => connector_routing_data,
+        ConnectorCallType::Retryable(connector_routing_datas) => connector_routing_datas
+            .first()
+            .ok_or(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Found no connector routing data in retryable call")?,
+        ConnectorCallType::SessionMultiple(_session_connector_datas) => {
+            return Err(errors::ApiErrorResponse::InternalServerError).attach_printable(
+                "SessionMultiple connector call type is invalid in confirm calls",
+            );
+        }
+    };
+
+    construct_profile_id_and_get_mca(
+        state,
+        merchant_context,
+        payment_data,
+        &connector_routing_data
+            .connector_data
+            .connector_name
+            .to_string(),
+        connector_routing_data
+            .connector_data
+            .merchant_connector_id
+            .as_ref(),
+        false,
+    )
+    .await
+}
+
 #[cfg(feature = "v1")]
 #[allow(clippy::too_many_arguments)]
 #[instrument(skip_all)]
@@ -3610,13 +3716,7 @@ where
         router_data.connector_customer = Some(connector_customer_id);
     }
 
-    router_data.payment_method_token = if let Some(decrypted_token) =
-        add_decrypted_payment_method_token(tokenization_action.clone(), payment_data).await?
-    {
-        Some(decrypted_token)
-    } else {
-        router_data.payment_method_token
-    };
+    router_data.payment_method_token = payment_data.get_payment_method_token().cloned();
 
     let payment_method_token_response = router_data
         .add_payment_method_token(
@@ -3832,7 +3932,6 @@ where
         operation,
         payment_data,
         validate_result,
-        &merchant_connector_account,
         merchant_context.get_merchant_key_store(),
         customer,
         business_profile,
@@ -4801,134 +4900,273 @@ where
 
     Ok(router_data)
 }
+struct ApplePayWallet;
+struct PazeWallet;
+struct GooglePayWallet;
 
-pub async fn add_decrypted_payment_method_token<F, D>(
-    tokenization_action: TokenizationAction,
-    payment_data: &D,
-) -> CustomResult<Option<PaymentMethodToken>, errors::ApiErrorResponse>
+#[async_trait::async_trait]
+pub trait WalletFlow<F, D>: Send + Sync
 where
-    F: Send + Clone + Sync,
+    F: Send + Clone,
     D: OperationSessionGetters<F> + Send + Sync + Clone,
 {
-    // Tokenization Action will be DecryptApplePayToken, only when payment method type is Apple Pay
-    // and the connector supports Apple Pay predecrypt
-    match &tokenization_action {
-        TokenizationAction::DecryptApplePayToken(payment_processing_details)
-        | TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt(
-            payment_processing_details,
-        ) => {
-            let apple_pay_data = match payment_data.get_payment_method_data() {
-                Some(domain::PaymentMethodData::Wallet(domain::WalletData::ApplePay(
-                    wallet_data,
-                ))) => Some(
-                    ApplePayData::token_json(domain::WalletData::ApplePay(wallet_data.clone()))
-                        .change_context(errors::ApiErrorResponse::InternalServerError)
-                        .attach_printable("failed to parse apple pay token to json")?
-                        .decrypt(
-                            &payment_processing_details.payment_processing_certificate,
-                            &payment_processing_details.payment_processing_certificate_key,
-                        )
-                        .await
-                        .change_context(errors::ApiErrorResponse::InternalServerError)
-                        .attach_printable("failed to decrypt apple pay token")?,
-                ),
-                _ => None,
-            };
+    fn decide_wallet_flow(
+        &self,
+        state: &SessionState,
+        payment_data: &D,
+        merchant_connector_account: &helpers::MerchantConnectorAccountType,
+    ) -> CustomResult<Option<DecideWalletFlow>, errors::ApiErrorResponse>;
 
-            let apple_pay_predecrypt = apple_pay_data
-                .parse_value::<hyperswitch_domain_models::router_data::ApplePayPredecryptData>(
-                    "ApplePayPredecryptData",
-                )
-                .change_context(errors::ApiErrorResponse::InternalServerError)
-                .attach_printable(
-                    "failed to parse decrypted apple pay response to ApplePayPredecryptData",
+    async fn decrypt_wallet_token(
+        &self,
+        wallet_flow: &DecideWalletFlow,
+        payment_data: &D,
+    ) -> CustomResult<PaymentMethodToken, errors::ApiErrorResponse>;
+}
+
+#[async_trait::async_trait]
+impl<F, D> WalletFlow<F, D> for PazeWallet
+where
+    F: Send + Clone,
+    D: OperationSessionGetters<F> + Send + Sync + Clone,
+{
+    fn decide_wallet_flow(
+        &self,
+        state: &SessionState,
+        _payment_data: &D,
+        _merchant_connector_account: &helpers::MerchantConnectorAccountType,
+    ) -> CustomResult<Option<DecideWalletFlow>, errors::ApiErrorResponse> {
+        let paze_keys = state
+            .conf
+            .paze_decrypt_keys
+            .as_ref()
+            .get_required_value("Paze decrypt keys")
+            .attach_printable("Paze decrypt keys not found in the configuration")?;
+
+        let wallet_flow = DecideWalletFlow::PazeDecrypt(PazePaymentProcessingDetails {
+            paze_private_key: paze_keys.get_inner().paze_private_key.clone(),
+            paze_private_key_passphrase: paze_keys.get_inner().paze_private_key_passphrase.clone(),
+        });
+        Ok(Some(wallet_flow))
+    }
+
+    async fn decrypt_wallet_token(
+        &self,
+        wallet_flow: &DecideWalletFlow,
+        payment_data: &D,
+    ) -> CustomResult<PaymentMethodToken, errors::ApiErrorResponse> {
+        let paze_payment_processing_details = wallet_flow
+            .get_paze_payment_processing_details()
+            .get_required_value("Paze payment processing details")
+            .attach_printable(
+                "Paze payment processing details not found in Paze decryption flow",
+            )?;
+
+        let paze_wallet_data = payment_data
+                .get_payment_method_data()
+                .and_then(|payment_method_data| payment_method_data.get_wallet_data())
+                .and_then(|wallet_data| wallet_data.get_paze_wallet_data())
+                .get_required_value("Paze wallet token").attach_printable(
+                    "Paze wallet data not found in the payment method data during the Paze decryption flow",
                 )?;
 
-            Ok(Some(PaymentMethodToken::ApplePayDecrypt(Box::new(
-                apple_pay_predecrypt,
-            ))))
-        }
-        TokenizationAction::DecryptPazeToken(payment_processing_details) => {
-            let paze_data = match payment_data.get_payment_method_data() {
-                Some(domain::PaymentMethodData::Wallet(domain::WalletData::Paze(wallet_data))) => {
-                    Some(
-                        decrypt_paze_token(
-                            wallet_data.clone(),
-                            payment_processing_details.paze_private_key.clone(),
-                            payment_processing_details
-                                .paze_private_key_passphrase
-                                .clone(),
-                        )
-                        .change_context(errors::ApiErrorResponse::InternalServerError)
-                        .attach_printable("failed to decrypt paze token")?,
-                    )
-                }
-                _ => None,
-            };
-            let paze_decrypted_data = paze_data
-                .parse_value::<hyperswitch_domain_models::router_data::PazeDecryptedData>(
-                    "PazeDecryptedData",
+        let paze_data = decrypt_paze_token(
+            paze_wallet_data.clone(),
+            paze_payment_processing_details.paze_private_key.clone(),
+            paze_payment_processing_details
+                .paze_private_key_passphrase
+                .clone(),
+        )
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("failed to decrypt paze token")?;
+
+        let paze_decrypted_data = paze_data
+            .parse_value::<hyperswitch_domain_models::router_data::PazeDecryptedData>(
+                "PazeDecryptedData",
+            )
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("failed to parse PazeDecryptedData")?;
+        Ok(PaymentMethodToken::PazeDecrypt(Box::new(
+            paze_decrypted_data,
+        )))
+    }
+}
+
+#[async_trait::async_trait]
+impl<F, D> WalletFlow<F, D> for ApplePayWallet
+where
+    F: Send + Clone,
+    D: OperationSessionGetters<F> + Send + Sync + Clone,
+{
+    fn decide_wallet_flow(
+        &self,
+        state: &SessionState,
+        payment_data: &D,
+        merchant_connector_account: &helpers::MerchantConnectorAccountType,
+    ) -> CustomResult<Option<DecideWalletFlow>, errors::ApiErrorResponse> {
+        let apple_pay_metadata = check_apple_pay_metadata(state, Some(merchant_connector_account));
+
+        add_apple_pay_flow_metrics(
+            &apple_pay_metadata,
+            payment_data.get_payment_attempt().connector.clone(),
+            payment_data.get_payment_attempt().merchant_id.clone(),
+        );
+
+        let wallet_flow = match apple_pay_metadata {
+            Some(domain::ApplePayFlow::Simplified(payment_processing_details)) => Some(
+                DecideWalletFlow::ApplePayDecrypt(payment_processing_details),
+            ),
+            Some(domain::ApplePayFlow::Manual) | None => None,
+        };
+        Ok(wallet_flow)
+    }
+
+    async fn decrypt_wallet_token(
+        &self,
+        wallet_flow: &DecideWalletFlow,
+        payment_data: &D,
+    ) -> CustomResult<PaymentMethodToken, errors::ApiErrorResponse> {
+        let apple_pay_payment_processing_details = wallet_flow
+            .get_apple_pay_payment_processing_details()
+            .get_required_value("Apple Pay payment processing details")
+            .attach_printable(
+                "Apple Pay payment processing details not found in Apple Pay decryption flow",
+            )?;
+        let apple_pay_wallet_data = payment_data
+                .get_payment_method_data()
+                .and_then(|payment_method_data| payment_method_data.get_wallet_data())
+                .and_then(|wallet_data| wallet_data.get_apple_pay_wallet_data())
+                .get_required_value("Paze wallet token").attach_printable(
+                    "Apple Pay wallet data not found in the payment method data during the Apple Pay decryption flow",
+                )?;
+        let apple_pay_data =
+            ApplePayData::token_json(domain::WalletData::ApplePay(apple_pay_wallet_data.clone()))
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("failed to parse apple pay token to json")?
+                .decrypt(
+                    &apple_pay_payment_processing_details.payment_processing_certificate,
+                    &apple_pay_payment_processing_details.payment_processing_certificate_key,
                 )
+                .await
                 .change_context(errors::ApiErrorResponse::InternalServerError)
-                .attach_printable("failed to parse PazeDecryptedData")?;
-            Ok(Some(PaymentMethodToken::PazeDecrypt(Box::new(
-                paze_decrypted_data,
-            ))))
-        }
-        TokenizationAction::DecryptGooglePayToken(payment_processing_details) => {
-            let google_pay_data = match payment_data.get_payment_method_data() {
-                Some(domain::PaymentMethodData::Wallet(domain::WalletData::GooglePay(
-                    wallet_data,
-                ))) => {
-                    let decryptor = helpers::GooglePayTokenDecryptor::new(
-                        payment_processing_details
-                            .google_pay_root_signing_keys
-                            .clone(),
-                        payment_processing_details.google_pay_recipient_id.clone(),
-                        payment_processing_details.google_pay_private_key.clone(),
-                    )
-                    .change_context(errors::ApiErrorResponse::InternalServerError)
-                    .attach_printable("failed to create google pay token decryptor")?;
+                .attach_printable("failed to decrypt apple pay token")?;
 
-                    // should_verify_token is set to false to disable verification of token
-                    Some(
-                        decryptor
-                            .decrypt_token(wallet_data.tokenization_data.token.clone(), false)
-                            .change_context(errors::ApiErrorResponse::InternalServerError)
-                            .attach_printable("failed to decrypt google pay token")?,
-                    )
-                }
-                Some(payment_method_data) => {
-                    logger::info!(
-                        "Invalid payment_method_data found for Google Pay Decrypt Flow: {:?}",
-                        payment_method_data.get_payment_method()
-                    );
-                    None
-                }
-                None => {
-                    logger::info!("No payment_method_data found for Google Pay Decrypt Flow");
-                    None
-                }
-            };
+        let apple_pay_predecrypt = apple_pay_data
+            .parse_value::<hyperswitch_domain_models::router_data::ApplePayPredecryptData>(
+                "ApplePayPredecryptData",
+            )
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable(
+                "failed to parse decrypted apple pay response to ApplePayPredecryptData",
+            )?;
 
-            let google_pay_predecrypt = google_pay_data
-                .ok_or(errors::ApiErrorResponse::InternalServerError)
-                .attach_printable("failed to get GooglePayDecryptedData in response")?;
+        Ok(PaymentMethodToken::ApplePayDecrypt(Box::new(
+            apple_pay_predecrypt,
+        )))
+    }
+}
+
+#[async_trait::async_trait]
+impl<F, D> WalletFlow<F, D> for GooglePayWallet
+where
+    F: Send + Clone,
+    D: OperationSessionGetters<F> + Send + Sync + Clone,
+{
+    fn decide_wallet_flow(
+        &self,
+        state: &SessionState,
+        _payment_data: &D,
+        merchant_connector_account: &helpers::MerchantConnectorAccountType,
+    ) -> CustomResult<Option<DecideWalletFlow>, errors::ApiErrorResponse> {
+        Ok(
+            get_google_pay_connector_wallet_details(state, merchant_connector_account)
+                .map(DecideWalletFlow::GooglePayDecrypt),
+        )
+    }
+
+    async fn decrypt_wallet_token(
+        &self,
+        wallet_flow: &DecideWalletFlow,
+        payment_data: &D,
+    ) -> CustomResult<PaymentMethodToken, errors::ApiErrorResponse> {
+        let google_pay_payment_processing_details = wallet_flow
+            .get_google_pay_payment_processing_details()
+            .get_required_value("Google Pay payment processing details")
+            .attach_printable(
+                "Google Pay payment processing details not found in Google Pay decryption flow",
+            )?;
+
+        let google_pay_wallet_data = payment_data
+                .get_payment_method_data()
+                .and_then(|payment_method_data| payment_method_data.get_wallet_data())
+                .and_then(|wallet_data| wallet_data.get_google_pay_wallet_data())
+                .get_required_value("Paze wallet token").attach_printable(
+                    "Google Pay wallet data not found in the payment method data during the Google Pay decryption flow",
+                )?;
+
+        let decryptor = helpers::GooglePayTokenDecryptor::new(
+            google_pay_payment_processing_details
+                .google_pay_root_signing_keys
+                .clone(),
+            google_pay_payment_processing_details
+                .google_pay_recipient_id
+                .clone(),
+            google_pay_payment_processing_details
+                .google_pay_private_key
+                .clone(),
+        )
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("failed to create google pay token decryptor")?;
+
+        // should_verify_token is set to false to disable verification of token
+        let google_pay_data = decryptor
+            .decrypt_token(
+                google_pay_wallet_data.tokenization_data.token.clone(),
+                false,
+            )
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("failed to decrypt google pay token")?;
+
+        Ok(PaymentMethodToken::GooglePayDecrypt(Box::new(
+            google_pay_data,
+        )))
+    }
+}
 
-            Ok(Some(PaymentMethodToken::GooglePayDecrypt(Box::new(
-                google_pay_predecrypt,
-            ))))
+#[derive(Debug, Clone)]
+pub enum DecideWalletFlow {
+    ApplePayDecrypt(payments_api::PaymentProcessingDetails),
+    PazeDecrypt(PazePaymentProcessingDetails),
+    GooglePayDecrypt(GooglePayPaymentProcessingDetails),
+    SkipDecryption,
+}
+
+impl DecideWalletFlow {
+    fn get_paze_payment_processing_details(&self) -> Option<&PazePaymentProcessingDetails> {
+        if let Self::PazeDecrypt(details) = self {
+            Some(details)
+        } else {
+            None
         }
-        TokenizationAction::ConnectorToken(_) => {
-            logger::info!("Invalid tokenization action found for decryption flow: ConnectorToken");
-            Ok(None)
+    }
+
+    fn get_apple_pay_payment_processing_details(
+        &self,
+    ) -> Option<&payments_api::PaymentProcessingDetails> {
+        if let Self::ApplePayDecrypt(details) = self {
+            Some(details)
+        } else {
+            None
         }
-        token_action => {
-            logger::info!(
-                "Invalid tokenization action found for decryption flow: {:?}",
-                token_action
-            );
-            Ok(None)
+    }
+
+    fn get_google_pay_payment_processing_details(
+        &self,
+    ) -> Option<&GooglePayPaymentProcessingDetails> {
+        if let Self::GooglePayDecrypt(details) = self {
+            Some(details)
+        } else {
+            None
         }
     }
 }
@@ -5926,7 +6164,7 @@ fn is_payment_method_tokenization_enabled_for_connector(
     connector_name: &str,
     payment_method: storage::enums::PaymentMethod,
     payment_method_type: Option<storage::enums::PaymentMethodType>,
-    apple_pay_flow: &Option<domain::ApplePayFlow>,
+    payment_method_token: Option<&PaymentMethodToken>,
 ) -> RouterResult<bool> {
     let connector_tokenization_filter = state.conf.tokenization.0.get(connector_name);
 
@@ -5942,7 +6180,7 @@ fn is_payment_method_tokenization_enabled_for_connector(
                 )
                 && is_apple_pay_pre_decrypt_type_connector_tokenization(
                     payment_method_type,
-                    apple_pay_flow,
+                    payment_method_token,
                     connector_filter.apple_pay_pre_decrypt_flow.clone(),
                 )
         })
@@ -5951,13 +6189,13 @@ fn is_payment_method_tokenization_enabled_for_connector(
 
 fn is_apple_pay_pre_decrypt_type_connector_tokenization(
     payment_method_type: Option<storage::enums::PaymentMethodType>,
-    apple_pay_flow: &Option<domain::ApplePayFlow>,
+    payment_method_token: Option<&PaymentMethodToken>,
     apple_pay_pre_decrypt_flow_filter: Option<ApplePayPreDecryptFlow>,
 ) -> bool {
-    match (payment_method_type, apple_pay_flow) {
+    match (payment_method_type, payment_method_token) {
         (
             Some(storage::enums::PaymentMethodType::ApplePay),
-            Some(domain::ApplePayFlow::Simplified(_)),
+            Some(PaymentMethodToken::ApplePayDecrypt(..)),
         ) => !matches!(
             apple_pay_pre_decrypt_flow_filter,
             Some(ApplePayPreDecryptFlow::NetworkTokenization)
@@ -6142,58 +6380,20 @@ async fn decide_payment_method_tokenize_action(
     payment_intent_data: payments::PaymentIntent,
     pm_parent_token: Option<&str>,
     is_connector_tokenization_enabled: bool,
-    apple_pay_flow: Option<domain::ApplePayFlow>,
-    payment_method_type: Option<storage_enums::PaymentMethodType>,
-    merchant_connector_account: &helpers::MerchantConnectorAccountType,
 ) -> RouterResult<TokenizationAction> {
-    if let Some(storage_enums::PaymentMethodType::Paze) = payment_method_type {
-        // Paze generates a one time use network token which should not be tokenized in the connector or router.
-        match &state.conf.paze_decrypt_keys {
-            Some(paze_keys) => Ok(TokenizationAction::DecryptPazeToken(
-                PazePaymentProcessingDetails {
-                    paze_private_key: paze_keys.get_inner().paze_private_key.clone(),
-                    paze_private_key_passphrase: paze_keys
-                        .get_inner()
-                        .paze_private_key_passphrase
-                        .clone(),
-                },
-            )),
-            None => Err(errors::ApiErrorResponse::InternalServerError)
-                .attach_printable("Failed to fetch Paze configs"),
-        }
-    } else if let Some(storage_enums::PaymentMethodType::GooglePay) = payment_method_type {
-        let google_pay_details =
-            get_google_pay_connector_wallet_details(state, merchant_connector_account);
-
-        match google_pay_details {
-            Some(wallet_details) => Ok(TokenizationAction::DecryptGooglePayToken(wallet_details)),
-            None => {
-                if is_connector_tokenization_enabled {
-                    Ok(TokenizationAction::TokenizeInConnectorAndRouter)
-                } else {
-                    Ok(TokenizationAction::TokenizeInRouter)
-                }
-            }
-        }
-    } else if matches!(
+    if matches!(
         payment_intent_data.split_payments,
         Some(common_types::payments::SplitPaymentsRequest::StripeSplitPayment(_))
     ) {
         Ok(TokenizationAction::TokenizeInConnector)
     } else {
         match pm_parent_token {
-            None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) {
-                (true, Some(domain::ApplePayFlow::Simplified(payment_processing_details))) => {
-                    TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt(
-                        payment_processing_details,
-                    )
-                }
-                (true, _) => TokenizationAction::TokenizeInConnectorAndRouter,
-                (false, Some(domain::ApplePayFlow::Simplified(payment_processing_details))) => {
-                    TokenizationAction::DecryptApplePayToken(payment_processing_details)
-                }
-                (false, _) => TokenizationAction::TokenizeInRouter,
+            None => Ok(if is_connector_tokenization_enabled {
+                TokenizationAction::TokenizeInConnectorAndRouter
+            } else {
+                TokenizationAction::TokenizeInRouter
             }),
+
             Some(token) => {
                 let redis_conn = state
                     .store
@@ -6218,19 +6418,10 @@ async fn decide_payment_method_tokenize_action(
                     Some(connector_token) => {
                         Ok(TokenizationAction::ConnectorToken(connector_token))
                     }
-                    None => Ok(match (is_connector_tokenization_enabled, apple_pay_flow) {
-                        (
-                            true,
-                            Some(domain::ApplePayFlow::Simplified(payment_processing_details)),
-                        ) => TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt(
-                            payment_processing_details,
-                        ),
-                        (true, _) => TokenizationAction::TokenizeInConnectorAndRouter,
-                        (
-                            false,
-                            Some(domain::ApplePayFlow::Simplified(payment_processing_details)),
-                        ) => TokenizationAction::DecryptApplePayToken(payment_processing_details),
-                        (false, _) => TokenizationAction::TokenizeInRouter,
+                    None => Ok(if is_connector_tokenization_enabled {
+                        TokenizationAction::TokenizeInConnectorAndRouter
+                    } else {
+                        TokenizationAction::TokenizeInRouter
                     }),
                 }
             }
@@ -6258,10 +6449,6 @@ pub enum TokenizationAction {
     TokenizeInConnectorAndRouter,
     ConnectorToken(String),
     SkipConnectorTokenization,
-    DecryptApplePayToken(payments_api::PaymentProcessingDetails),
-    TokenizeInConnectorAndApplepayPreDecrypt(payments_api::PaymentProcessingDetails),
-    DecryptPazeToken(PazePaymentProcessingDetails),
-    DecryptGooglePayToken(GooglePayPaymentProcessingDetails),
 }
 
 #[cfg(feature = "v2")]
@@ -6271,7 +6458,6 @@ pub async fn get_connector_tokenization_action_when_confirm_true<F, Req, D>(
     _operation: &BoxedOperation<'_, F, Req, D>,
     payment_data: &mut D,
     _validate_result: &operations::ValidateResult,
-    _merchant_connector_account: &helpers::MerchantConnectorAccountType,
     _merchant_key_store: &domain::MerchantKeyStore,
     _customer: &Option<domain::Customer>,
     _business_profile: &domain::Profile,
@@ -6292,7 +6478,6 @@ pub async fn get_connector_tokenization_action_when_confirm_true<F, Req, D>(
     operation: &BoxedOperation<'_, F, Req, D>,
     payment_data: &mut D,
     validate_result: &operations::ValidateResult,
-    merchant_connector_account: &helpers::MerchantConnectorAccountType,
     merchant_key_store: &domain::MerchantKeyStore,
     customer: &Option<domain::Customer>,
     business_profile: &domain::Profile,
@@ -6327,24 +6512,15 @@ where
                 .get_required_value("payment_method")?;
             let payment_method_type = payment_data.get_payment_attempt().payment_method_type;
 
-            let apple_pay_flow =
-                decide_apple_pay_flow(state, payment_method_type, Some(merchant_connector_account));
-
             let is_connector_tokenization_enabled =
                 is_payment_method_tokenization_enabled_for_connector(
                     state,
                     &connector,
                     payment_method,
                     payment_method_type,
-                    &apple_pay_flow,
+                    payment_data.get_payment_method_token(),
                 )?;
 
-            add_apple_pay_flow_metrics(
-                &apple_pay_flow,
-                payment_data.get_payment_attempt().connector.clone(),
-                payment_data.get_payment_attempt().merchant_id.clone(),
-            );
-
             let payment_method_action = decide_payment_method_tokenize_action(
                 state,
                 &connector,
@@ -6352,9 +6528,6 @@ where
                 payment_data.get_payment_intent().clone(),
                 payment_data.get_token(),
                 is_connector_tokenization_enabled,
-                apple_pay_flow,
-                payment_method_type,
-                merchant_connector_account,
             )
             .await?;
 
@@ -6377,7 +6550,6 @@ where
 
                     TokenizationAction::SkipConnectorTokenization
                 }
-
                 TokenizationAction::TokenizeInConnector => TokenizationAction::TokenizeInConnector,
                 TokenizationAction::TokenizeInConnectorAndRouter => {
                     let (_operation, payment_method_data, pm_id) = operation
@@ -6404,22 +6576,6 @@ where
                 TokenizationAction::SkipConnectorTokenization => {
                     TokenizationAction::SkipConnectorTokenization
                 }
-                TokenizationAction::DecryptApplePayToken(payment_processing_details) => {
-                    TokenizationAction::DecryptApplePayToken(payment_processing_details)
-                }
-                TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt(
-                    payment_processing_details,
-                ) => TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt(
-                    payment_processing_details,
-                ),
-                TokenizationAction::DecryptPazeToken(paze_payment_processing_details) => {
-                    TokenizationAction::DecryptPazeToken(paze_payment_processing_details)
-                }
-                TokenizationAction::DecryptGooglePayToken(
-                    google_pay_payment_processing_details,
-                ) => {
-                    TokenizationAction::DecryptGooglePayToken(google_pay_payment_processing_details)
-                }
             };
             (payment_data.to_owned(), connector_tokenization_action)
         }
@@ -6520,6 +6676,7 @@ where
     pub force_sync: Option<bool>,
     pub all_keys_required: Option<bool>,
     pub payment_method_data: Option<domain::PaymentMethodData>,
+    pub payment_method_token: Option<PaymentMethodToken>,
     pub payment_method_info: Option<domain::PaymentMethod>,
     pub refunds: Vec<diesel_refund::Refund>,
     pub disputes: Vec<storage::Dispute>,
@@ -9405,6 +9562,7 @@ pub trait OperationSessionGetters<F> {
     #[cfg(feature = "v2")]
     fn get_client_secret(&self) -> &Option<Secret<String>>;
     fn get_payment_method_info(&self) -> Option<&domain::PaymentMethod>;
+    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken>;
     fn get_mandate_id(&self) -> Option<&payments_api::MandateIds>;
     fn get_address(&self) -> &PaymentAddress;
     fn get_creds_identifier(&self) -> Option<&str>;
@@ -9470,6 +9628,7 @@ pub trait OperationSessionSetters<F> {
     fn set_client_secret(&mut self, client_secret: Option<Secret<String>>);
     fn set_payment_attempt(&mut self, payment_attempt: storage::PaymentAttempt);
     fn set_payment_method_data(&mut self, payment_method_data: Option<domain::PaymentMethodData>);
+    fn set_payment_method_token(&mut self, payment_method_token: Option<PaymentMethodToken>);
     fn set_email_if_not_present(&mut self, email: pii::Email);
     fn set_payment_method_id_in_attempt(&mut self, payment_method_id: Option<String>);
     fn set_pm_token(&mut self, token: String);
@@ -9553,6 +9712,10 @@ impl<F: Clone> OperationSessionGetters<F> for PaymentData<F> {
         self.payment_method_info.as_ref()
     }
 
+    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken> {
+        self.payment_method_token.as_ref()
+    }
+
     fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> {
         self.mandate_id.as_ref()
     }
@@ -9717,6 +9880,10 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentData<F> {
         self.payment_method_data = payment_method_data;
     }
 
+    fn set_payment_method_token(&mut self, payment_method_token: Option<PaymentMethodToken>) {
+        self.payment_method_token = payment_method_token;
+    }
+
     fn set_payment_method_id_in_attempt(&mut self, payment_method_id: Option<String>) {
         self.payment_attempt.payment_method_id = payment_method_id;
     }
@@ -9749,10 +9916,24 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentData<F> {
     }
 
     fn set_card_network(&mut self, card_network: enums::CardNetwork) {
-        if let Some(domain::PaymentMethodData::Card(card)) = &mut self.payment_method_data {
-            logger::debug!("set card network {:?}", card_network.clone());
-            card.card_network = Some(card_network);
-        };
+        match &mut self.payment_method_data {
+            Some(domain::PaymentMethodData::Card(card)) => {
+                logger::debug!("Setting card network: {:?}", card_network);
+                card.card_network = Some(card_network);
+            }
+            Some(domain::PaymentMethodData::Wallet(wallet_data)) => match wallet_data {
+                hyperswitch_domain_models::payment_method_data::WalletData::ApplePay(wallet) => {
+                    logger::debug!("Setting Apple Pay card network: {:?}", card_network);
+                    wallet.payment_method.network = card_network.to_string();
+                }
+                _ => {
+                    logger::debug!("Wallet type does not support setting card network.");
+                }
+            },
+            _ => {
+                logger::warn!("Payment method data does not support setting card network.");
+            }
+        }
     }
 
     fn set_co_badged_card_data(
@@ -9878,6 +10059,10 @@ impl<F: Clone> OperationSessionGetters<F> for PaymentIntentData<F> {
         todo!()
     }
 
+    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken> {
+        todo!()
+    }
+
     fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> {
         todo!()
     }
@@ -10042,6 +10227,10 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentIntentData<F> {
         todo!()
     }
 
+    fn set_payment_method_token(&mut self, _payment_method_token: Option<PaymentMethodToken>) {
+        todo!()
+    }
+
     fn set_payment_method_id_in_attempt(&mut self, _payment_method_id: Option<String>) {
         todo!()
     }
@@ -10179,6 +10368,10 @@ impl<F: Clone> OperationSessionGetters<F> for PaymentConfirmData<F> {
         todo!()
     }
 
+    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken> {
+        todo!()
+    }
+
     fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> {
         todo!()
     }
@@ -10340,6 +10533,10 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentConfirmData<F> {
         todo!()
     }
 
+    fn set_payment_method_token(&mut self, _payment_method_token: Option<PaymentMethodToken>) {
+        todo!()
+    }
+
     fn set_payment_method_id_in_attempt(&mut self, _payment_method_id: Option<String>) {
         todo!()
     }
@@ -10478,6 +10675,10 @@ impl<F: Clone> OperationSessionGetters<F> for PaymentStatusData<F> {
         todo!()
     }
 
+    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken> {
+        todo!()
+    }
+
     fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> {
         todo!()
     }
@@ -10635,6 +10836,10 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentStatusData<F> {
         todo!()
     }
 
+    fn set_payment_method_token(&mut self, _payment_method_token: Option<PaymentMethodToken>) {
+        todo!()
+    }
+
     fn set_payment_method_id_in_attempt(&mut self, _payment_method_id: Option<String>) {
         todo!()
     }
@@ -10772,6 +10977,10 @@ impl<F: Clone> OperationSessionGetters<F> for PaymentCaptureData<F> {
         todo!()
     }
 
+    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken> {
+        todo!()
+    }
+
     fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> {
         todo!()
     }
@@ -10931,6 +11140,10 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentCaptureData<F> {
         todo!()
     }
 
+    fn set_payment_method_token(&mut self, _payment_method_token: Option<PaymentMethodToken>) {
+        todo!()
+    }
+
     fn set_payment_method_id_in_attempt(&mut self, _payment_method_id: Option<String>) {
         todo!()
     }
@@ -11063,6 +11276,10 @@ impl<F: Clone> OperationSessionGetters<F> for PaymentAttemptListData<F> {
         todo!()
     }
 
+    fn get_payment_method_token(&self) -> Option<&PaymentMethodToken> {
+        todo!()
+    }
+
     fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> {
         todo!()
     }
diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs
index a16c2cd433f..8beac4097a9 100644
--- a/crates/router/src/core/payments/operations/payment_approve.rs
+++ b/crates/router/src/core/payments/operations/payment_approve.rs
@@ -173,6 +173,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsCaptureR
             ),
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs
index 343c1f98a9d..dfe3657b0f7 100644
--- a/crates/router/src/core/payments/operations/payment_cancel.rs
+++ b/crates/router/src/core/payments/operations/payment_cancel.rs
@@ -184,6 +184,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsCancelRe
             ),
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs
index 8e3a765b8ad..6108ed3658f 100644
--- a/crates/router/src/core/payments/operations/payment_capture.rs
+++ b/crates/router/src/core/payments/operations/payment_capture.rs
@@ -235,6 +235,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, payments::PaymentData<F>, api::Paymen
             ),
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             refunds: vec![],
             disputes: vec![],
diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
index 3ce888e6574..38a189e50fd 100644
--- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs
+++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
@@ -332,6 +332,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
                 .payment_method_data
                 .as_ref()
                 .and_then(|pmd| pmd.payment_method_data.clone().map(Into::into)),
+            payment_method_token: None,
             payment_method_info,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 2aa1a72e73f..abbdc1f5c75 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -795,6 +795,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             token_data,
             confirm: request.confirm,
             payment_method_data: payment_method_data_after_card_bin_call.map(Into::into),
+            payment_method_token: None,
             payment_method_info,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index a73796075a5..1c3a8a0be9a 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -598,6 +598,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             token_data: None,
             confirm: request.confirm,
             payment_method_data: payment_method_data_after_card_bin_call.map(Into::into),
+            payment_method_token: None,
             payment_method_info,
             refunds: vec![],
             disputes: vec![],
diff --git a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs
index 3df1da1827e..b1543be1544 100644
--- a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs
+++ b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs
@@ -145,6 +145,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsPostSess
             ),
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs
index 33ec9a0d592..f963baa87c1 100644
--- a/crates/router/src/core/payments/operations/payment_reject.rs
+++ b/crates/router/src/core/payments/operations/payment_reject.rs
@@ -171,6 +171,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, PaymentsCancelRequest
             token_data: None,
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs
index b0a5f2fc133..8a7c22376a0 100644
--- a/crates/router/src/core/payments/operations/payment_session.rs
+++ b/crates/router/src/core/payments/operations/payment_session.rs
@@ -193,6 +193,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsSessionR
             ),
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs
index e702ba1ef50..9727fb399d2 100644
--- a/crates/router/src/core/payments/operations/payment_start.rs
+++ b/crates/router/src/core/payments/operations/payment_start.rs
@@ -181,6 +181,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsStartReq
             confirm: Some(payment_attempt.confirm),
             payment_attempt,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs
index ac2a7b923fd..c6488bdb75c 100644
--- a/crates/router/src/core/payments/operations/payment_status.rs
+++ b/crates/router/src/core/payments/operations/payment_status.rs
@@ -517,6 +517,7 @@ async fn get_tracker_for_sync<
         token_data: None,
         confirm: Some(request.force_sync),
         payment_method_data: None,
+        payment_method_token: None,
         payment_method_info,
         force_sync: Some(
             request.force_sync
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index 2299acbe304..0b77e5c31c4 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -475,6 +475,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
                 .payment_method_data
                 .as_ref()
                 .and_then(|pmd| pmd.payment_method_data.clone().map(Into::into)),
+            payment_method_token: None,
             payment_method_info,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payment_update_metadata.rs b/crates/router/src/core/payments/operations/payment_update_metadata.rs
index 2c6841c44a4..23a300c3c8b 100644
--- a/crates/router/src/core/payments/operations/payment_update_metadata.rs
+++ b/crates/router/src/core/payments/operations/payment_update_metadata.rs
@@ -131,6 +131,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsUpdateMe
             address: payments::PaymentAddress::new(None, None, None, None),
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
index e5262d092c1..a32f89ef4d3 100644
--- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
+++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
@@ -145,6 +145,7 @@ impl<F: Send + Clone + Sync>
             address: PaymentAddress::new(None, None, None, None),
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs
index 85ad5fb1cb6..9f0863e6767 100644
--- a/crates/router/src/core/payments/operations/tax_calculation.rs
+++ b/crates/router/src/core/payments/operations/tax_calculation.rs
@@ -160,6 +160,7 @@ impl<F: Send + Clone + Sync>
             ),
             confirm: None,
             payment_method_data: None,
+            payment_method_token: None,
             payment_method_info: None,
             force_sync: None,
             all_keys_required: None,
diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs
index f4389bc1738..d6578ad36c7 100644
--- a/crates/router/src/core/payments/tokenization.rs
+++ b/crates/router/src/core/payments/tokenization.rs
@@ -1253,8 +1253,7 @@ pub async fn add_payment_method_token<F: Clone, T: types::Tokenizable + Clone>(
 ) -> RouterResult<types::PaymentMethodTokenResult> {
     if should_continue_payment {
         match tokenization_action {
-            payments::TokenizationAction::TokenizeInConnector
-            | payments::TokenizationAction::TokenizeInConnectorAndApplepayPreDecrypt(_) => {
+            payments::TokenizationAction::TokenizeInConnector => {
                 let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
                     api::PaymentMethodToken,
                     types::PaymentMethodTokenizationData,

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

- [ ] Bugfix
- [x] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
This pull request adds debit routing support for Apple Pay. In the Apple Pay decryption flow, if debit routing is enabled by the merchant and the card type is debit, a call will be made to the decision engine to retrieve the supported card networks and the potential debit routing savings. Among these networks, the lowest-cost network will be selected to process the Apple Pay payment.

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## 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).
-->


## 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)?
-->
-> enable debit routing and make a apple pay payment
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_tT5kUVUp7uaQHR2Z824Iy7393nL5sEWLxAvJblCxxmttLizAkJbWtsdgoIjdGQE2' \
--data-raw '{
    "amount": 650,
    "currency": "USD",
    "confirm": true,
    "business_country": "US",
    "business_label": "default",
    "amount_to_capture": 650,
    "customer_id": "cu_1752747625",
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "setup_future_usage": "on_session",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "payment_method": "wallet",
    "payment_method_type": "apple_pay",
    "billing": {
        "address": {
            "line1": "1467",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    }
    ,
    "payment_method_data": {
        "wallet": {
            "apple_pay": {
                "payment_data": "==",
                "payment_method": {
                    "display_name": "Discover 9319",
                    "network": "Discover",
                    "type": "debit"
                },
                "transaction_identifier": "c635c5b3af900d7bd81fecd7028f1262f9d030754ee65ec7afd988a678194751"
            }
        }
    }
}'
```
```
{
    "payment_id": "pay_O0EoroDslloH3cVj5Xc5",
    "merchant_id": "merchant_1752747413",
    "status": "succeeded",
    "amount": 650,
    "net_amount": 650,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 650,
    "connector": "adyen",
    "client_secret": "pay_O0EoroDslloH3cVj5Xc5_secret_mEciQ25Sjl46cuShfITO",
    "created": "2025-07-17T10:18:35.495Z",
    "currency": "USD",
    "customer_id": "cu_1752747515",
    "customer": {
        "id": "cu_1752747515",
        "name": "Joseph Doe",
        "email": "something@gmail.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "on_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "wallet",
    "payment_method_data": {
        "wallet": {
            "apple_pay": {
                "last4": "9319",
                "card_network": "Accel",
                "type": "debit"
            }
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": null,
            "line3": null,
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": null,
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "apple_pay",
    "connector_label": "adyen_US_default",
    "business_country": "US",
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cu_1752747515",
        "created_at": 1752747515,
        "expires": 1752751115,
        "secret": "epk_e7dc207a6f124b47a191ba2daf803e6b"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "P3TQQMQMMQ6M5375",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_O0EoroDslloH3cVj5Xc5_1",
    "payment_link": null,
    "profile_id": "pro_0BT05CUisTpwMzBcK4wf",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_dITrhiR4JCNaaJFsaPGH",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-07-17T10:33:35.495Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-07-17T10:18:40.793Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": null,
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}
```
-> Decision engine lookup using 8 digits bin with padded 0s for lookup
<img width="1382" height="303" alt="image" src="https://github.com/user-attachments/assets/84305a47-c56c-46e5-bb4e-685e51d7e736" />


## 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
- [ ] I added unit tests for my changes where possible
