Bug: [FEATURE] Add support for retries with clear pan and network token payment method data



Add support for payment retries with clear pan and network token payment method data and also reduced calls to locker when data is already fetch once.
diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json
index 2e0d57d977e..cd8b8458364 100644
--- a/api-reference-v2/openapi_spec.json
+++ b/api-reference-v2/openapi_spec.json
@@ -10615,7 +10615,8 @@
           "message",
           "status",
           "decision",
-          "step_up_possible"
+          "step_up_possible",
+          "clear_pan_possible"
         ],
         "properties": {
           "connector": {
@@ -10670,6 +10671,10 @@
               }
             ],
             "nullable": true
+          },
+          "clear_pan_possible": {
+            "type": "boolean",
+            "description": "indicates if retry with pan is possible"
           }
         }
       },
@@ -10754,7 +10759,8 @@
           "message",
           "status",
           "decision",
-          "step_up_possible"
+          "step_up_possible",
+          "clear_pan_possible"
         ],
         "properties": {
           "connector": {
@@ -10811,6 +10817,10 @@
               }
             ],
             "nullable": true
+          },
+          "clear_pan_possible": {
+            "type": "boolean",
+            "description": "indicates if retry with pan is possible"
           }
         }
       },
@@ -10915,6 +10925,11 @@
               }
             ],
             "nullable": true
+          },
+          "clear_pan_possible": {
+            "type": "boolean",
+            "description": "indicates if retry with pan is possible",
+            "nullable": true
           }
         }
       },
@@ -18738,6 +18753,11 @@
               }
             ],
             "nullable": true
+          },
+          "is_clear_pan_retries_enabled": {
+            "type": "boolean",
+            "description": "Indicates if clear pan retries is enabled or not.",
+            "nullable": true
           }
         },
         "additionalProperties": false
@@ -18771,7 +18791,8 @@
           "is_tax_connector_enabled",
           "is_network_tokenization_enabled",
           "should_collect_cvv_during_payment",
-          "is_click_to_pay_enabled"
+          "is_click_to_pay_enabled",
+          "is_clear_pan_retries_enabled"
         ],
         "properties": {
           "merchant_id": {
@@ -18970,6 +18991,10 @@
               }
             ],
             "nullable": true
+          },
+          "is_clear_pan_retries_enabled": {
+            "type": "boolean",
+            "description": "Indicates if clear pan retries is enabled or not."
           }
         }
       },
diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs
index d9ae29d4b30..5d31ea70994 100644
--- a/crates/api_models/src/admin.rs
+++ b/crates/api_models/src/admin.rs
@@ -1960,6 +1960,9 @@ pub struct ProfileCreate {
 
     /// Card Testing Guard Configs
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
+
+    ///Indicates if clear pan retries is enabled or not.
+    pub is_clear_pan_retries_enabled: Option<bool>,
 }
 
 #[nutype::nutype(
@@ -2081,6 +2084,9 @@ pub struct ProfileCreate {
 
     /// Card Testing Guard Configs
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
+
+    ///Indicates if clear pan retries is enabled or not.
+    pub is_clear_pan_retries_enabled: Option<bool>,
 }
 
 #[cfg(feature = "v1")]
@@ -2225,6 +2231,9 @@ pub struct ProfileResponse {
 
     /// Card Testing Guard Configs
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
+
+    ///Indicates if clear pan retries is enabled or not.
+    pub is_clear_pan_retries_enabled: bool,
 }
 
 #[cfg(feature = "v2")]
@@ -2352,6 +2361,9 @@ pub struct ProfileResponse {
 
     /// Card Testing Guard Configs
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
+
+    ///Indicates if clear pan retries is enabled or not.
+    pub is_clear_pan_retries_enabled: bool,
 }
 
 #[cfg(feature = "v1")]
@@ -2486,6 +2498,9 @@ pub struct ProfileUpdate {
 
     /// Card Testing Guard Configs
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
+
+    ///Indicates if clear pan retries is enabled or not.
+    pub is_clear_pan_retries_enabled: Option<bool>,
 }
 
 #[cfg(feature = "v2")]
@@ -2601,6 +2616,9 @@ pub struct ProfileUpdate {
 
     /// Card Testing Guard Configs
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
+
+    ///Indicates if clear pan retries is enabled or not.
+    pub is_clear_pan_retries_enabled: Option<bool>,
 }
 
 #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
diff --git a/crates/api_models/src/gsm.rs b/crates/api_models/src/gsm.rs
index b95794ef707..7ffc9c69413 100644
--- a/crates/api_models/src/gsm.rs
+++ b/crates/api_models/src/gsm.rs
@@ -29,6 +29,8 @@ pub struct GsmCreateRequest {
     pub unified_message: Option<String>,
     /// category in which error belongs to
     pub error_category: Option<ErrorCategory>,
+    /// indicates if retry with pan is possible
+    pub clear_pan_possible: bool,
 }
 
 #[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
@@ -93,6 +95,8 @@ pub struct GsmUpdateRequest {
     pub unified_message: Option<String>,
     /// category in which error belongs to
     pub error_category: Option<ErrorCategory>,
+    /// indicates if retry with pan is possible
+    pub clear_pan_possible: Option<bool>,
 }
 
 #[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)]
@@ -148,4 +152,6 @@ pub struct GsmResponse {
     pub unified_message: Option<String>,
     /// category in which error belongs to
     pub error_category: Option<ErrorCategory>,
+    /// indicates if retry with pan is possible
+    pub clear_pan_possible: bool,
 }
diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs
index c5507d78002..744193bf51e 100644
--- a/crates/diesel_models/src/business_profile.rs
+++ b/crates/diesel_models/src/business_profile.rs
@@ -63,6 +63,7 @@ pub struct Profile {
         Option<common_types::payments::AuthenticationConnectorAccountMap>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: Option<Encryption>,
+    pub is_clear_pan_retries_enabled: bool,
 }
 
 #[cfg(feature = "v1")]
@@ -111,6 +112,7 @@ pub struct ProfileNew {
         Option<common_types::payments::AuthenticationConnectorAccountMap>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: Option<Encryption>,
+    pub is_clear_pan_retries_enabled: bool,
 }
 
 #[cfg(feature = "v1")]
@@ -157,6 +159,7 @@ pub struct ProfileUpdateInternal {
         Option<common_types::payments::AuthenticationConnectorAccountMap>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: Option<Encryption>,
+    pub is_clear_pan_retries_enabled: Option<bool>,
 }
 
 #[cfg(feature = "v1")]
@@ -201,6 +204,7 @@ impl ProfileUpdateInternal {
             authentication_product_ids,
             card_testing_guard_config,
             card_testing_secret_key,
+            is_clear_pan_retries_enabled,
         } = self;
         Profile {
             profile_id: source.profile_id,
@@ -269,6 +273,8 @@ impl ProfileUpdateInternal {
             card_testing_guard_config: card_testing_guard_config
                 .or(source.card_testing_guard_config),
             card_testing_secret_key,
+            is_clear_pan_retries_enabled: is_clear_pan_retries_enabled
+                .unwrap_or(source.is_clear_pan_retries_enabled),
         }
     }
 }
@@ -321,6 +327,7 @@ pub struct Profile {
         Option<common_types::payments::AuthenticationConnectorAccountMap>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: Option<Encryption>,
+    pub is_clear_pan_retries_enabled: bool,
     pub routing_algorithm_id: Option<common_utils::id_type::RoutingId>,
     pub order_fulfillment_time: Option<i64>,
     pub order_fulfillment_time_origin: Option<common_enums::OrderFulfillmentTimeOrigin>,
@@ -394,6 +401,7 @@ pub struct ProfileNew {
     pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: Option<Encryption>,
+    pub is_clear_pan_retries_enabled: Option<bool>,
 }
 
 #[cfg(feature = "v2")]
@@ -442,6 +450,7 @@ pub struct ProfileUpdateInternal {
     pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: Option<Encryption>,
+    pub is_clear_pan_retries_enabled: Option<bool>,
 }
 
 #[cfg(feature = "v2")]
@@ -488,6 +497,7 @@ impl ProfileUpdateInternal {
             three_ds_decision_manager_config,
             card_testing_guard_config,
             card_testing_secret_key,
+            is_clear_pan_retries_enabled,
         } = self;
         Profile {
             id: source.id,
@@ -562,6 +572,8 @@ impl ProfileUpdateInternal {
             card_testing_guard_config: card_testing_guard_config
                 .or(source.card_testing_guard_config),
             card_testing_secret_key: card_testing_secret_key.or(source.card_testing_secret_key),
+            is_clear_pan_retries_enabled: is_clear_pan_retries_enabled
+                .unwrap_or(source.is_clear_pan_retries_enabled),
         }
     }
 }
diff --git a/crates/diesel_models/src/gsm.rs b/crates/diesel_models/src/gsm.rs
index aba8d75a6eb..46583a5b22c 100644
--- a/crates/diesel_models/src/gsm.rs
+++ b/crates/diesel_models/src/gsm.rs
@@ -41,6 +41,7 @@ pub struct GatewayStatusMap {
     pub unified_code: Option<String>,
     pub unified_message: Option<String>,
     pub error_category: Option<ErrorCategory>,
+    pub clear_pan_possible: bool,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Insertable)]
@@ -58,6 +59,7 @@ pub struct GatewayStatusMappingNew {
     pub unified_code: Option<String>,
     pub unified_message: Option<String>,
     pub error_category: Option<ErrorCategory>,
+    pub clear_pan_possible: bool,
 }
 
 #[derive(
@@ -78,6 +80,7 @@ pub struct GatewayStatusMapperUpdateInternal {
     pub unified_message: Option<String>,
     pub error_category: Option<ErrorCategory>,
     pub last_modified: PrimitiveDateTime,
+    pub clear_pan_possible: Option<bool>,
 }
 
 #[derive(Debug)]
@@ -89,6 +92,7 @@ pub struct GatewayStatusMappingUpdate {
     pub unified_code: Option<String>,
     pub unified_message: Option<String>,
     pub error_category: Option<ErrorCategory>,
+    pub clear_pan_possible: Option<bool>,
 }
 
 impl From<GatewayStatusMappingUpdate> for GatewayStatusMapperUpdateInternal {
@@ -101,6 +105,7 @@ impl From<GatewayStatusMappingUpdate> for GatewayStatusMapperUpdateInternal {
             unified_code,
             unified_message,
             error_category,
+            clear_pan_possible,
         } = value;
         Self {
             status,
@@ -116,6 +121,7 @@ impl From<GatewayStatusMappingUpdate> for GatewayStatusMapperUpdateInternal {
             sub_flow: None,
             code: None,
             message: None,
+            clear_pan_possible,
         }
     }
 }
diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs
index 1de8483a3f3..9135baeb77a 100644
--- a/crates/diesel_models/src/schema.rs
+++ b/crates/diesel_models/src/schema.rs
@@ -219,6 +219,7 @@ diesel::table! {
         authentication_product_ids -> Nullable<Jsonb>,
         card_testing_guard_config -> Nullable<Jsonb>,
         card_testing_secret_key -> Nullable<Bytea>,
+        is_clear_pan_retries_enabled -> Bool,
     }
 }
 
@@ -565,6 +566,7 @@ diesel::table! {
         unified_message -> Nullable<Varchar>,
         #[max_length = 64]
         error_category -> Nullable<Varchar>,
+        clear_pan_possible -> Bool,
     }
 }
 
diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs
index 6018d0a6999..af1b2c65f40 100644
--- a/crates/diesel_models/src/schema_v2.rs
+++ b/crates/diesel_models/src/schema_v2.rs
@@ -215,6 +215,7 @@ diesel::table! {
         authentication_product_ids -> Nullable<Jsonb>,
         card_testing_guard_config -> Nullable<Jsonb>,
         card_testing_secret_key -> Nullable<Bytea>,
+        is_clear_pan_retries_enabled -> Bool,
         #[max_length = 64]
         routing_algorithm_id -> Nullable<Varchar>,
         order_fulfillment_time -> Nullable<Int8>,
@@ -576,6 +577,7 @@ diesel::table! {
         unified_message -> Nullable<Varchar>,
         #[max_length = 64]
         error_category -> Nullable<Varchar>,
+        clear_pan_possible -> Bool,
     }
 }
 
diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs
index 07fd0a9fd90..d4bb6ed1fce 100644
--- a/crates/hyperswitch_domain_models/src/business_profile.rs
+++ b/crates/hyperswitch_domain_models/src/business_profile.rs
@@ -64,6 +64,7 @@ pub struct Profile {
         Option<common_types::payments::AuthenticationConnectorAccountMap>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: OptionalEncryptableName,
+    pub is_clear_pan_retries_enabled: bool,
 }
 
 #[cfg(feature = "v1")]
@@ -110,6 +111,7 @@ pub struct ProfileSetter {
         Option<common_types::payments::AuthenticationConnectorAccountMap>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: OptionalEncryptableName,
+    pub is_clear_pan_retries_enabled: bool,
 }
 
 #[cfg(feature = "v1")]
@@ -162,6 +164,7 @@ impl From<ProfileSetter> for Profile {
             authentication_product_ids: value.authentication_product_ids,
             card_testing_guard_config: value.card_testing_guard_config,
             card_testing_secret_key: value.card_testing_secret_key,
+            is_clear_pan_retries_enabled: value.is_clear_pan_retries_enabled,
         }
     }
 }
@@ -216,6 +219,7 @@ pub struct ProfileGeneralUpdate {
         Option<common_types::payments::AuthenticationConnectorAccountMap>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: OptionalEncryptableName,
+    pub is_clear_pan_retries_enabled: Option<bool>,
 }
 
 #[cfg(feature = "v1")]
@@ -285,6 +289,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                     authentication_product_ids,
                     card_testing_guard_config,
                     card_testing_secret_key,
+                    is_clear_pan_retries_enabled,
                 } = *update;
 
                 Self {
@@ -327,6 +332,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                     authentication_product_ids,
                     card_testing_guard_config,
                     card_testing_secret_key: card_testing_secret_key.map(Encryption::from),
+                    is_clear_pan_retries_enabled,
                 }
             }
             ProfileUpdate::RoutingAlgorithmUpdate {
@@ -371,6 +377,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 authentication_product_ids: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::DynamicRoutingAlgorithmUpdate {
                 dynamic_routing_algorithm,
@@ -413,6 +420,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 authentication_product_ids: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::ExtendedCardInfoUpdate {
                 is_extended_card_info_enabled,
@@ -455,6 +463,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 authentication_product_ids: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::ConnectorAgnosticMitUpdate {
                 is_connector_agnostic_mit_enabled,
@@ -497,6 +506,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 authentication_product_ids: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::NetworkTokenizationUpdate {
                 is_network_tokenization_enabled,
@@ -539,6 +549,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 authentication_product_ids: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::CardTestingSecretKeyUpdate {
                 card_testing_secret_key,
@@ -581,6 +592,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 authentication_product_ids: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: card_testing_secret_key.map(Encryption::from),
+                is_clear_pan_retries_enabled: None,
             },
         }
     }
@@ -642,6 +654,7 @@ impl super::behaviour::Conversion for Profile {
             authentication_product_ids: self.authentication_product_ids,
             card_testing_guard_config: self.card_testing_guard_config,
             card_testing_secret_key: self.card_testing_secret_key.map(|name| name.into()),
+            is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled,
         })
     }
 
@@ -728,6 +741,7 @@ impl super::behaviour::Conversion for Profile {
                         .and_then(|val| val.try_into_optionaloperation())
                     })
                     .await?,
+                is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
             })
         }
         .await
@@ -784,6 +798,7 @@ impl super::behaviour::Conversion for Profile {
             authentication_product_ids: self.authentication_product_ids,
             card_testing_guard_config: self.card_testing_guard_config,
             card_testing_secret_key: self.card_testing_secret_key.map(Encryption::from),
+            is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled,
         })
     }
 }
@@ -834,6 +849,7 @@ pub struct Profile {
     pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: OptionalEncryptableName,
+    pub is_clear_pan_retries_enabled: bool,
 }
 
 #[cfg(feature = "v2")]
@@ -880,6 +896,7 @@ pub struct ProfileSetter {
     pub three_ds_decision_manager_config: Option<common_types::payments::DecisionManagerRecord>,
     pub card_testing_guard_config: Option<CardTestingGuardConfig>,
     pub card_testing_secret_key: OptionalEncryptableName,
+    pub is_clear_pan_retries_enabled: bool,
 }
 
 #[cfg(feature = "v2")]
@@ -932,6 +949,7 @@ impl From<ProfileSetter> for Profile {
             three_ds_decision_manager_config: value.three_ds_decision_manager_config,
             card_testing_guard_config: value.card_testing_guard_config,
             card_testing_secret_key: value.card_testing_secret_key,
+            is_clear_pan_retries_enabled: value.is_clear_pan_retries_enabled,
         }
     }
 }
@@ -1100,6 +1118,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                     three_ds_decision_manager_config,
                     card_testing_guard_config,
                     card_testing_secret_key: card_testing_secret_key.map(Encryption::from),
+                    is_clear_pan_retries_enabled: None,
                 }
             }
             ProfileUpdate::RoutingAlgorithmUpdate {
@@ -1146,6 +1165,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 three_ds_decision_manager_config: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::ExtendedCardInfoUpdate {
                 is_extended_card_info_enabled,
@@ -1190,6 +1210,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 three_ds_decision_manager_config: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::ConnectorAgnosticMitUpdate {
                 is_connector_agnostic_mit_enabled,
@@ -1234,6 +1255,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 three_ds_decision_manager_config: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::DefaultRoutingFallbackUpdate {
                 default_fallback_routing,
@@ -1278,6 +1300,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 three_ds_decision_manager_config: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::NetworkTokenizationUpdate {
                 is_network_tokenization_enabled,
@@ -1322,6 +1345,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 three_ds_decision_manager_config: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::CollectCvvDuringPaymentUpdate {
                 should_collect_cvv_during_payment,
@@ -1366,6 +1390,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 three_ds_decision_manager_config: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::DecisionManagerRecordUpdate {
                 three_ds_decision_manager_config,
@@ -1410,6 +1435,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 three_ds_decision_manager_config: Some(three_ds_decision_manager_config),
                 card_testing_guard_config: None,
                 card_testing_secret_key: None,
+                is_clear_pan_retries_enabled: None,
             },
             ProfileUpdate::CardTestingSecretKeyUpdate {
                 card_testing_secret_key,
@@ -1454,6 +1480,7 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 three_ds_decision_manager_config: None,
                 card_testing_guard_config: None,
                 card_testing_secret_key: card_testing_secret_key.map(Encryption::from),
+                is_clear_pan_retries_enabled: None,
             },
         }
     }
@@ -1519,6 +1546,7 @@ impl super::behaviour::Conversion for Profile {
             three_ds_decision_manager_config: self.three_ds_decision_manager_config,
             card_testing_guard_config: self.card_testing_guard_config,
             card_testing_secret_key: self.card_testing_secret_key.map(|name| name.into()),
+            is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled,
         })
     }
 
@@ -1605,6 +1633,7 @@ impl super::behaviour::Conversion for Profile {
                         .and_then(|val| val.try_into_optionaloperation())
                     })
                     .await?,
+                is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
             })
         }
         .await
@@ -1665,6 +1694,7 @@ impl super::behaviour::Conversion for Profile {
             three_ds_decision_manager_config: self.three_ds_decision_manager_config,
             card_testing_guard_config: self.card_testing_guard_config,
             card_testing_secret_key: self.card_testing_secret_key.map(Encryption::from),
+            is_clear_pan_retries_enabled: Some(self.is_clear_pan_retries_enabled),
         })
     }
 }
diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs
index 2f8375b47c0..78b2144f3ed 100644
--- a/crates/hyperswitch_domain_models/src/payment_method_data.rs
+++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs
@@ -71,6 +71,10 @@ impl PaymentMethodData {
             Self::CardToken(_) | Self::MandatePayment => None,
         }
     }
+
+    pub fn is_network_token_payment_method_data(&self) -> bool {
+        matches!(self, Self::NetworkToken(_))
+    }
 }
 
 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs
index 606a8af51c3..d7816915ba5 100644
--- a/crates/hyperswitch_domain_models/src/payments.rs
+++ b/crates/hyperswitch_domain_models/src/payments.rs
@@ -35,13 +35,13 @@ use diesel_models::{
 };
 
 use self::payment_attempt::PaymentAttempt;
-#[cfg(feature = "v1")]
-use crate::RemoteStorageObject;
 #[cfg(feature = "v2")]
 use crate::{
     address::Address, business_profile, errors, merchant_account, payment_address,
     payment_method_data, ApiModelToDieselModelConvertor,
 };
+#[cfg(feature = "v1")]
+use crate::{payment_method_data, RemoteStorageObject};
 
 #[cfg(feature = "v1")]
 #[derive(Clone, Debug, PartialEq, serde::Serialize, ToEncryption)]
@@ -633,3 +633,80 @@ where
         &self.payment_intent.id
     }
 }
+
+#[derive(Clone, serde::Serialize, Debug)]
+pub enum VaultOperation {
+    ExistingVaultData(VaultData),
+}
+
+impl VaultOperation {
+    pub fn get_updated_vault_data(
+        existing_vault_data: Option<&Self>,
+        payment_method_data: &payment_method_data::PaymentMethodData,
+    ) -> Option<Self> {
+        match (existing_vault_data, payment_method_data) {
+            (None, payment_method_data::PaymentMethodData::Card(card)) => {
+                Some(Self::ExistingVaultData(VaultData::Card(card.clone())))
+            }
+            (None, payment_method_data::PaymentMethodData::NetworkToken(nt_data)) => Some(
+                Self::ExistingVaultData(VaultData::NetworkToken(nt_data.clone())),
+            ),
+            (Some(Self::ExistingVaultData(vault_data)), payment_method_data) => {
+                match (vault_data, payment_method_data) {
+                    (
+                        VaultData::Card(card),
+                        payment_method_data::PaymentMethodData::NetworkToken(nt_data),
+                    ) => Some(Self::ExistingVaultData(VaultData::CardAndNetworkToken(
+                        Box::new(CardAndNetworkTokenData {
+                            card_data: card.clone(),
+                            network_token_data: nt_data.clone(),
+                        }),
+                    ))),
+                    (
+                        VaultData::NetworkToken(nt_data),
+                        payment_method_data::PaymentMethodData::Card(card),
+                    ) => Some(Self::ExistingVaultData(VaultData::CardAndNetworkToken(
+                        Box::new(CardAndNetworkTokenData {
+                            card_data: card.clone(),
+                            network_token_data: nt_data.clone(),
+                        }),
+                    ))),
+                    _ => Some(Self::ExistingVaultData(vault_data.clone())),
+                }
+            }
+            //payment_method_data is not card or network token
+            _ => None,
+        }
+    }
+}
+
+#[derive(Clone, serde::Serialize, Debug)]
+pub enum VaultData {
+    Card(payment_method_data::Card),
+    NetworkToken(payment_method_data::NetworkTokenData),
+    CardAndNetworkToken(Box<CardAndNetworkTokenData>),
+}
+
+#[derive(Default, Clone, serde::Serialize, Debug)]
+pub struct CardAndNetworkTokenData {
+    pub card_data: payment_method_data::Card,
+    pub network_token_data: payment_method_data::NetworkTokenData,
+}
+
+impl VaultData {
+    pub fn get_card_vault_data(&self) -> Option<payment_method_data::Card> {
+        match self {
+            Self::Card(card_data) => Some(card_data.clone()),
+            Self::NetworkToken(_network_token_data) => None,
+            Self::CardAndNetworkToken(vault_data) => Some(vault_data.card_data.clone()),
+        }
+    }
+
+    pub fn get_network_token_data(&self) -> Option<payment_method_data::NetworkTokenData> {
+        match self {
+            Self::Card(_card_data) => None,
+            Self::NetworkToken(network_token_data) => Some(network_token_data.clone()),
+            Self::CardAndNetworkToken(vault_data) => Some(vault_data.network_token_data.clone()),
+        }
+    }
+}
diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs
index 38b1ddb0f8b..157b8570522 100644
--- a/crates/router/src/core/admin.rs
+++ b/crates/router/src/core/admin.rs
@@ -3786,6 +3786,7 @@ impl ProfileCreateBridge for api::ProfileCreate {
                 .await
                 .change_context(errors::ApiErrorResponse::InternalServerError)
                 .attach_printable("error while generating card testing secret key")?,
+            is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled.unwrap_or_default(),
         }))
     }
 
@@ -3941,6 +3942,7 @@ impl ProfileCreateBridge for api::ProfileCreate {
                 .await
                 .change_context(errors::ApiErrorResponse::InternalServerError)
                 .attach_printable("error while generating card testing secret key")?,
+            is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled.unwrap_or_default(),
         }))
     }
 }
@@ -4227,6 +4229,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate {
                     .card_testing_guard_config
                     .map(ForeignInto::foreign_into),
                 card_testing_secret_key,
+                is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled,
             },
         )))
     }
diff --git a/crates/router/src/core/gsm.rs b/crates/router/src/core/gsm.rs
index c7daee111a9..6c544791a18 100644
--- a/crates/router/src/core/gsm.rs
+++ b/crates/router/src/core/gsm.rs
@@ -68,6 +68,7 @@ pub async fn update_gsm_rule(
         unified_code,
         unified_message,
         error_category,
+        clear_pan_possible,
     } = gsm_request;
     GsmInterface::update_gsm_rule(
         db,
@@ -84,6 +85,7 @@ pub async fn update_gsm_rule(
             unified_code,
             unified_message,
             error_category,
+            clear_pan_possible,
         },
     )
     .await
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 9f0fd705228..452364b654c 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -24,7 +24,7 @@ use api_models::payment_methods;
 #[cfg(feature = "payouts")]
 pub use api_models::{enums::PayoutConnectors, payouts as payout_types};
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
-use common_utils::ext_traits::Encode;
+use common_utils::ext_traits::{Encode, OptionExt};
 use common_utils::{consts::DEFAULT_LOCALE, id_type};
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use common_utils::{
@@ -47,7 +47,9 @@ use hyperswitch_domain_models::api::{GenericLinks, GenericLinksData};
 use hyperswitch_domain_models::mandates::CommonMandateReference;
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use hyperswitch_domain_models::payment_method_data;
-use hyperswitch_domain_models::payments::{payment_attempt::PaymentAttempt, PaymentIntent};
+use hyperswitch_domain_models::payments::{
+    payment_attempt::PaymentAttempt, PaymentIntent, VaultData,
+};
 use masking::{PeekInterface, Secret};
 use router_env::{instrument, tracing};
 use time::Duration;
@@ -541,6 +543,8 @@ pub async fn retrieve_payment_method_with_token(
     mandate_id: Option<api_models::payments::MandateIds>,
     payment_method_info: Option<domain::PaymentMethod>,
     business_profile: &domain::Profile,
+    should_retry_with_pan: bool,
+    vault_data: Option<&VaultData>,
 ) -> RouterResult<storage::PaymentMethodDataWithId> {
     let token = match token_data {
         storage::PaymentTokenData::TemporaryGeneric(generic_token) => {
@@ -584,7 +588,7 @@ pub async fn retrieve_payment_method_with_token(
         }
 
         storage::PaymentTokenData::Permanent(card_token) => {
-            payment_helpers::retrieve_card_with_permanent_token(
+            payment_helpers::retrieve_payment_method_data_with_permanent_token(
                 state,
                 card_token.locker_id.as_ref().unwrap_or(&card_token.token),
                 card_token
@@ -596,9 +600,14 @@ pub async fn retrieve_payment_method_with_token(
                 merchant_key_store,
                 storage_scheme,
                 mandate_id,
-                payment_method_info,
+                payment_method_info
+                    .get_required_value("PaymentMethod")
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("PaymentMethod not found")?,
                 business_profile,
                 payment_attempt.connector.clone(),
+                should_retry_with_pan,
+                vault_data,
             )
             .await
             .map(|card| Some((card, enums::PaymentMethod::Card)))?
@@ -619,7 +628,7 @@ pub async fn retrieve_payment_method_with_token(
         }
 
         storage::PaymentTokenData::PermanentCard(card_token) => {
-            payment_helpers::retrieve_card_with_permanent_token(
+            payment_helpers::retrieve_payment_method_data_with_permanent_token(
                 state,
                 card_token.locker_id.as_ref().unwrap_or(&card_token.token),
                 card_token
@@ -631,9 +640,14 @@ pub async fn retrieve_payment_method_with_token(
                 merchant_key_store,
                 storage_scheme,
                 mandate_id,
-                payment_method_info,
+                payment_method_info
+                    .get_required_value("PaymentMethod")
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("PaymentMethod not found")?,
                 business_profile,
                 payment_attempt.connector.clone(),
+                should_retry_with_pan,
+                vault_data,
             )
             .await
             .map(|card| Some((card, enums::PaymentMethod::Card)))?
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 7ea847ce653..f29bcb98ee7 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -51,7 +51,7 @@ use hyperswitch_domain_models::router_response_types::RedirectForm;
 pub use hyperswitch_domain_models::{
     mandates::{CustomerAcceptance, MandateData},
     payment_address::PaymentAddress,
-    payments::HeaderPayload,
+    payments::{self as domain_payments, HeaderPayload},
     router_data::{PaymentMethodToken, RouterData},
     router_request_types::CustomerDetails,
 };
@@ -214,6 +214,7 @@ where
                 None,
                 profile,
                 false,
+                false, //should_retry_with_pan is set to false in case of PreDetermined ConnectorCallType
             )
             .await?;
 
@@ -519,6 +520,7 @@ where
                         None,
                         &business_profile,
                         false,
+                        false,
                     )
                     .await?;
 
@@ -638,6 +640,7 @@ where
                         None,
                         &business_profile,
                         false,
+                        false,
                     )
                     .await?;
 
@@ -659,7 +662,7 @@ where
                                 req_state.clone(),
                                 &mut payment_data,
                                 connectors,
-                                connector_data.clone(),
+                                &connector_data,
                                 router_data,
                                 &merchant_account,
                                 &key_store,
@@ -2738,6 +2741,7 @@ pub async fn call_connector_service<F, RouterDReq, ApiRequest, D>(
     frm_suggestion: Option<storage_enums::FrmSuggestion>,
     business_profile: &domain::Profile,
     is_retry_payment: bool,
+    should_retry_with_pan: bool,
 ) -> RouterResult<(
     RouterData<F, RouterDReq, router_types::PaymentsResponseData>,
     helpers::MerchantConnectorAccountType,
@@ -2790,6 +2794,7 @@ where
         key_store,
         customer,
         business_profile,
+        should_retry_with_pan,
     )
     .await?;
     *payment_data = pd;
@@ -2990,6 +2995,7 @@ pub async fn call_connector_service<F, RouterDReq, ApiRequest, D>(
     frm_suggestion: Option<storage_enums::FrmSuggestion>,
     business_profile: &domain::Profile,
     is_retry_payment: bool,
+    should_retry_with_pan: bool,
 ) -> RouterResult<RouterData<F, RouterDReq, router_types::PaymentsResponseData>>
 where
     F: Send + Clone + Sync,
@@ -4705,6 +4711,7 @@ pub async fn get_connector_tokenization_action_when_confirm_true<F, Req, D>(
     merchant_key_store: &domain::MerchantKeyStore,
     customer: &Option<domain::Customer>,
     business_profile: &domain::Profile,
+    should_retry_with_pan: bool,
 ) -> RouterResult<(D, TokenizationAction)>
 where
     F: Send + Clone,
@@ -4776,6 +4783,7 @@ where
                             merchant_key_store,
                             customer,
                             business_profile,
+                            should_retry_with_pan,
                         )
                         .await?;
                     payment_data.set_payment_method_data(payment_method_data);
@@ -4795,6 +4803,7 @@ where
                             merchant_key_store,
                             customer,
                             business_profile,
+                            should_retry_with_pan,
                         )
                         .await?;
 
@@ -4883,6 +4892,7 @@ where
                     merchant_key_store,
                     customer,
                     business_profile,
+                    false,
                 )
                 .await?;
             payment_data.set_payment_method_data(payment_method_data);
@@ -4950,6 +4960,7 @@ where
     pub service_details: Option<api_models::payments::CtpServiceDetails>,
     pub card_testing_guard_data:
         Option<hyperswitch_domain_models::card_testing_guard_data::CardTestingGuardData>,
+    pub vault_operation: Option<domain_payments::VaultOperation>,
 }
 
 #[derive(Clone, serde::Serialize, Debug)]
@@ -7190,7 +7201,6 @@ pub async fn payment_external_authentication<F: Clone + Sync>(
         &payment_intent,
         &key_store,
         storage_scheme,
-        &business_profile,
     )
     .await?
     .ok_or(errors::ApiErrorResponse::InternalServerError)
@@ -7603,6 +7613,9 @@ pub trait OperationSessionGetters<F> {
     fn get_force_sync(&self) -> Option<bool>;
     fn get_capture_method(&self) -> Option<enums::CaptureMethod>;
 
+    #[cfg(feature = "v1")]
+    fn get_vault_operation(&self) -> Option<&domain_payments::VaultOperation>;
+
     #[cfg(feature = "v2")]
     fn get_optional_payment_attempt(&self) -> Option<&storage::PaymentAttempt>;
 }
@@ -7647,6 +7660,9 @@ pub trait OperationSessionSetters<F> {
         straight_through_algorithm: serde_json::Value,
     );
     fn set_connector_in_payment_attempt(&mut self, connector: Option<String>);
+
+    #[cfg(feature = "v1")]
+    fn set_vault_operation(&mut self, vault_operation: domain_payments::VaultOperation);
 }
 
 #[cfg(feature = "v1")]
@@ -7779,6 +7795,11 @@ impl<F: Clone> OperationSessionGetters<F> for PaymentData<F> {
         self.payment_attempt.capture_method
     }
 
+    #[cfg(feature = "v1")]
+    fn get_vault_operation(&self) -> Option<&domain_payments::VaultOperation> {
+        self.vault_operation.as_ref()
+    }
+
     // #[cfg(feature = "v2")]
     // fn get_capture_method(&self) -> Option<enums::CaptureMethod> {
     //     Some(self.payment_intent.capture_method)
@@ -7895,6 +7916,10 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentData<F> {
     fn set_connector_in_payment_attempt(&mut self, connector: Option<String>) {
         self.payment_attempt.connector = connector;
     }
+
+    fn set_vault_operation(&mut self, vault_operation: domain_payments::VaultOperation) {
+        self.vault_operation = Some(vault_operation);
+    }
 }
 
 #[cfg(feature = "v2")]
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 21d84d3cba1..05b4d592c23 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -32,8 +32,8 @@ use hyperswitch_domain_models::{
     mandates::MandateData,
     payment_method_data::{GetPaymentMethodType, PazeWalletData},
     payments::{
-        payment_attempt::PaymentAttempt, payment_intent::PaymentIntentFetchConstraints,
-        PaymentIntent,
+        self as domain_payments, payment_attempt::PaymentAttempt,
+        payment_intent::PaymentIntentFetchConstraints, PaymentIntent,
     },
     router_data::KlarnaSdkResponse,
 };
@@ -1988,12 +1988,96 @@ pub async fn retrieve_card_with_permanent_token(
     todo!()
 }
 
+pub enum VaultFetchAction {
+    FetchCardDetailsFromLocker,
+    FetchCardDetailsForNetworkTransactionIdFlowFromLocker,
+    FetchNetworkTokenDataFromTokenizationService(String),
+    FetchNetworkTokenDetailsFromLocker(api_models::payments::NetworkTokenWithNTIRef),
+    NoFetchAction,
+}
+
+pub fn decide_payment_method_retrieval_action(
+    is_network_tokenization_enabled: bool,
+    mandate_id: Option<api_models::payments::MandateIds>,
+    connector: Option<api_enums::Connector>,
+    network_tokenization_supported_connectors: &HashSet<api_enums::Connector>,
+    should_retry_with_pan: bool,
+    network_token_requestor_ref_id: Option<String>,
+) -> VaultFetchAction {
+    let standard_flow = || {
+        determine_standard_vault_action(
+            is_network_tokenization_enabled,
+            mandate_id,
+            connector,
+            network_tokenization_supported_connectors,
+            network_token_requestor_ref_id,
+        )
+    };
+
+    should_retry_with_pan
+        .then_some(VaultFetchAction::FetchCardDetailsFromLocker)
+        .unwrap_or_else(standard_flow)
+}
+
+pub fn determine_standard_vault_action(
+    is_network_tokenization_enabled: bool,
+    mandate_id: Option<api_models::payments::MandateIds>,
+    connector: Option<api_enums::Connector>,
+    network_tokenization_supported_connectors: &HashSet<api_enums::Connector>,
+    network_token_requestor_ref_id: Option<String>,
+) -> VaultFetchAction {
+    let is_network_transaction_id_flow = mandate_id
+        .as_ref()
+        .map(|mandate_ids| mandate_ids.is_network_transaction_id_flow())
+        .unwrap_or(false);
+
+    if !is_network_tokenization_enabled {
+        if is_network_transaction_id_flow {
+            VaultFetchAction::FetchCardDetailsForNetworkTransactionIdFlowFromLocker
+        } else {
+            VaultFetchAction::FetchCardDetailsFromLocker
+        }
+    } else {
+        match mandate_id {
+            Some(mandate_ids) => match mandate_ids.mandate_reference_id {
+                Some(api_models::payments::MandateReferenceId::NetworkTokenWithNTI(nt_data)) => {
+                    VaultFetchAction::FetchNetworkTokenDetailsFromLocker(nt_data)
+                }
+                Some(api_models::payments::MandateReferenceId::NetworkMandateId(_)) => {
+                    VaultFetchAction::FetchCardDetailsForNetworkTransactionIdFlowFromLocker
+                }
+                Some(api_models::payments::MandateReferenceId::ConnectorMandateId(_)) | None => {
+                    VaultFetchAction::NoFetchAction
+                }
+            },
+            None => {
+                //saved card flow
+                let is_network_token_supported_connector = connector
+                    .map(|conn| network_tokenization_supported_connectors.contains(&conn))
+                    .unwrap_or(false);
+
+                match (
+                    is_network_token_supported_connector,
+                    network_token_requestor_ref_id,
+                ) {
+                    (true, Some(ref_id)) => {
+                        VaultFetchAction::FetchNetworkTokenDataFromTokenizationService(ref_id)
+                    }
+                    (false, Some(_)) | (true, None) | (false, None) => {
+                        VaultFetchAction::FetchCardDetailsFromLocker
+                    }
+                }
+            }
+        }
+    }
+}
+
 #[cfg(all(
     any(feature = "v2", feature = "v1"),
     not(feature = "payment_methods_v2")
 ))]
 #[allow(clippy::too_many_arguments)]
-pub async fn retrieve_card_with_permanent_token(
+pub async fn retrieve_payment_method_data_with_permanent_token(
     state: &SessionState,
     locker_id: &str,
     _payment_method_id: &str,
@@ -2002,9 +2086,11 @@ pub async fn retrieve_card_with_permanent_token(
     _merchant_key_store: &domain::MerchantKeyStore,
     _storage_scheme: enums::MerchantStorageScheme,
     mandate_id: Option<api_models::payments::MandateIds>,
-    payment_method_info: Option<domain::PaymentMethod>,
+    payment_method_info: domain::PaymentMethod,
     business_profile: &domain::Profile,
     connector: Option<String>,
+    should_retry_with_pan: bool,
+    vault_data: Option<&domain_payments::VaultData>,
 ) -> RouterResult<domain::PaymentMethodData> {
     let customer_id = payment_intent
         .customer_id
@@ -2014,238 +2100,176 @@ pub async fn retrieve_card_with_permanent_token(
             message: "no customer id provided for the payment".to_string(),
         })?;
 
-    if !business_profile.is_network_tokenization_enabled {
-        let is_network_transaction_id_flow = mandate_id
-            .map(|mandate_ids| mandate_ids.is_network_transaction_id_flow())
-            .unwrap_or(false);
+    let network_tokenization_supported_connectors = &state
+        .conf
+        .network_tokenization_supported_connectors
+        .connector_list;
 
-        if is_network_transaction_id_flow {
-            let card_details_from_locker = cards::get_card_from_locker(
-                state,
-                customer_id,
-                &payment_intent.merchant_id,
-                locker_id,
-            )
-            .await
-            .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("failed to fetch card details from locker")?;
-
-            let card_network = card_details_from_locker
-                .card_brand
-                .map(|card_brand| enums::CardNetwork::from_str(&card_brand))
-                .transpose()
-                .map_err(|e| {
-                    logger::error!("Failed to parse card network {e:?}");
+    let connector_variant = connector
+        .as_ref()
+        .map(|conn| {
+            api_enums::Connector::from_str(conn.as_str())
+                .change_context(errors::ApiErrorResponse::InvalidDataValue {
+                    field_name: "connector",
                 })
-                .ok()
-                .flatten();
+                .attach_printable_lazy(|| format!("unable to parse connector name {connector:?}"))
+        })
+        .transpose()?;
 
-            let card_details_for_network_transaction_id = hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId {
-                            card_number: card_details_from_locker.card_number,
-                            card_exp_month: card_details_from_locker.card_exp_month,
-                            card_exp_year: card_details_from_locker.card_exp_year,
-                            card_issuer: None,
-                            card_network,
-                            card_type: None,
-                            card_issuing_country: None,
-                            bank_code: None,
-                            nick_name: card_details_from_locker.nick_name.map(masking::Secret::new),
-                            card_holder_name: card_details_from_locker.name_on_card.clone(),
-                        };
+    let vault_fetch_action = decide_payment_method_retrieval_action(
+        business_profile.is_network_tokenization_enabled,
+        mandate_id,
+        connector_variant,
+        network_tokenization_supported_connectors,
+        should_retry_with_pan,
+        payment_method_info
+            .network_token_requestor_reference_id
+            .clone(),
+    );
+    match vault_fetch_action {
+        VaultFetchAction::FetchCardDetailsFromLocker => {
+            let card = vault_data
+                .and_then(|vault_data| vault_data.get_card_vault_data())
+                .map(Ok)
+                .async_unwrap_or_else(|| async {
+                    fetch_card_details_from_locker(
+                        state,
+                        customer_id,
+                        &payment_intent.merchant_id,
+                        locker_id,
+                        card_token_data,
+                    )
+                    .await
+                })
+                .await?;
 
-            Ok(
-                domain::PaymentMethodData::CardDetailsForNetworkTransactionId(
-                    card_details_for_network_transaction_id,
-                ),
-            )
-        } else {
-            fetch_card_details_from_locker(
+            Ok(domain::PaymentMethodData::Card(card))
+        }
+        VaultFetchAction::FetchCardDetailsForNetworkTransactionIdFlowFromLocker => {
+            fetch_card_details_for_network_transaction_flow_from_locker(
                 state,
                 customer_id,
                 &payment_intent.merchant_id,
                 locker_id,
-                card_token_data,
             )
             .await
             .change_context(errors::ApiErrorResponse::InternalServerError)
             .attach_printable("failed to fetch card information from the permanent locker")
         }
-    } else {
-        match (payment_method_info, mandate_id) {
-            (None, _) => Err(errors::ApiErrorResponse::InternalServerError)
-                .attach_printable("Payment method data is not present"),
-            (Some(ref pm_data), None) => {
-                // Regular (non-mandate) Payment flow
-                let network_tokenization_supported_connectors = &state
-                    .conf
-                    .network_tokenization_supported_connectors
-                    .connector_list;
-                let connector_variant = connector
-                    .as_ref()
-                    .map(|conn| {
-                        api_enums::Connector::from_str(conn.as_str())
-                            .change_context(errors::ApiErrorResponse::InvalidDataValue {
-                                field_name: "connector",
-                            })
-                            .attach_printable_lazy(|| {
-                                format!("unable to parse connector name {connector:?}")
-                            })
-                    })
-                    .transpose()?;
-                if let (Some(_conn), Some(token_ref)) = (
-                    connector_variant
-                        .filter(|conn| network_tokenization_supported_connectors.contains(conn)),
-                    pm_data.network_token_requestor_reference_id.clone(),
-                ) {
-                    logger::info!("Fetching network token data from tokenization service");
-                    match network_tokenization::get_token_from_tokenization_service(
-                        state, token_ref, pm_data,
-                    )
-                    .await
-                    .change_context(errors::ApiErrorResponse::InternalServerError)
-                    .attach_printable(
-                        "failed to fetch network token data from tokenization service",
-                    ) {
-                        Ok(network_token_data) => {
-                            Ok(domain::PaymentMethodData::NetworkToken(network_token_data))
-                        }
-                        Err(err) => {
-                            logger::info!("Failed to fetch network token data from tokenization service {err:?}");
-                            logger::info!("Falling back to fetch card details from locker");
-                            fetch_card_details_from_locker(
-                                state,
-                                customer_id,
-                                &payment_intent.merchant_id,
-                                locker_id,
-                                card_token_data,
-                            )
-                            .await
-                            .change_context(errors::ApiErrorResponse::InternalServerError)
-                            .attach_printable(
-                                "failed to fetch card information from the permanent locker",
-                            )
-                        }
-                    }
-                } else {
-                    logger::info!("Either the connector is not in the NT supported list or token requestor reference ID is absent");
-                    logger::info!("Falling back to fetch card details from locker");
-                    fetch_card_details_from_locker(
-                        state,
-                        customer_id,
-                        &payment_intent.merchant_id,
-                        locker_id,
-                        card_token_data,
-                    )
-                    .await
-                    .change_context(errors::ApiErrorResponse::InternalServerError)
-                    .attach_printable("failed to fetch card information from the permanent locker")
+        VaultFetchAction::FetchNetworkTokenDataFromTokenizationService(
+            network_token_requestor_ref_id,
+        ) => {
+            logger::info!("Fetching network token data from tokenization service");
+            match network_tokenization::get_token_from_tokenization_service(
+                state,
+                network_token_requestor_ref_id,
+                &payment_method_info,
+            )
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("failed to fetch network token data from tokenization service")
+            {
+                Ok(network_token_data) => {
+                    Ok(domain::PaymentMethodData::NetworkToken(network_token_data))
                 }
-            }
-            (Some(ref pm_data), Some(mandate_ids)) => {
-                // Mandate Payment flow
-                match mandate_ids.mandate_reference_id {
-                    Some(api_models::payments::MandateReferenceId::NetworkTokenWithNTI(
-                        nt_data,
-                    )) => {
-                        {
-                            if let Some(network_token_locker_id) =
-                                pm_data.network_token_locker_id.as_ref()
-                            {
-                                let mut token_data = cards::get_card_from_locker(
+                Err(err) => {
+                    logger::info!(
+                        "Failed to fetch network token data from tokenization service {err:?}"
+                    );
+                    logger::info!("Falling back to fetch card details from locker");
+                    Ok(domain::PaymentMethodData::Card(
+                        vault_data
+                            .and_then(|vault_data| vault_data.get_card_vault_data())
+                            .map(Ok)
+                            .async_unwrap_or_else(|| async {
+                                fetch_card_details_from_locker(
                                     state,
                                     customer_id,
                                     &payment_intent.merchant_id,
-                                    network_token_locker_id,
+                                    locker_id,
+                                    card_token_data,
                                 )
                                 .await
-                                .change_context(errors::ApiErrorResponse::InternalServerError)
-                                .attach_printable(
-                                    "failed to fetch network token information from the permanent locker",
-                                )?;
-                                let expiry = nt_data.token_exp_month.zip(nt_data.token_exp_year);
-                                if let Some((exp_month, exp_year)) = expiry {
-                                    token_data.card_exp_month = exp_month;
-                                    token_data.card_exp_year = exp_year;
-                                }
-                                let network_token_data = domain::NetworkTokenData {
-                                    token_number: token_data.card_number,
-                                    token_cryptogram: None,
-                                    token_exp_month: token_data.card_exp_month,
-                                    token_exp_year: token_data.card_exp_year,
-                                    nick_name: token_data.nick_name.map(masking::Secret::new),
-                                    card_issuer: None,
-                                    card_network: None,
-                                    card_type: None,
-                                    card_issuing_country: None,
-                                    bank_code: None,
-                                    eci: None,
-                                };
-                                Ok(domain::PaymentMethodData::NetworkToken(network_token_data))
-                            } else {
-                                // Mandate but network token locker id is not present
-                                Err(errors::ApiErrorResponse::InternalServerError)
-                                    .attach_printable("Network token locker id is not present")
-                            }
-                        }
-                    }
-
-                    Some(api_models::payments::MandateReferenceId::NetworkMandateId(_)) => {
-                        let card_details_from_locker = cards::get_card_from_locker(
+                            })
+                            .await?,
+                    ))
+                }
+            }
+        }
+        VaultFetchAction::FetchNetworkTokenDetailsFromLocker(nt_data) => {
+            if let Some(network_token_locker_id) =
+                payment_method_info.network_token_locker_id.as_ref()
+            {
+                let network_token_data = vault_data
+                    .and_then(|vault_data| vault_data.get_network_token_data())
+                    .map(Ok)
+                    .async_unwrap_or_else(|| async {
+                        fetch_network_token_details_from_locker(
                             state,
                             customer_id,
                             &payment_intent.merchant_id,
-                            locker_id,
+                            network_token_locker_id,
+                            nt_data,
                         )
                         .await
-                        .change_context(errors::ApiErrorResponse::InternalServerError)
-                        .attach_printable("failed to fetch card details from locker")?;
-
-                        let card_network = card_details_from_locker
-                            .card_brand
-                            .map(|card_brand| enums::CardNetwork::from_str(&card_brand))
-                            .transpose()
-                            .map_err(|e| {
-                                logger::error!("Failed to parse card network {e:?}");
-                            })
-                            .ok()
-                            .flatten();
-
-                        let card_details_for_network_transaction_id = hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId {
-                            card_number: card_details_from_locker.card_number,
-                            card_exp_month: card_details_from_locker.card_exp_month,
-                            card_exp_year: card_details_from_locker.card_exp_year,
-                            card_issuer: None,
-                            card_network,
-                            card_type: None,
-                            card_issuing_country: None,
-                            bank_code: None,
-                            nick_name: card_details_from_locker.nick_name.map(masking::Secret::new),
-                            card_holder_name: card_details_from_locker.name_on_card,
-                        };
-
-                        Ok(
-                            domain::PaymentMethodData::CardDetailsForNetworkTransactionId(
-                                card_details_for_network_transaction_id,
-                            ),
-                        )
-                    }
-
-                    Some(api_models::payments::MandateReferenceId::ConnectorMandateId(_))
-                    | None => Err(errors::ApiErrorResponse::InternalServerError)
-                        .attach_printable("Payment method data is not present"),
-                }
+                    })
+                    .await?;
+                Ok(domain::PaymentMethodData::NetworkToken(network_token_data))
+            } else {
+                Err(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Network token locker id is not present")
             }
         }
+        VaultFetchAction::NoFetchAction => Err(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Payment method data is not present"),
     }
 }
 
+#[cfg(all(
+    any(feature = "v2", feature = "v1"),
+    not(feature = "payment_methods_v2")
+))]
+#[allow(clippy::too_many_arguments)]
+pub async fn retrieve_card_with_permanent_token_for_external_authentication(
+    state: &SessionState,
+    locker_id: &str,
+    payment_intent: &PaymentIntent,
+    card_token_data: Option<&domain::CardToken>,
+    _merchant_key_store: &domain::MerchantKeyStore,
+    _storage_scheme: enums::MerchantStorageScheme,
+) -> RouterResult<domain::PaymentMethodData> {
+    let customer_id = payment_intent
+        .customer_id
+        .as_ref()
+        .get_required_value("customer_id")
+        .change_context(errors::ApiErrorResponse::UnprocessableEntity {
+            message: "no customer id provided for the payment".to_string(),
+        })?;
+    Ok(domain::PaymentMethodData::Card(
+        fetch_card_details_from_locker(
+            state,
+            customer_id,
+            &payment_intent.merchant_id,
+            locker_id,
+            card_token_data,
+        )
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("failed to fetch card information from the permanent locker")?,
+    ))
+}
+
+#[cfg(all(
+    any(feature = "v2", feature = "v1"),
+    not(feature = "payment_methods_v2")
+))]
 pub async fn fetch_card_details_from_locker(
     state: &SessionState,
     customer_id: &id_type::CustomerId,
     merchant_id: &id_type::MerchantId,
     locker_id: &str,
     card_token_data: Option<&domain::CardToken>,
-) -> RouterResult<domain::PaymentMethodData> {
+) -> RouterResult<domain::Card> {
     let card = cards::get_card_from_locker(state, customer_id, merchant_id, locker_id)
         .await
         .change_context(errors::ApiErrorResponse::InternalServerError)
@@ -2290,7 +2314,106 @@ pub async fn fetch_card_details_from_locker(
         card_issuing_country: None,
         bank_code: None,
     };
-    Ok(domain::PaymentMethodData::Card(api_card.into()))
+    Ok(api_card.into())
+}
+
+#[cfg(all(
+    any(feature = "v2", feature = "v1"),
+    not(feature = "payment_methods_v2")
+))]
+pub async fn fetch_network_token_details_from_locker(
+    state: &SessionState,
+    customer_id: &id_type::CustomerId,
+    merchant_id: &id_type::MerchantId,
+    network_token_locker_id: &str,
+    network_transaction_data: api_models::payments::NetworkTokenWithNTIRef,
+) -> RouterResult<domain::NetworkTokenData> {
+    let mut token_data =
+        cards::get_card_from_locker(state, customer_id, merchant_id, network_token_locker_id)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable(
+                "failed to fetch network token information from the permanent locker",
+            )?;
+    let expiry = network_transaction_data
+        .token_exp_month
+        .zip(network_transaction_data.token_exp_year);
+    if let Some((exp_month, exp_year)) = expiry {
+        token_data.card_exp_month = exp_month;
+        token_data.card_exp_year = exp_year;
+    }
+
+    let card_network = token_data
+        .card_brand
+        .map(|card_brand| enums::CardNetwork::from_str(&card_brand))
+        .transpose()
+        .map_err(|e| {
+            logger::error!("Failed to parse card network {e:?}");
+        })
+        .ok()
+        .flatten();
+
+    let network_token_data = domain::NetworkTokenData {
+        token_number: token_data.card_number,
+        token_cryptogram: None,
+        token_exp_month: token_data.card_exp_month,
+        token_exp_year: token_data.card_exp_year,
+        nick_name: token_data.nick_name.map(masking::Secret::new),
+        card_issuer: None,
+        card_network,
+        card_type: None,
+        card_issuing_country: None,
+        bank_code: None,
+        eci: None,
+    };
+    Ok(network_token_data)
+}
+
+#[cfg(all(
+    any(feature = "v2", feature = "v1"),
+    not(feature = "payment_methods_v2")
+))]
+pub async fn fetch_card_details_for_network_transaction_flow_from_locker(
+    state: &SessionState,
+    customer_id: &id_type::CustomerId,
+    merchant_id: &id_type::MerchantId,
+    locker_id: &str,
+) -> RouterResult<domain::PaymentMethodData> {
+    let card_details_from_locker =
+        cards::get_card_from_locker(state, customer_id, merchant_id, locker_id)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("failed to fetch card details from locker")?;
+
+    let card_network = card_details_from_locker
+        .card_brand
+        .map(|card_brand| enums::CardNetwork::from_str(&card_brand))
+        .transpose()
+        .map_err(|e| {
+            logger::error!("Failed to parse card network {e:?}");
+        })
+        .ok()
+        .flatten();
+
+    let card_details_for_network_transaction_id =
+        hyperswitch_domain_models::payment_method_data::CardDetailsForNetworkTransactionId {
+            card_number: card_details_from_locker.card_number,
+            card_exp_month: card_details_from_locker.card_exp_month,
+            card_exp_year: card_details_from_locker.card_exp_year,
+            card_issuer: None,
+            card_network,
+            card_type: None,
+            card_issuing_country: None,
+            bank_code: None,
+            nick_name: card_details_from_locker.nick_name.map(masking::Secret::new),
+            card_holder_name: card_details_from_locker.name_on_card.clone(),
+        };
+
+    Ok(
+        domain::PaymentMethodData::CardDetailsForNetworkTransactionId(
+            card_details_for_network_transaction_id,
+        ),
+    )
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -2424,6 +2547,7 @@ pub async fn make_pm_data<'a, F: Clone, R, D>(
     any(feature = "v1", feature = "v2"),
     not(feature = "payment_methods_v2")
 ))]
+#[allow(clippy::too_many_arguments)]
 pub async fn make_pm_data<'a, F: Clone, R, D>(
     operation: BoxedOperation<'a, F, R, D>,
     state: &'a SessionState,
@@ -2432,11 +2556,15 @@ pub async fn make_pm_data<'a, F: Clone, R, D>(
     customer: &Option<domain::Customer>,
     storage_scheme: common_enums::enums::MerchantStorageScheme,
     business_profile: &domain::Profile,
+    should_retry_with_pan: bool,
 ) -> RouterResult<(
     BoxedOperation<'a, F, R, D>,
     Option<domain::PaymentMethodData>,
     Option<String>,
 )> {
+    use super::OperationSessionSetters;
+    use crate::core::payments::OperationSessionGetters;
+
     let request = payment_data.payment_method_data.clone();
 
     let mut card_token_data = payment_data
@@ -2484,6 +2612,12 @@ pub async fn make_pm_data<'a, F: Clone, R, D>(
     // TODO: Handle case where payment method and token both are present in request properly.
     let (payment_method, pm_id) = match (&request, payment_data.token_data.as_ref()) {
         (_, Some(hyperswitch_token)) => {
+            let existing_vault_data = payment_data.get_vault_operation();
+
+            let vault_data = existing_vault_data.map(|data| match data {
+                domain_payments::VaultOperation::ExistingVaultData(vault_data) => vault_data,
+            });
+
             let pm_data = Box::pin(payment_methods::retrieve_payment_method_with_token(
                 state,
                 merchant_key_store,
@@ -2496,11 +2630,25 @@ pub async fn make_pm_data<'a, F: Clone, R, D>(
                 mandate_id,
                 payment_data.payment_method_info.clone(),
                 business_profile,
+                should_retry_with_pan,
+                vault_data,
             ))
             .await;
 
             let payment_method_details = pm_data.attach_printable("in 'make_pm_data'")?;
 
+            if let Some(ref payment_method_data) = payment_method_details.payment_method_data {
+                let updated_vault_operation =
+                    domain_payments::VaultOperation::get_updated_vault_data(
+                        existing_vault_data,
+                        payment_method_data,
+                    );
+
+                if let Some(vault_operation) = updated_vault_operation {
+                    payment_data.set_vault_operation(vault_operation);
+                }
+            };
+
             Ok::<_, error_stack::Report<errors::ApiErrorResponse>>(
                 if let Some(payment_method_data) = payment_method_details.payment_method_data {
                     payment_data.payment_attempt.payment_method =
@@ -6471,7 +6619,6 @@ pub async fn get_payment_method_details_from_payment_token(
     payment_intent: &PaymentIntent,
     key_store: &domain::MerchantKeyStore,
     storage_scheme: enums::MerchantStorageScheme,
-    business_profile: &domain::Profile,
 ) -> RouterResult<Option<(domain::PaymentMethodData, enums::PaymentMethod)>> {
     let hyperswitch_token = if let Some(token) = payment_attempt.payment_token.clone() {
         let redis_conn = state
@@ -6546,43 +6693,31 @@ pub async fn get_payment_method_details_from_payment_token(
             .await
         }
 
-        storage::PaymentTokenData::Permanent(card_token) => retrieve_card_with_permanent_token(
-            state,
-            &card_token.token,
-            card_token
-                .payment_method_id
-                .as_ref()
-                .unwrap_or(&card_token.token),
-            payment_intent,
-            None,
-            key_store,
-            storage_scheme,
-            None,
-            None,
-            business_profile,
-            payment_attempt.connector.clone(),
-        )
-        .await
-        .map(|card| Some((card, enums::PaymentMethod::Card))),
+        storage::PaymentTokenData::Permanent(card_token) => {
+            retrieve_card_with_permanent_token_for_external_authentication(
+                state,
+                &card_token.token,
+                payment_intent,
+                None,
+                key_store,
+                storage_scheme,
+            )
+            .await
+            .map(|card| Some((card, enums::PaymentMethod::Card)))
+        }
 
-        storage::PaymentTokenData::PermanentCard(card_token) => retrieve_card_with_permanent_token(
-            state,
-            &card_token.token,
-            card_token
-                .payment_method_id
-                .as_ref()
-                .unwrap_or(&card_token.token),
-            payment_intent,
-            None,
-            key_store,
-            storage_scheme,
-            None,
-            None,
-            business_profile,
-            payment_attempt.connector.clone(),
-        )
-        .await
-        .map(|card| Some((card, enums::PaymentMethod::Card))),
+        storage::PaymentTokenData::PermanentCard(card_token) => {
+            retrieve_card_with_permanent_token_for_external_authentication(
+                state,
+                &card_token.token,
+                payment_intent,
+                None,
+                key_store,
+                storage_scheme,
+            )
+            .await
+            .map(|card| Some((card, enums::PaymentMethod::Card)))
+        }
 
         storage::PaymentTokenData::AuthBankDebit(auth_token) => {
             retrieve_payment_method_from_auth_service(
diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs
index a1ebaa04152..fde773de8a1 100644
--- a/crates/router/src/core/payments/operations.rs
+++ b/crates/router/src/core/payments/operations.rs
@@ -261,6 +261,7 @@ pub trait Domain<F: Clone, R, D>: Send + Sync {
         merchant_key_store: &domain::MerchantKeyStore,
         customer: &Option<domain::Customer>,
         business_profile: &domain::Profile,
+        should_retry_with_pan: bool,
     ) -> RouterResult<(
         BoxedOperation<'a, F, R, D>,
         Option<domain::PaymentMethodData>,
@@ -557,6 +558,7 @@ where
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         BoxedOperation<'a, F, api::PaymentsRetrieveRequest, D>,
         Option<domain::PaymentMethodData>,
@@ -651,6 +653,7 @@ where
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         BoxedOperation<'a, F, api::PaymentsCaptureRequest, D>,
         Option<domain::PaymentMethodData>,
@@ -756,6 +759,7 @@ where
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         BoxedOperation<'a, F, api::PaymentsCancelRequest, D>,
         Option<domain::PaymentMethodData>,
@@ -840,6 +844,7 @@ where
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         BoxedOperation<'a, F, api::PaymentsRejectRequest, D>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs
index 393d08a68d4..3ab64a1361d 100644
--- a/crates/router/src/core/payments/operations/payment_approve.rs
+++ b/crates/router/src/core/payments/operations/payment_approve.rs
@@ -201,6 +201,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsCaptureR
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs
index d713e7aa567..f5ce637a5ba 100644
--- a/crates/router/src/core/payments/operations/payment_cancel.rs
+++ b/crates/router/src/core/payments/operations/payment_cancel.rs
@@ -212,6 +212,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsCancelRe
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs
index 2a58adb822c..a6c9594eb84 100644
--- a/crates/router/src/core/payments/operations/payment_capture.rs
+++ b/crates/router/src/core/payments/operations/payment_capture.rs
@@ -261,6 +261,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, payments::PaymentData<F>, api::Paymen
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
diff --git a/crates/router/src/core/payments/operations/payment_capture_v2.rs b/crates/router/src/core/payments/operations/payment_capture_v2.rs
index 93b7ffa6c19..f69dd8de62c 100644
--- a/crates/router/src/core/payments/operations/payment_capture_v2.rs
+++ b/crates/router/src/core/payments/operations/payment_capture_v2.rs
@@ -247,6 +247,7 @@ impl<F: Clone + Send> Domain<F, PaymentsCaptureRequest, PaymentCaptureData<F>> f
         _key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         BoxedConfirmOperation<'a, F>,
         Option<domain::PaymentMethodData>,
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 fab2a9144c7..2dc118a60fe 100644
--- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs
+++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
@@ -355,6 +355,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let customer_details = Some(CustomerDetails {
@@ -412,6 +413,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
         merchant_key_store: &domain::MerchantKeyStore,
         customer: &Option<domain::Customer>,
         business_profile: &domain::Profile,
+        should_retry_with_pan: bool,
     ) -> RouterResult<(
         CompleteAuthorizeOperation<'a, F>,
         Option<domain::PaymentMethodData>,
@@ -425,6 +427,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
             customer,
             storage_scheme,
             business_profile,
+            should_retry_with_pan,
         ))
         .await?;
         Ok((op, payment_method_data, pm_id))
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 852e51f4a8e..556954155e8 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -827,6 +827,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             session_id: None,
             service_details: request.ctp_service_details.clone(),
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -909,6 +910,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
         key_store: &domain::MerchantKeyStore,
         customer: &Option<domain::Customer>,
         business_profile: &domain::Profile,
+        should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentConfirmOperation<'a, F>,
         Option<domain::PaymentMethodData>,
@@ -922,6 +924,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
             customer,
             storage_scheme,
             business_profile,
+            should_retry_with_pan,
         ))
         .await?;
         utils::when(payment_method_data.is_none(), || {
diff --git a/crates/router/src/core/payments/operations/payment_confirm_intent.rs b/crates/router/src/core/payments/operations/payment_confirm_intent.rs
index 40b1918323c..a5b0e6eb65e 100644
--- a/crates/router/src/core/payments/operations/payment_confirm_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm_intent.rs
@@ -321,6 +321,7 @@ impl<F: Clone + Send + Sync> Domain<F, PaymentsConfirmIntentRequest, PaymentConf
         key_store: &domain::MerchantKeyStore,
         customer: &Option<domain::Customer>,
         business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         BoxedConfirmOperation<'a, F>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index 06036c4bc59..7211b88a10a 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -626,6 +626,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -777,6 +778,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
         merchant_key_store: &domain::MerchantKeyStore,
         customer: &Option<domain::Customer>,
         business_profile: &domain::Profile,
+        should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentCreateOperation<'a, F>,
         Option<domain::PaymentMethodData>,
@@ -790,6 +792,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
             customer,
             storage_scheme,
             business_profile,
+            should_retry_with_pan,
         ))
         .await
     }
diff --git a/crates/router/src/core/payments/operations/payment_create_intent.rs b/crates/router/src/core/payments/operations/payment_create_intent.rs
index 1cd0010bdf6..755c4e153ce 100644
--- a/crates/router/src/core/payments/operations/payment_create_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_create_intent.rs
@@ -258,6 +258,7 @@ impl<F: Clone + Send + Sync> Domain<F, PaymentsCreateIntentRequest, payments::Pa
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentsCreateIntentOperation<'a, F>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/operations/payment_get.rs b/crates/router/src/core/payments/operations/payment_get.rs
index fdf5350bed8..f15990d67b9 100644
--- a/crates/router/src/core/payments/operations/payment_get.rs
+++ b/crates/router/src/core/payments/operations/payment_get.rs
@@ -251,6 +251,7 @@ impl<F: Clone + Send + Sync> Domain<F, PaymentsRetrieveRequest, PaymentStatusDat
         _key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         BoxedConfirmOperation<'a, F>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/operations/payment_get_intent.rs b/crates/router/src/core/payments/operations/payment_get_intent.rs
index 0041209eb0f..05f939ee31b 100644
--- a/crates/router/src/core/payments/operations/payment_get_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_get_intent.rs
@@ -190,6 +190,7 @@ impl<F: Clone + Send + Sync> Domain<F, PaymentsGetIntentRequest, payments::Payme
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentsGetIntentOperation<'a, F>,
         Option<domain::PaymentMethodData>,
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 0a3efc92ccd..45a659c85b5 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
@@ -170,6 +170,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsPostSess
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
         let get_trackers_response = operations::GetTrackerResponse {
             operation: Box::new(self),
@@ -214,6 +215,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsPostSessionTokensRequest, Pa
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentPostSessionTokensOperation<'a, F>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs
index 91317dbde68..1d919fc45bd 100644
--- a/crates/router/src/core/payments/operations/payment_reject.rs
+++ b/crates/router/src/core/payments/operations/payment_reject.rs
@@ -199,6 +199,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, PaymentsCancelRequest
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs
index a86ca0be4ef..5833ec3e87a 100644
--- a/crates/router/src/core/payments/operations/payment_session.rs
+++ b/crates/router/src/core/payments/operations/payment_session.rs
@@ -217,6 +217,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsSessionR
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -339,6 +340,7 @@ where
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentSessionOperation<'b, F>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/operations/payment_session_intent.rs b/crates/router/src/core/payments/operations/payment_session_intent.rs
index 9bca88c6d04..b2ab23223d7 100644
--- a/crates/router/src/core/payments/operations/payment_session_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_session_intent.rs
@@ -197,6 +197,7 @@ impl<F: Clone + Send + Sync> Domain<F, PaymentsSessionRequest, payments::Payment
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentsCreateIntentOperation<'a, F>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs
index ebae54e1220..8023f9ed959 100644
--- a/crates/router/src/core/payments/operations/payment_start.rs
+++ b/crates/router/src/core/payments/operations/payment_start.rs
@@ -204,6 +204,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsStartReq
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -311,6 +312,7 @@ where
         merchant_key_store: &domain::MerchantKeyStore,
         customer: &Option<domain::Customer>,
         business_profile: &domain::Profile,
+        should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentSessionOperation<'a, F>,
         Option<domain::PaymentMethodData>,
@@ -331,6 +333,7 @@ where
                 customer,
                 storage_scheme,
                 business_profile,
+                should_retry_with_pan,
             ))
             .await
         } else {
diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs
index e05eed41419..bcfe90367d7 100644
--- a/crates/router/src/core/payments/operations/payment_status.rs
+++ b/crates/router/src/core/payments/operations/payment_status.rs
@@ -95,6 +95,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentStatusOperation<'a, F, api::PaymentsRequest>,
         Option<domain::PaymentMethodData>,
@@ -535,6 +536,7 @@ async fn get_tracker_for_sync<
         session_id: None,
         service_details: None,
         card_testing_guard_data: None,
+        vault_operation: None,
     };
 
     let get_trackers_response = operations::GetTrackerResponse {
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index 89a94552bc2..e7cc8a41b85 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -496,6 +496,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -646,6 +647,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
         merchant_key_store: &domain::MerchantKeyStore,
         customer: &Option<domain::Customer>,
         business_profile: &domain::Profile,
+        should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentUpdateOperation<'a, F>,
         Option<domain::PaymentMethodData>,
@@ -659,6 +661,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsRequest, PaymentData<F>> for
             customer,
             storage_scheme,
             business_profile,
+            should_retry_with_pan,
         ))
         .await
     }
diff --git a/crates/router/src/core/payments/operations/payment_update_intent.rs b/crates/router/src/core/payments/operations/payment_update_intent.rs
index af6b7d57838..7662c07eee0 100644
--- a/crates/router/src/core/payments/operations/payment_update_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_update_intent.rs
@@ -419,6 +419,7 @@ impl<F: Clone + Send> Domain<F, PaymentsUpdateIntentRequest, payments::PaymentIn
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentsUpdateIntentOperation<'a, F>,
         Option<domain::PaymentMethodData>,
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 8ef656599a7..cdd823483e2 100644
--- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
+++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
@@ -178,6 +178,7 @@ impl<F: Send + Clone + Sync>
             session_id: None,
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -348,6 +349,7 @@ impl<F: Clone + Send + Sync>
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentIncrementalAuthorizationOperation<'a, F>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs
index 0d31c4d5de1..aac91e20c10 100644
--- a/crates/router/src/core/payments/operations/tax_calculation.rs
+++ b/crates/router/src/core/payments/operations/tax_calculation.rs
@@ -184,6 +184,7 @@ impl<F: Send + Clone + Sync>
             session_id: request.session_id.clone(),
             service_details: None,
             card_testing_guard_data: None,
+            vault_operation: None,
         };
         let get_trackers_response = operations::GetTrackerResponse {
             operation: Box::new(self),
@@ -338,6 +339,7 @@ impl<F: Clone + Send + Sync> Domain<F, api::PaymentsDynamicTaxCalculationRequest
         _merchant_key_store: &domain::MerchantKeyStore,
         _customer: &Option<domain::Customer>,
         _business_profile: &domain::Profile,
+        _should_retry_with_pan: bool,
     ) -> RouterResult<(
         PaymentSessionUpdateOperation<'a, F>,
         Option<domain::PaymentMethodData>,
diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs
index d113cfd55de..5fdf14dbf5a 100644
--- a/crates/router/src/core/payments/retry.rs
+++ b/crates/router/src/core/payments/retry.rs
@@ -35,7 +35,7 @@ pub async fn do_gsm_actions<F, ApiRequest, FData, D>(
     req_state: ReqState,
     payment_data: &mut D,
     mut connectors: IntoIter<api::ConnectorData>,
-    original_connector_data: api::ConnectorData,
+    original_connector_data: &api::ConnectorData,
     mut router_data: types::RouterData<F, FData, types::PaymentsResponseData>,
     merchant_account: &domain::MerchantAccount,
     key_store: &domain::MerchantKeyStore,
@@ -110,6 +110,7 @@ where
             true,
             frm_suggestion,
             business_profile,
+            false, //should_retry_with_pan is not applicable for step-up
         )
         .await?;
     }
@@ -140,12 +141,29 @@ where
                         break;
                     }
 
-                    let connector = super::get_connector_data(&mut connectors)?;
+                    let is_network_token = payment_data
+                        .get_payment_method_data()
+                        .map(|pmd| pmd.is_network_token_payment_method_data())
+                        .unwrap_or(false);
+
+                    let should_retry_with_pan = is_network_token
+                        && initial_gsm
+                            .as_ref()
+                            .map(|gsm| gsm.clear_pan_possible)
+                            .unwrap_or(false)
+                        && business_profile.is_clear_pan_retries_enabled;
+
+                    let connector = if should_retry_with_pan {
+                        // If should_retry_with_pan is true, it indicates that we are retrying with PAN using the same connector.
+                        original_connector_data.clone()
+                    } else {
+                        super::get_connector_data(&mut connectors)?
+                    };
 
                     router_data = do_retry(
                         &state.clone(),
                         req_state.clone(),
-                        connector,
+                        &connector,
                         operation,
                         customer,
                         merchant_account,
@@ -158,6 +176,7 @@ where
                         false,
                         frm_suggestion,
                         business_profile,
+                        should_retry_with_pan,
                     )
                     .await?;
 
@@ -297,7 +316,7 @@ fn get_flow_name<F>() -> RouterResult<String> {
 pub async fn do_retry<F, ApiRequest, FData, D>(
     state: &routes::SessionState,
     req_state: ReqState,
-    connector: api::ConnectorData,
+    connector: &api::ConnectorData,
     operation: &operations::BoxedOperation<'_, F, ApiRequest, D>,
     customer: &Option<domain::Customer>,
     merchant_account: &domain::MerchantAccount,
@@ -309,6 +328,7 @@ pub async fn do_retry<F, ApiRequest, FData, D>(
     is_step_up: bool,
     frm_suggestion: Option<storage_enums::FrmSuggestion>,
     business_profile: &domain::Profile,
+    should_retry_with_pan: bool,
 ) -> RouterResult<types::RouterData<F, FData, types::PaymentsResponseData>>
 where
     F: Clone + Send + Sync,
@@ -341,7 +361,7 @@ where
         req_state,
         merchant_account,
         key_store,
-        connector,
+        connector.clone(),
         operation,
         payment_data,
         customer,
@@ -352,6 +372,7 @@ where
         frm_suggestion,
         business_profile,
         true,
+        should_retry_with_pan,
     )
     .await?;
 
diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs
index 2852766cdd3..67e8990e113 100644
--- a/crates/router/src/types/api/admin.rs
+++ b/crates/router/src/types/api/admin.rs
@@ -187,6 +187,7 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
             card_testing_guard_config: item
                 .card_testing_guard_config
                 .map(ForeignInto::foreign_into),
+            is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
         })
     }
 }
@@ -261,6 +262,7 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
             card_testing_guard_config: item
                 .card_testing_guard_config
                 .map(ForeignInto::foreign_into),
+            is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
         })
     }
 }
@@ -435,5 +437,6 @@ pub async fn create_profile_from_merchant_account(
             .await
             .change_context(errors::ApiErrorResponse::InternalServerError)
             .attach_printable("error while generating card testing secret key")?,
+        is_clear_pan_retries_enabled: request.is_clear_pan_retries_enabled.unwrap_or_default(),
     }))
 }
diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs
index 8938461eec4..1035aed2f99 100644
--- a/crates/router/src/types/transformers.rs
+++ b/crates/router/src/types/transformers.rs
@@ -1838,6 +1838,7 @@ impl ForeignFrom<gsm_api_types::GsmCreateRequest> for storage::GatewayStatusMapp
             unified_code: value.unified_code,
             unified_message: value.unified_message,
             error_category: value.error_category,
+            clear_pan_possible: value.clear_pan_possible,
         }
     }
 }
@@ -1857,6 +1858,7 @@ impl ForeignFrom<storage::GatewayStatusMap> for gsm_api_types::GsmResponse {
             unified_code: value.unified_code,
             unified_message: value.unified_message,
             error_category: value.error_category,
+            clear_pan_possible: value.clear_pan_possible,
         }
     }
 }
diff --git a/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/down.sql b/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/down.sql
new file mode 100644
index 00000000000..80199b9a334
--- /dev/null
+++ b/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/down.sql
@@ -0,0 +1,2 @@
+-- This file should undo anything in `up.sql`
+ALTER TABLE gateway_status_map DROP COLUMN IF EXISTS clear_pan_possible;
\ No newline at end of file
diff --git a/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/up.sql b/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/up.sql
new file mode 100644
index 00000000000..4423df380c4
--- /dev/null
+++ b/migrations/2024-12-10-091820_add-clear-pan-possible-to-gsm/up.sql
@@ -0,0 +1,2 @@
+-- Your SQL goes here
+ALTER TABLE gateway_status_map ADD COLUMN IF NOT EXISTS clear_pan_possible BOOLEAN NOT NULL DEFAULT FALSE;
\ No newline at end of file
diff --git a/migrations/2025-02-27-171444_add-clear-pan-retries-enabled-to-profile/down.sql b/migrations/2025-02-27-171444_add-clear-pan-retries-enabled-to-profile/down.sql
new file mode 100644
index 00000000000..ac61e6b3dca
--- /dev/null
+++ b/migrations/2025-02-27-171444_add-clear-pan-retries-enabled-to-profile/down.sql
@@ -0,0 +1,2 @@
+-- This file should undo anything in `up.sql`
+ALTER TABLE business_profile DROP COLUMN IF EXISTS is_clear_pan_retries_enabled;
\ No newline at end of file
diff --git a/migrations/2025-02-27-171444_add-clear-pan-retries-enabled-to-profile/up.sql b/migrations/2025-02-27-171444_add-clear-pan-retries-enabled-to-profile/up.sql
new file mode 100644
index 00000000000..9a877729291
--- /dev/null
+++ b/migrations/2025-02-27-171444_add-clear-pan-retries-enabled-to-profile/up.sql
@@ -0,0 +1,2 @@
+-- Your SQL goes here
+ALTER TABLE business_profile ADD COLUMN IF NOT EXISTS is_clear_pan_retries_enabled BOOLEAN NOT NULL DEFAULT FALSE;
\ No newline at end of file

## 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 -->
Add support to retry a transaction with clear PAN or Network Token
- added support for clear pan retry with same connector when previous attempt failed with payment method data - network token.
- refactored `make_pm_data` which does fetch payment method data from locker and construction of payment method data domain types.
- refactored `make_pm_data` for reducing locker calls during retries. by adding vault_data which holds payment method data from previous attempt.

### Additional Changes

- [x] This PR modifies the API contract
- [x] 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)?
-->
test cases - 
1 - enable network tokenization, auto retries for profile
2 - make a setup future usage= on_session payment.
3 - make saved card payment (with payment token) (payment will happen with network token + cryptogram) with adyen, if it fails, a retry will happen with card data fetched from locker with same connector.

verification - 2 payment attempts will be created for that payment intent id. 1st attempt payment method data would be network token and 2nd would be card

Curl for test case added to the [issue](https://github.com/juspay/hyperswitch/issues/6925)


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