Bug: [FEATURE] Add external vault support in v1



Add external vault support in v1 payments flow.
Currently we only save card in hs-card-vault
Added new support to save card in external vault based merchant-profile configuration.


diff --git a/crates/api_models/src/admin.rs b/crates/api_models/src/admin.rs
index b0b656a1ede..e0483b19503 100644
--- a/crates/api_models/src/admin.rs
+++ b/crates/api_models/src/admin.rs
@@ -2203,6 +2203,13 @@ pub struct ProfileCreate {
     /// Bool indicating if overcapture  must be requested for all payments
     #[schema(value_type = Option<bool>)]
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+
+    /// Indicates if external vault is enabled or not.
+    #[schema(value_type = Option<ExternalVaultEnabled>, example = "Enable")]
+    pub is_external_vault_enabled: Option<common_enums::ExternalVaultEnabled>,
+
+    /// External Vault Connector Details
+    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
 }
 
 #[nutype::nutype(
@@ -2553,6 +2560,13 @@ pub struct ProfileResponse {
     /// Bool indicating if overcapture  must be requested for all payments
     #[schema(value_type = Option<bool>)]
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+
+    /// Indicates if external vault is enabled or not.
+    #[schema(value_type = Option<ExternalVaultEnabled>, example = "Enable")]
+    pub is_external_vault_enabled: Option<common_enums::ExternalVaultEnabled>,
+
+    /// External Vault Connector Details
+    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
 }
 
 #[cfg(feature = "v2")]
@@ -2906,6 +2920,13 @@ pub struct ProfileUpdate {
     /// Bool indicating if overcapture  must be requested for all payments
     #[schema(value_type = Option<bool>)]
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+
+    /// Indicates if external vault is enabled or not.
+    #[schema(value_type = Option<ExternalVaultEnabled>, example = "Enable")]
+    pub is_external_vault_enabled: Option<common_enums::ExternalVaultEnabled>,
+
+    /// External Vault Connector Details
+    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
 }
 
 #[cfg(feature = "v2")]
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 75c5f27df57..591932c5deb 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -1413,6 +1413,34 @@ impl From<CardDetail> for CardDetailFromLocker {
     }
 }
 
+#[cfg(feature = "v1")]
+impl From<CardDetail> for CardDetailFromLocker {
+    fn from(item: CardDetail) -> Self {
+        // scheme should be updated in case of co-badged cards
+        let card_scheme = item
+            .card_network
+            .clone()
+            .map(|card_network| card_network.to_string());
+        Self {
+            issuer_country: item.card_issuing_country,
+            last4_digits: Some(item.card_number.get_last4()),
+            card_number: Some(item.card_number),
+            expiry_month: Some(item.card_exp_month),
+            expiry_year: Some(item.card_exp_year),
+            card_holder_name: item.card_holder_name,
+            nick_name: item.nick_name,
+            card_isin: None,
+            card_issuer: item.card_issuer,
+            card_network: item.card_network,
+            card_type: item.card_type.map(|card| card.to_string()),
+            saved_to_locker: true,
+            card_fingerprint: None,
+            scheme: card_scheme,
+            card_token: None,
+        }
+    }
+}
+
 #[cfg(feature = "v2")]
 impl From<CardDetail> for CardDetailsPaymentMethod {
     fn from(item: CardDetail) -> Self {
diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs
index 581858a85de..df7cb93114f 100644
--- a/crates/common_enums/src/enums.rs
+++ b/crates/common_enums/src/enums.rs
@@ -9491,3 +9491,50 @@ impl RoutingApproach {
 pub enum CallbackMapperIdType {
     NetworkTokenRequestorReferenceID,
 }
+
+/// Payment Method Status
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    PartialEq,
+    Eq,
+    Hash,
+    serde::Serialize,
+    serde::Deserialize,
+    strum::Display,
+    strum::EnumString,
+    ToSchema,
+)]
+#[router_derive::diesel_enum(storage_type = "text")]
+#[strum(serialize_all = "snake_case")]
+#[serde(rename_all = "snake_case")]
+pub enum VaultType {
+    /// Indicates that the payment method is stored in internal vault.
+    Internal,
+    /// Indicates that the payment method is stored in external vault.
+    External,
+}
+
+#[derive(
+    Clone,
+    Debug,
+    Copy,
+    Default,
+    Eq,
+    Hash,
+    PartialEq,
+    serde::Deserialize,
+    serde::Serialize,
+    strum::Display,
+    strum::EnumString,
+    ToSchema,
+)]
+#[router_derive::diesel_enum(storage_type = "text")]
+#[serde(rename_all = "snake_case")]
+#[strum(serialize_all = "snake_case")]
+pub enum ExternalVaultEnabled {
+    Enable,
+    #[default]
+    Skip,
+}
diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs
index a1e13b1f40c..17641cee59b 100644
--- a/crates/diesel_models/src/business_profile.rs
+++ b/crates/diesel_models/src/business_profile.rs
@@ -80,6 +80,8 @@ pub struct Profile {
     pub dispute_polling_interval: Option<primitive_wrappers::DisputePollingIntervalInHours>,
     pub is_manual_retry_enabled: Option<bool>,
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+    pub is_external_vault_enabled: Option<bool>,
+    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
 }
 
 #[cfg(feature = "v1")]
@@ -139,6 +141,8 @@ pub struct ProfileNew {
     pub merchant_country_code: Option<common_types::payments::MerchantCountryCode>,
     pub dispute_polling_interval: Option<primitive_wrappers::DisputePollingIntervalInHours>,
     pub is_manual_retry_enabled: Option<bool>,
+    pub is_external_vault_enabled: Option<bool>,
+    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
 }
 
 #[cfg(feature = "v1")]
@@ -199,6 +203,8 @@ pub struct ProfileUpdateInternal {
     pub dispute_polling_interval: Option<primitive_wrappers::DisputePollingIntervalInHours>,
     pub is_manual_retry_enabled: Option<bool>,
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+    pub is_external_vault_enabled: Option<bool>,
+    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
 }
 
 #[cfg(feature = "v1")]
@@ -256,6 +262,8 @@ impl ProfileUpdateInternal {
             dispute_polling_interval,
             is_manual_retry_enabled,
             always_enable_overcapture,
+            is_external_vault_enabled,
+            external_vault_connector_details,
         } = self;
         Profile {
             profile_id: source.profile_id,
@@ -345,6 +353,10 @@ impl ProfileUpdateInternal {
             is_manual_retry_enabled: is_manual_retry_enabled.or(source.is_manual_retry_enabled),
             always_enable_overcapture: always_enable_overcapture
                 .or(source.always_enable_overcapture),
+            is_external_vault_enabled: is_external_vault_enabled
+                .or(source.is_external_vault_enabled),
+            external_vault_connector_details: external_vault_connector_details
+                .or(source.external_vault_connector_details),
         }
     }
 }
@@ -411,6 +423,8 @@ pub struct Profile {
     pub dispute_polling_interval: Option<primitive_wrappers::DisputePollingIntervalInHours>,
     pub is_manual_retry_enabled: Option<bool>,
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+    pub is_external_vault_enabled: Option<bool>,
+    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
     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>,
@@ -422,8 +436,6 @@ pub struct Profile {
         Option<primitive_wrappers::ShouldCollectCvvDuringPayment>,
     pub revenue_recovery_retry_algorithm_type: Option<common_enums::RevenueRecoveryAlgorithmType>,
     pub revenue_recovery_retry_algorithm_data: Option<RevenueRecoveryAlgorithmData>,
-    pub is_external_vault_enabled: Option<bool>,
-    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
     pub split_txns_enabled: Option<common_enums::SplitTxnsEnabled>,
 }
 
diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs
index 34fff64e7d9..747c6fdbd39 100644
--- a/crates/diesel_models/src/payment_method.rs
+++ b/crates/diesel_models/src/payment_method.rs
@@ -60,6 +60,8 @@ pub struct PaymentMethod {
     pub network_token_requestor_reference_id: Option<String>,
     pub network_token_locker_id: Option<String>,
     pub network_token_payment_method_data: Option<Encryption>,
+    pub external_vault_source: Option<common_utils::id_type::MerchantConnectorAccountId>,
+    pub vault_type: Option<storage_enums::VaultType>,
 }
 
 #[cfg(feature = "v2")]
@@ -84,11 +86,12 @@ pub struct PaymentMethod {
     pub network_token_requestor_reference_id: Option<String>,
     pub network_token_locker_id: Option<String>,
     pub network_token_payment_method_data: Option<Encryption>,
+    pub external_vault_source: Option<common_utils::id_type::MerchantConnectorAccountId>,
+    pub vault_type: Option<storage_enums::VaultType>,
     pub locker_fingerprint_id: Option<String>,
     pub payment_method_type_v2: Option<storage_enums::PaymentMethod>,
     pub payment_method_subtype: Option<storage_enums::PaymentMethodType>,
     pub id: common_utils::id_type::GlobalPaymentMethodId,
-    pub external_vault_source: Option<common_utils::id_type::MerchantConnectorAccountId>,
     pub external_vault_token_data: Option<Encryption>,
 }
 
@@ -144,6 +147,8 @@ pub struct PaymentMethodNew {
     pub network_token_requestor_reference_id: Option<String>,
     pub network_token_locker_id: Option<String>,
     pub network_token_payment_method_data: Option<Encryption>,
+    pub external_vault_source: Option<common_utils::id_type::MerchantConnectorAccountId>,
+    pub vault_type: Option<storage_enums::VaultType>,
 }
 
 #[cfg(feature = "v2")]
@@ -173,6 +178,7 @@ pub struct PaymentMethodNew {
     pub payment_method_type_v2: Option<storage_enums::PaymentMethod>,
     pub payment_method_subtype: Option<storage_enums::PaymentMethodType>,
     pub id: common_utils::id_type::GlobalPaymentMethodId,
+    pub vault_type: Option<storage_enums::VaultType>,
 }
 
 impl PaymentMethodNew {
@@ -372,6 +378,7 @@ impl PaymentMethodUpdateInternal {
                 .or(source.network_token_payment_method_data),
             external_vault_source: external_vault_source.or(source.external_vault_source),
             external_vault_token_data: source.external_vault_token_data,
+            vault_type: source.vault_type,
         }
     }
 }
@@ -458,6 +465,8 @@ impl PaymentMethodUpdateInternal {
             network_token_locker_id: network_token_locker_id.or(source.network_token_locker_id),
             network_token_payment_method_data: network_token_payment_method_data
                 .or(source.network_token_payment_method_data),
+            external_vault_source: source.external_vault_source,
+            vault_type: source.vault_type,
         }
     }
 }
@@ -899,6 +908,8 @@ impl From<&PaymentMethodNew> for PaymentMethod {
             network_token_payment_method_data: payment_method_new
                 .network_token_payment_method_data
                 .clone(),
+            external_vault_source: payment_method_new.external_vault_source.clone(),
+            vault_type: payment_method_new.vault_type,
         }
     }
 }
@@ -937,6 +948,7 @@ impl From<&PaymentMethodNew> for PaymentMethod {
                 .clone(),
             external_vault_source: None,
             external_vault_token_data: payment_method_new.external_vault_token_data.clone(),
+            vault_type: payment_method_new.vault_type,
         }
     }
 }
diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs
index 36345ef7570..9316c470d99 100644
--- a/crates/diesel_models/src/schema.rs
+++ b/crates/diesel_models/src/schema.rs
@@ -257,6 +257,8 @@ diesel::table! {
         dispute_polling_interval -> Nullable<Int4>,
         is_manual_retry_enabled -> Nullable<Bool>,
         always_enable_overcapture -> Nullable<Bool>,
+        is_external_vault_enabled -> Nullable<Bool>,
+        external_vault_connector_details -> Nullable<Jsonb>,
     }
 }
 
@@ -1240,6 +1242,10 @@ diesel::table! {
         #[max_length = 64]
         network_token_locker_id -> Nullable<Varchar>,
         network_token_payment_method_data -> Nullable<Bytea>,
+        #[max_length = 64]
+        external_vault_source -> Nullable<Varchar>,
+        #[max_length = 64]
+        vault_type -> Nullable<Varchar>,
     }
 }
 
diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs
index f05b4e460c3..5433c9ca5ad 100644
--- a/crates/diesel_models/src/schema_v2.rs
+++ b/crates/diesel_models/src/schema_v2.rs
@@ -252,6 +252,8 @@ diesel::table! {
         dispute_polling_interval -> Nullable<Int4>,
         is_manual_retry_enabled -> Nullable<Bool>,
         always_enable_overcapture -> Nullable<Bool>,
+        is_external_vault_enabled -> Nullable<Bool>,
+        external_vault_connector_details -> Nullable<Jsonb>,
         #[max_length = 64]
         routing_algorithm_id -> Nullable<Varchar>,
         order_fulfillment_time -> Nullable<Int8>,
@@ -265,8 +267,6 @@ diesel::table! {
         should_collect_cvv_during_payment -> Nullable<Bool>,
         revenue_recovery_retry_algorithm_type -> Nullable<RevenueRecoveryAlgorithmType>,
         revenue_recovery_retry_algorithm_data -> Nullable<Jsonb>,
-        is_external_vault_enabled -> Nullable<Bool>,
-        external_vault_connector_details -> Nullable<Jsonb>,
         #[max_length = 16]
         split_txns_enabled -> Nullable<Varchar>,
     }
@@ -1172,6 +1172,10 @@ diesel::table! {
         network_token_locker_id -> Nullable<Varchar>,
         network_token_payment_method_data -> Nullable<Bytea>,
         #[max_length = 64]
+        external_vault_source -> Nullable<Varchar>,
+        #[max_length = 64]
+        vault_type -> Nullable<Varchar>,
+        #[max_length = 64]
         locker_fingerprint_id -> Nullable<Varchar>,
         #[max_length = 64]
         payment_method_type_v2 -> Nullable<Varchar>,
@@ -1179,8 +1183,6 @@ diesel::table! {
         payment_method_subtype -> Nullable<Varchar>,
         #[max_length = 64]
         id -> Varchar,
-        #[max_length = 64]
-        external_vault_source -> Nullable<Varchar>,
         external_vault_token_data -> Nullable<Bytea>,
     }
 }
diff --git a/crates/hyperswitch_domain_models/src/business_profile.rs b/crates/hyperswitch_domain_models/src/business_profile.rs
index efb9fc5979d..3672db0dd16 100644
--- a/crates/hyperswitch_domain_models/src/business_profile.rs
+++ b/crates/hyperswitch_domain_models/src/business_profile.rs
@@ -11,13 +11,11 @@ use common_utils::{
     pii, type_name,
     types::keymanager,
 };
-use diesel_models::business_profile::{
-    AuthenticationConnectorDetails, BusinessPaymentLinkConfig, BusinessPayoutLinkConfig,
-    CardTestingGuardConfig, ProfileUpdateInternal, WebhookDetails,
-};
 #[cfg(feature = "v2")]
+use diesel_models::business_profile::RevenueRecoveryAlgorithmData;
 use diesel_models::business_profile::{
-    ExternalVaultConnectorDetails, RevenueRecoveryAlgorithmData,
+    AuthenticationConnectorDetails, BusinessPaymentLinkConfig, BusinessPayoutLinkConfig,
+    CardTestingGuardConfig, ExternalVaultConnectorDetails, ProfileUpdateInternal, WebhookDetails,
 };
 use error_stack::ResultExt;
 use masking::{ExposeInterface, PeekInterface, Secret};
@@ -86,6 +84,104 @@ pub struct Profile {
     pub dispute_polling_interval: Option<primitive_wrappers::DisputePollingIntervalInHours>,
     pub is_manual_retry_enabled: Option<bool>,
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+    pub external_vault_details: ExternalVaultDetails,
+}
+
+#[cfg(feature = "v1")]
+#[derive(Clone, Debug)]
+pub enum ExternalVaultDetails {
+    ExternalVaultEnabled(ExternalVaultConnectorDetails),
+    Skip,
+}
+
+#[cfg(feature = "v1")]
+impl ExternalVaultDetails {
+    pub fn is_external_vault_enabled(&self) -> bool {
+        match self {
+            Self::ExternalVaultEnabled(_) => true,
+            Self::Skip => false,
+        }
+    }
+}
+
+#[cfg(feature = "v1")]
+impl
+    TryFrom<(
+        Option<common_enums::ExternalVaultEnabled>,
+        Option<ExternalVaultConnectorDetails>,
+    )> for ExternalVaultDetails
+{
+    type Error = error_stack::Report<ValidationError>;
+    fn try_from(
+        item: (
+            Option<common_enums::ExternalVaultEnabled>,
+            Option<ExternalVaultConnectorDetails>,
+        ),
+    ) -> Result<Self, Self::Error> {
+        match item {
+            (is_external_vault_enabled, external_vault_connector_details)
+                if is_external_vault_enabled
+                    .unwrap_or(common_enums::ExternalVaultEnabled::Skip)
+                    == common_enums::ExternalVaultEnabled::Enable =>
+            {
+                Ok(Self::ExternalVaultEnabled(
+                    external_vault_connector_details
+                        .get_required_value("ExternalVaultConnectorDetails")?,
+                ))
+            }
+            _ => Ok(Self::Skip),
+        }
+    }
+}
+
+#[cfg(feature = "v1")]
+impl TryFrom<(Option<bool>, Option<ExternalVaultConnectorDetails>)> for ExternalVaultDetails {
+    type Error = error_stack::Report<ValidationError>;
+    fn try_from(
+        item: (Option<bool>, Option<ExternalVaultConnectorDetails>),
+    ) -> Result<Self, Self::Error> {
+        match item {
+            (is_external_vault_enabled, external_vault_connector_details)
+                if is_external_vault_enabled.unwrap_or(false) =>
+            {
+                Ok(Self::ExternalVaultEnabled(
+                    external_vault_connector_details
+                        .get_required_value("ExternalVaultConnectorDetails")?,
+                ))
+            }
+            _ => Ok(Self::Skip),
+        }
+    }
+}
+
+#[cfg(feature = "v1")]
+impl From<ExternalVaultDetails>
+    for (
+        Option<common_enums::ExternalVaultEnabled>,
+        Option<ExternalVaultConnectorDetails>,
+    )
+{
+    fn from(external_vault_details: ExternalVaultDetails) -> Self {
+        match external_vault_details {
+            ExternalVaultDetails::ExternalVaultEnabled(connector_details) => (
+                Some(common_enums::ExternalVaultEnabled::Enable),
+                Some(connector_details),
+            ),
+            ExternalVaultDetails::Skip => (Some(common_enums::ExternalVaultEnabled::Skip), None),
+        }
+    }
+}
+
+#[cfg(feature = "v1")]
+impl From<ExternalVaultDetails> for (Option<bool>, Option<ExternalVaultConnectorDetails>) {
+    fn from(external_vault_details: ExternalVaultDetails) -> Self {
+        match external_vault_details {
+            ExternalVaultDetails::ExternalVaultEnabled(connector_details) => {
+                (Some(true), Some(connector_details))
+            }
+            ExternalVaultDetails::Skip => (Some(false), None),
+        }
+    }
 }
 
 #[cfg(feature = "v1")]
@@ -144,6 +240,7 @@ pub struct ProfileSetter {
     pub dispute_polling_interval: Option<primitive_wrappers::DisputePollingIntervalInHours>,
     pub is_manual_retry_enabled: Option<bool>,
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+    pub external_vault_details: ExternalVaultDetails,
 }
 
 #[cfg(feature = "v1")]
@@ -209,6 +306,7 @@ impl From<ProfileSetter> for Profile {
             dispute_polling_interval: value.dispute_polling_interval,
             is_manual_retry_enabled: value.is_manual_retry_enabled,
             always_enable_overcapture: value.always_enable_overcapture,
+            external_vault_details: value.external_vault_details,
         }
     }
 }
@@ -276,6 +374,8 @@ pub struct ProfileGeneralUpdate {
     pub dispute_polling_interval: Option<primitive_wrappers::DisputePollingIntervalInHours>,
     pub is_manual_retry_enabled: Option<bool>,
     pub always_enable_overcapture: Option<primitive_wrappers::AlwaysEnableOvercaptureBool>,
+    pub is_external_vault_enabled: Option<common_enums::ExternalVaultEnabled>,
+    pub external_vault_connector_details: Option<ExternalVaultConnectorDetails>,
 }
 
 #[cfg(feature = "v1")]
@@ -361,8 +461,18 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                     always_request_extended_authorization,
                     is_manual_retry_enabled,
                     always_enable_overcapture,
+                    is_external_vault_enabled,
+                    external_vault_connector_details,
                 } = *update;
 
+                let is_external_vault_enabled = match is_external_vault_enabled {
+                    Some(external_vault_mode) => match external_vault_mode {
+                        common_enums::ExternalVaultEnabled::Enable => Some(true),
+                        common_enums::ExternalVaultEnabled::Skip => Some(false),
+                    },
+                    None => Some(false),
+                };
+
                 Self {
                     profile_name,
                     modified_at: now,
@@ -416,6 +526,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                     dispute_polling_interval,
                     is_manual_retry_enabled,
                     always_enable_overcapture,
+                    is_external_vault_enabled,
+                    external_vault_connector_details,
                 }
             }
             ProfileUpdate::RoutingAlgorithmUpdate {
@@ -474,6 +586,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 dispute_polling_interval: None,
                 is_manual_retry_enabled: None,
                 always_enable_overcapture: None,
+                is_external_vault_enabled: None,
+                external_vault_connector_details: None,
             },
             ProfileUpdate::DynamicRoutingAlgorithmUpdate {
                 dynamic_routing_algorithm,
@@ -529,6 +643,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 dispute_polling_interval: None,
                 is_manual_retry_enabled: None,
                 always_enable_overcapture: None,
+                is_external_vault_enabled: None,
+                external_vault_connector_details: None,
             },
             ProfileUpdate::ExtendedCardInfoUpdate {
                 is_extended_card_info_enabled,
@@ -584,6 +700,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 dispute_polling_interval: None,
                 is_manual_retry_enabled: None,
                 always_enable_overcapture: None,
+                is_external_vault_enabled: None,
+                external_vault_connector_details: None,
             },
             ProfileUpdate::ConnectorAgnosticMitUpdate {
                 is_connector_agnostic_mit_enabled,
@@ -639,6 +757,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 dispute_polling_interval: None,
                 is_manual_retry_enabled: None,
                 always_enable_overcapture: None,
+                is_external_vault_enabled: None,
+                external_vault_connector_details: None,
             },
             ProfileUpdate::NetworkTokenizationUpdate {
                 is_network_tokenization_enabled,
@@ -694,6 +814,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 dispute_polling_interval: None,
                 is_manual_retry_enabled: None,
                 always_enable_overcapture: None,
+                is_external_vault_enabled: None,
+                external_vault_connector_details: None,
             },
             ProfileUpdate::CardTestingSecretKeyUpdate {
                 card_testing_secret_key,
@@ -749,6 +871,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 dispute_polling_interval: None,
                 is_manual_retry_enabled: None,
                 always_enable_overcapture: None,
+                is_external_vault_enabled: None,
+                external_vault_connector_details: None,
             },
             ProfileUpdate::AcquirerConfigMapUpdate {
                 acquirer_config_map,
@@ -804,6 +928,8 @@ impl From<ProfileUpdate> for ProfileUpdateInternal {
                 dispute_polling_interval: None,
                 is_manual_retry_enabled: None,
                 always_enable_overcapture: None,
+                is_external_vault_enabled: None,
+                external_vault_connector_details: None,
             },
         }
     }
@@ -816,6 +942,9 @@ impl super::behaviour::Conversion for Profile {
     type NewDstType = diesel_models::business_profile::ProfileNew;
 
     async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
+        let (is_external_vault_enabled, external_vault_connector_details) =
+            self.external_vault_details.into();
+
         Ok(diesel_models::business_profile::Profile {
             profile_id: self.profile_id.clone(),
             id: Some(self.profile_id),
@@ -879,6 +1008,8 @@ impl super::behaviour::Conversion for Profile {
             dispute_polling_interval: self.dispute_polling_interval,
             is_manual_retry_enabled: self.is_manual_retry_enabled,
             always_enable_overcapture: self.always_enable_overcapture,
+            is_external_vault_enabled,
+            external_vault_connector_details,
         })
     }
 
@@ -891,104 +1022,124 @@ impl super::behaviour::Conversion for Profile {
     where
         Self: Sized,
     {
-        async {
-            Ok::<Self, error_stack::Report<common_utils::errors::CryptoError>>(Self {
-                profile_id: item.profile_id,
-                merchant_id: item.merchant_id,
-                profile_name: item.profile_name,
-                created_at: item.created_at,
-                modified_at: item.modified_at,
-                return_url: item.return_url,
-                enable_payment_response_hash: item.enable_payment_response_hash,
-                payment_response_hash_key: item.payment_response_hash_key,
-                redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
-                webhook_details: item.webhook_details,
-                metadata: item.metadata,
-                routing_algorithm: item.routing_algorithm,
-                intent_fulfillment_time: item.intent_fulfillment_time,
-                frm_routing_algorithm: item.frm_routing_algorithm,
-                payout_routing_algorithm: item.payout_routing_algorithm,
-                is_recon_enabled: item.is_recon_enabled,
-                applepay_verified_domains: item.applepay_verified_domains,
-                payment_link_config: item.payment_link_config,
-                session_expiry: item.session_expiry,
-                authentication_connector_details: item.authentication_connector_details,
-                payout_link_config: item.payout_link_config,
-                is_extended_card_info_enabled: item.is_extended_card_info_enabled,
-                extended_card_info_config: item.extended_card_info_config,
-                is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
-                use_billing_as_payment_method_billing: item.use_billing_as_payment_method_billing,
-                collect_shipping_details_from_wallet_connector: item
-                    .collect_shipping_details_from_wallet_connector,
-                collect_billing_details_from_wallet_connector: item
-                    .collect_billing_details_from_wallet_connector,
-                always_collect_billing_details_from_wallet_connector: item
-                    .always_collect_billing_details_from_wallet_connector,
-                always_collect_shipping_details_from_wallet_connector: item
-                    .always_collect_shipping_details_from_wallet_connector,
-                outgoing_webhook_custom_http_headers: item
-                    .outgoing_webhook_custom_http_headers
-                    .async_lift(|inner| async {
-                        crypto_operation(
-                            state,
-                            type_name!(Self::DstType),
-                            CryptoOperation::DecryptOptional(inner),
-                            key_manager_identifier.clone(),
-                            key.peek(),
-                        )
-                        .await
-                        .and_then(|val| val.try_into_optionaloperation())
-                    })
-                    .await?,
-                tax_connector_id: item.tax_connector_id,
-                is_tax_connector_enabled: item.is_tax_connector_enabled.unwrap_or(false),
-                version: item.version,
-                dynamic_routing_algorithm: item.dynamic_routing_algorithm,
-                is_network_tokenization_enabled: item.is_network_tokenization_enabled,
-                is_auto_retries_enabled: item.is_auto_retries_enabled.unwrap_or(false),
-                max_auto_retries_enabled: item.max_auto_retries_enabled,
-                always_request_extended_authorization: item.always_request_extended_authorization,
-                is_click_to_pay_enabled: item.is_click_to_pay_enabled,
-                authentication_product_ids: item.authentication_product_ids,
-                card_testing_guard_config: item.card_testing_guard_config,
-                card_testing_secret_key: item
-                    .card_testing_secret_key
-                    .async_lift(|inner| async {
-                        crypto_operation(
-                            state,
-                            type_name!(Self::DstType),
-                            CryptoOperation::DecryptOptional(inner),
-                            key_manager_identifier.clone(),
-                            key.peek(),
-                        )
-                        .await
-                        .and_then(|val| val.try_into_optionaloperation())
-                    })
-                    .await?,
-                is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
-                force_3ds_challenge: item.force_3ds_challenge.unwrap_or_default(),
-                is_debit_routing_enabled: item.is_debit_routing_enabled,
-                merchant_business_country: item.merchant_business_country,
-                is_iframe_redirection_enabled: item.is_iframe_redirection_enabled,
-                is_pre_network_tokenization_enabled: item
-                    .is_pre_network_tokenization_enabled
-                    .unwrap_or(false),
-                three_ds_decision_rule_algorithm: item.three_ds_decision_rule_algorithm,
-                acquirer_config_map: item.acquirer_config_map,
-                merchant_category_code: item.merchant_category_code,
-                merchant_country_code: item.merchant_country_code,
-                dispute_polling_interval: item.dispute_polling_interval,
-                is_manual_retry_enabled: item.is_manual_retry_enabled,
-                always_enable_overcapture: item.always_enable_overcapture,
-            })
+        // Decrypt encrypted fields first
+        let (outgoing_webhook_custom_http_headers, card_testing_secret_key) = async {
+            let outgoing_webhook_custom_http_headers = item
+                .outgoing_webhook_custom_http_headers
+                .async_lift(|inner| async {
+                    crypto_operation(
+                        state,
+                        type_name!(Self::DstType),
+                        CryptoOperation::DecryptOptional(inner),
+                        key_manager_identifier.clone(),
+                        key.peek(),
+                    )
+                    .await
+                    .and_then(|val| val.try_into_optionaloperation())
+                })
+                .await?;
+
+            let card_testing_secret_key = item
+                .card_testing_secret_key
+                .async_lift(|inner| async {
+                    crypto_operation(
+                        state,
+                        type_name!(Self::DstType),
+                        CryptoOperation::DecryptOptional(inner),
+                        key_manager_identifier.clone(),
+                        key.peek(),
+                    )
+                    .await
+                    .and_then(|val| val.try_into_optionaloperation())
+                })
+                .await?;
+
+            Ok::<_, error_stack::Report<common_utils::errors::CryptoError>>((
+                outgoing_webhook_custom_http_headers,
+                card_testing_secret_key,
+            ))
         }
         .await
         .change_context(ValidationError::InvalidValue {
             message: "Failed while decrypting business profile data".to_string(),
+        })?;
+
+        let external_vault_details = ExternalVaultDetails::try_from((
+            item.is_external_vault_enabled,
+            item.external_vault_connector_details,
+        ))?;
+
+        // Construct the domain type
+        Ok(Self {
+            profile_id: item.profile_id,
+            merchant_id: item.merchant_id,
+            profile_name: item.profile_name,
+            created_at: item.created_at,
+            modified_at: item.modified_at,
+            return_url: item.return_url,
+            enable_payment_response_hash: item.enable_payment_response_hash,
+            payment_response_hash_key: item.payment_response_hash_key,
+            redirect_to_merchant_with_http_post: item.redirect_to_merchant_with_http_post,
+            webhook_details: item.webhook_details,
+            metadata: item.metadata,
+            routing_algorithm: item.routing_algorithm,
+            intent_fulfillment_time: item.intent_fulfillment_time,
+            frm_routing_algorithm: item.frm_routing_algorithm,
+            payout_routing_algorithm: item.payout_routing_algorithm,
+            is_recon_enabled: item.is_recon_enabled,
+            applepay_verified_domains: item.applepay_verified_domains,
+            payment_link_config: item.payment_link_config,
+            session_expiry: item.session_expiry,
+            authentication_connector_details: item.authentication_connector_details,
+            payout_link_config: item.payout_link_config,
+            is_extended_card_info_enabled: item.is_extended_card_info_enabled,
+            extended_card_info_config: item.extended_card_info_config,
+            is_connector_agnostic_mit_enabled: item.is_connector_agnostic_mit_enabled,
+            use_billing_as_payment_method_billing: item.use_billing_as_payment_method_billing,
+            collect_shipping_details_from_wallet_connector: item
+                .collect_shipping_details_from_wallet_connector,
+            collect_billing_details_from_wallet_connector: item
+                .collect_billing_details_from_wallet_connector,
+            always_collect_billing_details_from_wallet_connector: item
+                .always_collect_billing_details_from_wallet_connector,
+            always_collect_shipping_details_from_wallet_connector: item
+                .always_collect_shipping_details_from_wallet_connector,
+            outgoing_webhook_custom_http_headers,
+            tax_connector_id: item.tax_connector_id,
+            is_tax_connector_enabled: item.is_tax_connector_enabled.unwrap_or(false),
+            version: item.version,
+            dynamic_routing_algorithm: item.dynamic_routing_algorithm,
+            is_network_tokenization_enabled: item.is_network_tokenization_enabled,
+            is_auto_retries_enabled: item.is_auto_retries_enabled.unwrap_or(false),
+            max_auto_retries_enabled: item.max_auto_retries_enabled,
+            always_request_extended_authorization: item.always_request_extended_authorization,
+            is_click_to_pay_enabled: item.is_click_to_pay_enabled,
+            authentication_product_ids: item.authentication_product_ids,
+            card_testing_guard_config: item.card_testing_guard_config,
+            card_testing_secret_key,
+            is_clear_pan_retries_enabled: item.is_clear_pan_retries_enabled,
+            force_3ds_challenge: item.force_3ds_challenge.unwrap_or_default(),
+            is_debit_routing_enabled: item.is_debit_routing_enabled,
+            merchant_business_country: item.merchant_business_country,
+            is_iframe_redirection_enabled: item.is_iframe_redirection_enabled,
+            is_pre_network_tokenization_enabled: item
+                .is_pre_network_tokenization_enabled
+                .unwrap_or(false),
+            three_ds_decision_rule_algorithm: item.three_ds_decision_rule_algorithm,
+            acquirer_config_map: item.acquirer_config_map,
+            merchant_category_code: item.merchant_category_code,
+            merchant_country_code: item.merchant_country_code,
+            dispute_polling_interval: item.dispute_polling_interval,
+            is_manual_retry_enabled: item.is_manual_retry_enabled,
+            always_enable_overcapture: item.always_enable_overcapture,
+            external_vault_details,
         })
     }
 
     async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
+        let (is_external_vault_enabled, external_vault_connector_details) =
+            self.external_vault_details.into();
+
         Ok(diesel_models::business_profile::ProfileNew {
             profile_id: self.profile_id.clone(),
             id: Some(self.profile_id),
@@ -1047,6 +1198,8 @@ impl super::behaviour::Conversion for Profile {
             merchant_country_code: self.merchant_country_code,
             dispute_polling_interval: self.dispute_polling_interval,
             is_manual_retry_enabled: self.is_manual_retry_enabled,
+            is_external_vault_enabled,
+            external_vault_connector_details,
         })
     }
 }
diff --git a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs
index 5ba75893787..d6600d674fc 100644
--- a/crates/hyperswitch_domain_models/src/merchant_connector_account.rs
+++ b/crates/hyperswitch_domain_models/src/merchant_connector_account.rs
@@ -173,6 +173,17 @@ impl MerchantConnectorAccountTypeDetails {
         }
     }
 
+    pub fn get_connector_name_as_string(&self) -> String {
+        match self {
+            Self::MerchantConnectorAccount(merchant_connector_account) => {
+                merchant_connector_account.connector_name.to_string()
+            }
+            Self::MerchantConnectorDetails(merchant_connector_details) => {
+                merchant_connector_details.connector_name.to_string()
+            }
+        }
+    }
+
     pub fn get_inner_db_merchant_connector_account(&self) -> Option<&MerchantConnectorAccount> {
         match self {
             Self::MerchantConnectorAccount(merchant_connector_account) => {
@@ -257,6 +268,11 @@ impl MerchantConnectorAccount {
         self.connector_name.clone().to_string()
     }
 
+    #[cfg(feature = "v2")]
+    pub fn get_connector_name(&self) -> common_enums::connector_enums::Connector {
+        self.connector_name
+    }
+
     pub fn get_payment_merchant_connector_account_id_using_account_reference_id(
         &self,
         account_reference_id: String,
diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs
index 59202837dc2..932244a986d 100644
--- a/crates/hyperswitch_domain_models/src/payment_method_data.rs
+++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs
@@ -2559,3 +2559,70 @@ impl From<NetworkTokenData> for payment_methods::CardDetail {
         }
     }
 }
+
+#[cfg(feature = "v1")]
+impl
+    From<(
+        payment_methods::CardDetail,
+        Option<&CardToken>,
+        Option<payment_methods::CoBadgedCardData>,
+    )> for Card
+{
+    fn from(
+        value: (
+            payment_methods::CardDetail,
+            Option<&CardToken>,
+            Option<payment_methods::CoBadgedCardData>,
+        ),
+    ) -> Self {
+        let (
+            payment_methods::CardDetail {
+                card_number,
+                card_exp_month,
+                card_exp_year,
+                card_holder_name,
+                nick_name,
+                card_network,
+                card_issuer,
+                card_issuing_country,
+                card_type,
+            },
+            card_token_data,
+            co_badged_card_data,
+        ) = value;
+
+        // The card_holder_name from locker retrieved card is considered if it is a non-empty string or else card_holder_name is picked
+        let name_on_card = if let Some(name) = card_holder_name.clone() {
+            use masking::ExposeInterface;
+
+            if name.clone().expose().is_empty() {
+                card_token_data
+                    .and_then(|token_data| token_data.card_holder_name.clone())
+                    .or(Some(name))
+            } else {
+                card_holder_name
+            }
+        } else {
+            card_token_data.and_then(|token_data| token_data.card_holder_name.clone())
+        };
+
+        Self {
+            card_number,
+            card_exp_month,
+            card_exp_year,
+            card_holder_name: name_on_card,
+            card_cvc: card_token_data
+                .cloned()
+                .unwrap_or_default()
+                .card_cvc
+                .unwrap_or_default(),
+            card_issuer,
+            card_network,
+            card_type,
+            card_issuing_country,
+            bank_code: None,
+            nick_name,
+            co_badged_card_data,
+        }
+    }
+}
diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs
index 003998d9ccc..e9ce9057692 100644
--- a/crates/hyperswitch_domain_models/src/payment_methods.rs
+++ b/crates/hyperswitch_domain_models/src/payment_methods.rs
@@ -37,11 +37,9 @@ use crate::{
     type_encryption::{crypto_operation, CryptoOperation},
 };
 
-#[cfg(feature = "v2")]
 #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
 pub struct VaultId(String);
 
-#[cfg(any(feature = "v2", feature = "tokenization_v2"))]
 impl VaultId {
     pub fn get_string_repr(&self) -> &String {
         &self.0
@@ -88,7 +86,9 @@ pub struct PaymentMethod {
     pub network_token_requestor_reference_id: Option<String>,
     pub network_token_locker_id: Option<String>,
     pub network_token_payment_method_data: OptionalEncryptableValue,
+    pub vault_source_details: PaymentMethodVaultSourceDetails,
 }
+
 #[cfg(feature = "v2")]
 #[derive(Clone, Debug, router_derive::ToEncryption)]
 pub struct PaymentMethod {
@@ -128,6 +128,7 @@ pub struct PaymentMethod {
     #[encrypt(ty = Value)]
     pub external_vault_token_data:
         Option<Encryptable<api_models::payment_methods::ExternalVaultTokenData>>,
+    pub vault_type: Option<storage_enums::VaultType>,
 }
 
 impl PaymentMethod {
@@ -259,6 +260,7 @@ impl super::behaviour::Conversion for PaymentMethod {
     type DstType = diesel_models::payment_method::PaymentMethod;
     type NewDstType = diesel_models::payment_method::PaymentMethodNew;
     async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
+        let (vault_type, external_vault_source) = self.vault_source_details.into();
         Ok(Self::DstType {
             customer_id: self.customer_id,
             merchant_id: self.merchant_id,
@@ -298,6 +300,8 @@ impl super::behaviour::Conversion for PaymentMethod {
             network_token_payment_method_data: self
                 .network_token_payment_method_data
                 .map(|val| val.into()),
+            external_vault_source,
+            vault_type,
         })
     }
 
@@ -310,90 +314,115 @@ impl super::behaviour::Conversion for PaymentMethod {
     where
         Self: Sized,
     {
-        async {
-            Ok::<Self, error_stack::Report<common_utils::errors::CryptoError>>(Self {
-                customer_id: item.customer_id,
-                merchant_id: item.merchant_id,
-                payment_method_id: item.payment_method_id,
-                accepted_currency: item.accepted_currency,
-                scheme: item.scheme,
-                token: item.token,
-                cardholder_name: item.cardholder_name,
-                issuer_name: item.issuer_name,
-                issuer_country: item.issuer_country,
-                payer_country: item.payer_country,
-                is_stored: item.is_stored,
-                swift_code: item.swift_code,
-                direct_debit_token: item.direct_debit_token,
-                created_at: item.created_at,
-                last_modified: item.last_modified,
-                payment_method: item.payment_method,
-                payment_method_type: item.payment_method_type,
-                payment_method_issuer: item.payment_method_issuer,
-                payment_method_issuer_code: item.payment_method_issuer_code,
-                metadata: item.metadata,
-                payment_method_data: item
-                    .payment_method_data
-                    .async_lift(|inner| async {
-                        crypto_operation(
-                            state,
-                            type_name!(Self::DstType),
-                            CryptoOperation::DecryptOptional(inner),
-                            key_manager_identifier.clone(),
-                            key.peek(),
-                        )
-                        .await
-                        .and_then(|val| val.try_into_optionaloperation())
-                    })
-                    .await?,
-                locker_id: item.locker_id,
-                last_used_at: item.last_used_at,
-                connector_mandate_details: item.connector_mandate_details,
-                customer_acceptance: item.customer_acceptance,
-                status: item.status,
-                network_transaction_id: item.network_transaction_id,
-                client_secret: item.client_secret,
-                payment_method_billing_address: item
-                    .payment_method_billing_address
-                    .async_lift(|inner| async {
-                        crypto_operation(
-                            state,
-                            type_name!(Self::DstType),
-                            CryptoOperation::DecryptOptional(inner),
-                            key_manager_identifier.clone(),
-                            key.peek(),
-                        )
-                        .await
-                        .and_then(|val| val.try_into_optionaloperation())
-                    })
-                    .await?,
-                updated_by: item.updated_by,
-                version: item.version,
-                network_token_requestor_reference_id: item.network_token_requestor_reference_id,
-                network_token_locker_id: item.network_token_locker_id,
-                network_token_payment_method_data: item
-                    .network_token_payment_method_data
-                    .async_lift(|inner| async {
-                        crypto_operation(
-                            state,
-                            type_name!(Self::DstType),
-                            CryptoOperation::DecryptOptional(inner),
-                            key_manager_identifier.clone(),
-                            key.peek(),
-                        )
-                        .await
-                        .and_then(|val| val.try_into_optionaloperation())
-                    })
-                    .await?,
-            })
+        // Decrypt encrypted fields first
+        let (
+            payment_method_data,
+            payment_method_billing_address,
+            network_token_payment_method_data,
+        ) = async {
+            let payment_method_data = item
+                .payment_method_data
+                .async_lift(|inner| async {
+                    crypto_operation(
+                        state,
+                        type_name!(Self::DstType),
+                        CryptoOperation::DecryptOptional(inner),
+                        key_manager_identifier.clone(),
+                        key.peek(),
+                    )
+                    .await
+                    .and_then(|val| val.try_into_optionaloperation())
+                })
+                .await?;
+
+            let payment_method_billing_address = item
+                .payment_method_billing_address
+                .async_lift(|inner| async {
+                    crypto_operation(
+                        state,
+                        type_name!(Self::DstType),
+                        CryptoOperation::DecryptOptional(inner),
+                        key_manager_identifier.clone(),
+                        key.peek(),
+                    )
+                    .await
+                    .and_then(|val| val.try_into_optionaloperation())
+                })
+                .await?;
+
+            let network_token_payment_method_data = item
+                .network_token_payment_method_data
+                .async_lift(|inner| async {
+                    crypto_operation(
+                        state,
+                        type_name!(Self::DstType),
+                        CryptoOperation::DecryptOptional(inner),
+                        key_manager_identifier.clone(),
+                        key.peek(),
+                    )
+                    .await
+                    .and_then(|val| val.try_into_optionaloperation())
+                })
+                .await?;
+
+            Ok::<_, error_stack::Report<common_utils::errors::CryptoError>>((
+                payment_method_data,
+                payment_method_billing_address,
+                network_token_payment_method_data,
+            ))
         }
         .await
         .change_context(ValidationError::InvalidValue {
             message: "Failed while decrypting payment method data".to_string(),
+        })?;
+
+        let vault_source_details = PaymentMethodVaultSourceDetails::try_from((
+            item.vault_type,
+            item.external_vault_source,
+        ))?;
+
+        // Construct the domain type
+        Ok(Self {
+            customer_id: item.customer_id,
+            merchant_id: item.merchant_id,
+            payment_method_id: item.payment_method_id,
+            accepted_currency: item.accepted_currency,
+            scheme: item.scheme,
+            token: item.token,
+            cardholder_name: item.cardholder_name,
+            issuer_name: item.issuer_name,
+            issuer_country: item.issuer_country,
+            payer_country: item.payer_country,
+            is_stored: item.is_stored,
+            swift_code: item.swift_code,
+            direct_debit_token: item.direct_debit_token,
+            created_at: item.created_at,
+            last_modified: item.last_modified,
+            payment_method: item.payment_method,
+            payment_method_type: item.payment_method_type,
+            payment_method_issuer: item.payment_method_issuer,
+            payment_method_issuer_code: item.payment_method_issuer_code,
+            metadata: item.metadata,
+            payment_method_data,
+            locker_id: item.locker_id,
+            last_used_at: item.last_used_at,
+            connector_mandate_details: item.connector_mandate_details,
+            customer_acceptance: item.customer_acceptance,
+            status: item.status,
+            network_transaction_id: item.network_transaction_id,
+            client_secret: item.client_secret,
+            payment_method_billing_address,
+            updated_by: item.updated_by,
+            version: item.version,
+            network_token_requestor_reference_id: item.network_token_requestor_reference_id,
+            network_token_locker_id: item.network_token_locker_id,
+            network_token_payment_method_data,
+            vault_source_details,
         })
     }
 
     async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
+        let (vault_type, external_vault_source) = self.vault_source_details.into();
         Ok(Self::NewDstType {
             customer_id: self.customer_id,
             merchant_id: self.merchant_id,
@@ -433,6 +462,8 @@ impl super::behaviour::Conversion for PaymentMethod {
             network_token_payment_method_data: self
                 .network_token_payment_method_data
                 .map(|val| val.into()),
+            external_vault_source,
+            vault_type,
         })
     }
 }
@@ -472,6 +503,7 @@ impl super::behaviour::Conversion for PaymentMethod {
                 .map(|val| val.into()),
             external_vault_source: self.external_vault_source,
             external_vault_token_data: self.external_vault_token_data.map(|val| val.into()),
+            vault_type: self.vault_type,
         })
     }
 
@@ -577,6 +609,7 @@ impl super::behaviour::Conversion for PaymentMethod {
                 network_token_payment_method_data,
                 external_vault_source: storage_model.external_vault_source,
                 external_vault_token_data,
+                vault_type: storage_model.vault_type,
             })
         }
         .await
@@ -614,6 +647,7 @@ impl super::behaviour::Conversion for PaymentMethod {
                 .network_token_payment_method_data
                 .map(|val| val.into()),
             external_vault_token_data: self.external_vault_token_data.map(|val| val.into()),
+            vault_type: self.vault_type,
         })
     }
 }
@@ -1081,6 +1115,68 @@ impl ForeignTryFrom<(&[payment_methods::PaymentMethodRecord], id_type::MerchantI
     }
 }
 
+#[cfg(feature = "v1")]
+#[derive(Clone, Debug, Default)]
+pub enum PaymentMethodVaultSourceDetails {
+    ExternalVault {
+        external_vault_source: id_type::MerchantConnectorAccountId,
+    },
+    #[default]
+    InternalVault,
+}
+
+#[cfg(feature = "v1")]
+impl
+    TryFrom<(
+        Option<storage_enums::VaultType>,
+        Option<id_type::MerchantConnectorAccountId>,
+    )> for PaymentMethodVaultSourceDetails
+{
+    type Error = error_stack::Report<ValidationError>;
+    fn try_from(
+        value: (
+            Option<storage_enums::VaultType>,
+            Option<id_type::MerchantConnectorAccountId>,
+        ),
+    ) -> Result<Self, Self::Error> {
+        match value {
+            (Some(storage_enums::VaultType::External), Some(external_vault_source)) => {
+                Ok(Self::ExternalVault {
+                    external_vault_source,
+                })
+            }
+            (Some(storage_enums::VaultType::External), None) => {
+                Err(ValidationError::MissingRequiredField {
+                    field_name: "external vault mca id".to_string(),
+                }
+                .into())
+            }
+            (Some(storage_enums::VaultType::Internal), _) | (None, _) => Ok(Self::InternalVault), // defaulting to internal vault if vault type is none
+        }
+    }
+}
+#[cfg(feature = "v1")]
+impl From<PaymentMethodVaultSourceDetails>
+    for (
+        Option<storage_enums::VaultType>,
+        Option<id_type::MerchantConnectorAccountId>,
+    )
+{
+    fn from(value: PaymentMethodVaultSourceDetails) -> Self {
+        match value {
+            PaymentMethodVaultSourceDetails::ExternalVault {
+                external_vault_source,
+            } => (
+                Some(storage_enums::VaultType::External),
+                Some(external_vault_source),
+            ),
+            PaymentMethodVaultSourceDetails::InternalVault => {
+                (Some(storage_enums::VaultType::Internal), None)
+            }
+        }
+    }
+}
+
 #[cfg(feature = "v1")]
 #[cfg(test)]
 mod tests {
@@ -1127,6 +1223,7 @@ mod tests {
             network_token_requestor_reference_id: None,
             network_token_locker_id: None,
             network_token_payment_method_data: None,
+            vault_source_details: Default::default(),
         };
         payment_method.clone()
     }
diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs
index 8b2a3300a3b..e52daa7fedb 100644
--- a/crates/openapi/src/openapi.rs
+++ b/crates/openapi/src/openapi.rs
@@ -381,6 +381,9 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::enums::PaymentLinkSdkLabelType,
         api_models::enums::OrganizationType,
         api_models::enums::PaymentLinkShowSdkTerms,
+        api_models::enums::ExternalVaultEnabled,
+        api_models::enums::VaultSdk,
+        api_models::admin::ExternalVaultConnectorDetails,
         api_models::admin::MerchantConnectorCreate,
         api_models::admin::AdditionalMerchantData,
         api_models::admin::ConnectorWalletDetails,
diff --git a/crates/payment_methods/src/controller.rs b/crates/payment_methods/src/controller.rs
index 095788fa368..47a91f84633 100644
--- a/crates/payment_methods/src/controller.rs
+++ b/crates/payment_methods/src/controller.rs
@@ -9,6 +9,8 @@ use common_enums::enums as common_enums;
 use common_utils::encryption;
 use common_utils::{crypto, ext_traits, id_type, type_name, types::keymanager};
 use error_stack::ResultExt;
+#[cfg(feature = "v1")]
+use hyperswitch_domain_models::payment_methods::PaymentMethodVaultSourceDetails;
 use hyperswitch_domain_models::{merchant_key_store, payment_methods, type_encryption};
 use masking::{PeekInterface, Secret};
 #[cfg(feature = "v1")]
@@ -54,6 +56,7 @@ pub trait PaymentMethodsController {
         network_token_requestor_reference_id: Option<String>,
         network_token_locker_id: Option<String>,
         network_token_payment_method_data: crypto::OptionalEncryptableValue,
+        vault_source_details: Option<PaymentMethodVaultSourceDetails>,
     ) -> errors::PmResult<payment_methods::PaymentMethod>;
 
     #[cfg(feature = "v1")]
@@ -74,6 +77,7 @@ pub trait PaymentMethodsController {
         network_token_requestor_reference_id: Option<String>,
         network_token_locker_id: Option<String>,
         network_token_payment_method_data: crypto::OptionalEncryptableValue,
+        vault_source_details: Option<PaymentMethodVaultSourceDetails>,
     ) -> errors::PmResult<payment_methods::PaymentMethod>;
 
     #[cfg(feature = "v2")]
diff --git a/crates/payment_methods/src/core/migration/payment_methods.rs b/crates/payment_methods/src/core/migration/payment_methods.rs
index 494e1987e21..086dccbc2fe 100644
--- a/crates/payment_methods/src/core/migration/payment_methods.rs
+++ b/crates/payment_methods/src/core/migration/payment_methods.rs
@@ -448,6 +448,7 @@ pub async fn get_client_secret_or_add_payment_method_for_migration(
                 None,
                 None,
                 None,
+                Default::default(),
             )
             .await?;
         migration_status.connector_mandate_details_migrated(
@@ -615,6 +616,7 @@ pub async fn skip_locker_call_and_migrate_payment_method(
                 network_token_requestor_reference_id: None,
                 network_token_locker_id: None,
                 network_token_payment_method_data: None,
+                vault_source_details: Default::default(),
             },
             merchant_context.get_merchant_account().storage_scheme,
         )
diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs
index 7047164f0c7..caa47dfea09 100644
--- a/crates/router/src/core/admin.rs
+++ b/crates/router/src/core/admin.rs
@@ -3478,6 +3478,13 @@ impl ProfileCreateBridge for api::ProfileCreate {
             dispute_polling_interval: self.dispute_polling_interval,
             is_manual_retry_enabled: self.is_manual_retry_enabled,
             always_enable_overcapture: self.always_enable_overcapture,
+            external_vault_details: domain::ExternalVaultDetails::try_from((
+                self.is_external_vault_enabled,
+                self.external_vault_connector_details
+                    .map(ForeignFrom::foreign_from),
+            ))
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("error while generating external vault details")?,
         }))
     }
 
@@ -3966,7 +3973,7 @@ impl ProfileUpdateBridge for api::ProfileUpdate {
                     .map(ForeignInto::foreign_into),
                 card_testing_secret_key,
                 is_clear_pan_retries_enabled: self.is_clear_pan_retries_enabled,
-                force_3ds_challenge: self.force_3ds_challenge, //
+                force_3ds_challenge: self.force_3ds_challenge,
                 is_debit_routing_enabled: self.is_debit_routing_enabled,
                 merchant_business_country: self.merchant_business_country,
                 is_iframe_redirection_enabled: self.is_iframe_redirection_enabled,
@@ -3976,6 +3983,10 @@ impl ProfileUpdateBridge for api::ProfileUpdate {
                 dispute_polling_interval: self.dispute_polling_interval,
                 is_manual_retry_enabled: self.is_manual_retry_enabled,
                 always_enable_overcapture: self.always_enable_overcapture,
+                is_external_vault_enabled: self.is_external_vault_enabled,
+                external_vault_connector_details: self
+                    .external_vault_connector_details
+                    .map(ForeignInto::foreign_into),
             },
         )))
     }
diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs
index 69b219f4ae0..1f94b9bd998 100644
--- a/crates/router/src/core/errors/utils.rs
+++ b/crates/router/src/core/errors/utils.rs
@@ -90,7 +90,6 @@ pub trait ConnectorErrorExt<T> {
     #[cfg(feature = "payouts")]
     #[track_caller]
     fn to_payout_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse>;
-    #[cfg(feature = "v2")]
     #[track_caller]
     fn to_vault_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse>;
 
@@ -521,7 +520,6 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
         })
     }
 
-    #[cfg(feature = "v2")]
     fn to_vault_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse> {
         self.map_err(|err| {
             let error = match err.current_context() {
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 06622842281..b07b89e1328 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -39,15 +39,13 @@ use error_stack::{report, ResultExt};
 use futures::TryStreamExt;
 #[cfg(feature = "v1")]
 use hyperswitch_domain_models::api::{GenericLinks, GenericLinksData};
-use hyperswitch_domain_models::payments::{
-    payment_attempt::PaymentAttempt, PaymentIntent, VaultData,
-};
-#[cfg(feature = "v2")]
 use hyperswitch_domain_models::{
-    payment_method_data, payment_methods as domain_payment_methods,
+    payments::{payment_attempt::PaymentAttempt, PaymentIntent, VaultData},
     router_data_v2::flow_common_types::VaultConnectorFlowData,
-    router_flow_types::ExternalVaultInsertFlow, types::VaultRouterData,
+    router_flow_types::ExternalVaultInsertFlow,
+    types::VaultRouterData,
 };
+use hyperswitch_interfaces::connector_integration_interface::RouterDataConversion;
 use masking::{PeekInterface, Secret};
 use router_env::{instrument, tracing};
 use time::Duration;
@@ -61,19 +59,13 @@ use super::{
 #[cfg(feature = "v2")]
 use crate::{
     configs::settings,
-    core::{
-        payment_methods::transformers as pm_transforms, payments as payments_core,
-        tokenization as tokenization_core, utils as core_utils,
-    },
-    db::errors::ConnectorErrorExt,
-    headers, logger,
+    core::{payment_methods::transformers as pm_transforms, tokenization as tokenization_core},
+    headers,
     routes::{self, payment_methods as pm_routes},
-    services::{connector_integration_interface::RouterDataConversion, encryption},
+    services::encryption,
     types::{
-        self,
-        api::{self, payment_methods::PaymentMethodCreateExt},
+        api::PaymentMethodCreateExt,
         domain::types as domain_types,
-        payment_methods as pm_types,
         storage::{ephemeral_key, PaymentMethodListContext},
         transformers::{ForeignFrom, ForeignTryFrom},
         Tokenizable,
@@ -84,13 +76,15 @@ use crate::{
     consts,
     core::{
         errors::{ProcessTrackerError, RouterResult},
-        payments::helpers as payment_helpers,
+        payments::{self as payments_core, helpers as payment_helpers},
+        utils as core_utils,
     },
-    errors,
+    db::errors::ConnectorErrorExt,
+    errors, logger,
     routes::{app::StorageInterface, SessionState},
     services,
     types::{
-        domain,
+        self, api, domain, payment_methods as pm_types,
         storage::{self, enums as storage_enums},
     },
 };
@@ -1116,6 +1110,8 @@ pub async fn create_payment_method_proxy_card_core(
         Encryptable<hyperswitch_domain_models::address::Address>,
     >,
 ) -> RouterResult<(api::PaymentMethodResponse, domain::PaymentMethod)> {
+    use crate::core::payment_methods::vault::Vault;
+
     let key_manager_state = &(state).into();
 
     let external_vault_source = profile
@@ -1171,6 +1167,10 @@ pub async fn create_payment_method_proxy_card_core(
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Unable to parse External vault token data")?;
 
+    let vault_type = external_vault_source
+        .is_some()
+        .then_some(common_enums::VaultType::External);
+
     let payment_method = create_payment_method_for_confirm(
         state,
         customer_id,
@@ -1184,6 +1184,7 @@ pub async fn create_payment_method_proxy_card_core(
         payment_method_billing_address,
         encrypted_payment_method_data,
         encrypted_external_vault_token_data,
+        vault_type,
     )
     .await?;
 
@@ -1699,7 +1700,7 @@ pub async fn generate_token_data_response(
     state: &SessionState,
     request: payment_methods::GetTokenDataRequest,
     profile: domain::Profile,
-    payment_method: &domain_payment_methods::PaymentMethod,
+    payment_method: &domain::PaymentMethod,
 ) -> RouterResult<api::TokenDataResponse> {
     let token_details = match request.token_type {
         common_enums::TokenDataType::NetworkToken => {
@@ -1924,6 +1925,8 @@ pub async fn create_payment_method_for_intent(
         Encryptable<hyperswitch_domain_models::address::Address>,
     >,
 ) -> CustomResult<domain::PaymentMethod, errors::ApiErrorResponse> {
+    use josekit::jwe::zip::deflate::DeflateJweCompression::Def;
+
     let db = &*state.store;
 
     let current_time = common_utils::date_time::now();
@@ -1957,6 +1960,7 @@ pub async fn create_payment_method_for_intent(
                 network_token_requestor_reference_id: None,
                 external_vault_source: None,
                 external_vault_token_data: None,
+                vault_type: None,
             },
             storage_scheme,
         )
@@ -1987,6 +1991,7 @@ pub async fn create_payment_method_for_confirm(
     encrypted_external_vault_token_data: Option<
         Encryptable<payment_methods::ExternalVaultTokenData>,
     >,
+    vault_type: Option<common_enums::VaultType>,
 ) -> CustomResult<domain::PaymentMethod, errors::ApiErrorResponse> {
     let db = &*state.store;
     let key_manager_state = &state.into();
@@ -2021,6 +2026,7 @@ pub async fn create_payment_method_for_confirm(
                 network_token_requestor_reference_id: None,
                 external_vault_source,
                 external_vault_token_data: encrypted_external_vault_token_data,
+                vault_type,
             },
             storage_scheme,
         )
@@ -2039,9 +2045,9 @@ pub async fn get_external_vault_token(
     key_store: &domain::MerchantKeyStore,
     storage_scheme: enums::MerchantStorageScheme,
     payment_token: String,
-    vault_token: payment_method_data::VaultToken,
+    vault_token: domain::VaultToken,
     payment_method_type: &storage_enums::PaymentMethod,
-) -> CustomResult<payment_method_data::ExternalVaultPaymentMethodData, errors::ApiErrorResponse> {
+) -> CustomResult<domain::ExternalVaultPaymentMethodData, errors::ApiErrorResponse> {
     let db = &*state.store;
 
     let pm_token_data =
@@ -2099,12 +2105,12 @@ pub async fn get_external_vault_token(
 fn convert_from_saved_payment_method_data(
     vault_additional_data: payment_methods::PaymentMethodsData,
     external_vault_token_data: payment_methods::ExternalVaultTokenData,
-    vault_token: payment_method_data::VaultToken,
-) -> RouterResult<payment_method_data::ExternalVaultPaymentMethodData> {
+    vault_token: domain::VaultToken,
+) -> RouterResult<domain::ExternalVaultPaymentMethodData> {
     match vault_additional_data {
         payment_methods::PaymentMethodsData::Card(card_details) => {
-            Ok(payment_method_data::ExternalVaultPaymentMethodData::Card(
-                Box::new(domain::ExternalVaultCard {
+            Ok(domain::ExternalVaultPaymentMethodData::Card(Box::new(
+                domain::ExternalVaultCard {
                     card_number: external_vault_token_data.tokenized_card_number,
                     card_exp_month: card_details.expiry_month.ok_or(
                         errors::ApiErrorResponse::MissingRequiredField {
@@ -2127,8 +2133,8 @@ fn convert_from_saved_payment_method_data(
                     card_cvc: vault_token.card_cvc,
                     co_badged_card_data: None, // Co-badged data is not supported in external vault
                     bank_code: None,           // Bank code is not stored in external vault
-                }),
-            ))
+                },
+            )))
         }
         payment_methods::PaymentMethodsData::BankDetails(_)
         | payment_methods::PaymentMethodsData::WalletDetails(_) => {
@@ -2197,16 +2203,12 @@ pub async fn create_pm_additional_data_update(
     let encrypted_payment_method_data = pmd
         .map(
             |payment_method_vaulting_data| match payment_method_vaulting_data {
-                domain::PaymentMethodVaultingData::Card(card) => {
-                    payment_method_data::PaymentMethodsData::Card(
-                        payment_method_data::CardDetailsPaymentMethod::from(card.clone()),
-                    )
-                }
+                domain::PaymentMethodVaultingData::Card(card) => domain::PaymentMethodsData::Card(
+                    domain::CardDetailsPaymentMethod::from(card.clone()),
+                ),
                 domain::PaymentMethodVaultingData::NetworkToken(network_token) => {
-                    payment_method_data::PaymentMethodsData::NetworkToken(
-                        payment_method_data::NetworkTokenDetailsPaymentMethod::from(
-                            network_token.clone(),
-                        ),
+                    domain::PaymentMethodsData::NetworkToken(
+                        domain::NetworkTokenDetailsPaymentMethod::from(network_token.clone()),
                     )
                 }
             },
@@ -2311,10 +2313,20 @@ pub async fn vault_payment_method_external(
     merchant_account: &domain::MerchantAccount,
     merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
 ) -> RouterResult<pm_types::AddVaultResponse> {
+    let merchant_connector_account = match &merchant_connector_account {
+        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(mca) => {
+            Ok(mca.as_ref())
+        }
+        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(_) => {
+            Err(report!(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("MerchantConnectorDetails not supported for vault operations"))
+        }
+    }?;
+
     let router_data = core_utils::construct_vault_router_data(
         state,
-        merchant_account,
-        &merchant_connector_account,
+        merchant_account.get_id(),
+        merchant_connector_account,
         Some(pmd.clone()),
         None,
         None,
@@ -2327,16 +2339,68 @@ pub async fn vault_payment_method_external(
             "Cannot construct router data for making the external vault insert api call",
         )?;
 
-    let connector_name = merchant_connector_account
-        .get_connector_name()
-        .ok_or(errors::ApiErrorResponse::InternalServerError)
-        .attach_printable("Connector name not present for external vault")?; // always get the connector name from this call
+    let connector_name = merchant_connector_account.get_connector_name_as_string(); // always get the connector name from this call
 
     let connector_data = api::ConnectorData::get_external_vault_connector_by_name(
         &state.conf.connectors,
-        &connector_name,
+        connector_name,
         api::GetToken::Connector,
-        merchant_connector_account.get_mca_id(),
+        Some(merchant_connector_account.get_id()),
+    )
+    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .attach_printable("Failed to get the connector data")?;
+
+    let connector_integration: services::BoxedVaultConnectorIntegrationInterface<
+        ExternalVaultInsertFlow,
+        types::VaultRequestData,
+        types::VaultResponseData,
+    > = connector_data.connector.get_connector_integration();
+
+    let router_data_resp = services::execute_connector_processing_step(
+        state,
+        connector_integration,
+        &old_router_data,
+        payments_core::CallConnectorAction::Trigger,
+        None,
+        None,
+    )
+    .await
+    .to_vault_failed_response()?;
+
+    get_vault_response_for_insert_payment_method_data(router_data_resp)
+}
+
+#[cfg(feature = "v1")]
+#[instrument(skip_all)]
+pub async fn vault_payment_method_external_v1(
+    state: &SessionState,
+    pmd: &hyperswitch_domain_models::vault::PaymentMethodVaultingData,
+    merchant_account: &domain::MerchantAccount,
+    merchant_connector_account: hyperswitch_domain_models::merchant_connector_account::MerchantConnectorAccount,
+) -> RouterResult<pm_types::AddVaultResponse> {
+    let router_data = core_utils::construct_vault_router_data(
+        state,
+        merchant_account.get_id(),
+        &merchant_connector_account,
+        Some(pmd.clone()),
+        None,
+        None,
+    )
+    .await?;
+
+    let old_router_data = VaultConnectorFlowData::to_old_router_data(router_data)
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable(
+            "Cannot construct router data for making the external vault insert api call",
+        )?;
+
+    let connector_name = merchant_connector_account.get_connector_name_as_string();
+
+    let connector_data = api::ConnectorData::get_external_vault_connector_by_name(
+        &state.conf.connectors,
+        connector_name,
+        api::GetToken::Connector,
+        Some(merchant_connector_account.get_id()),
     )
     .change_context(errors::ApiErrorResponse::InternalServerError)
     .attach_printable("Failed to get the connector data")?;
@@ -2361,7 +2425,6 @@ pub async fn vault_payment_method_external(
     get_vault_response_for_insert_payment_method_data(router_data_resp)
 }
 
-#[cfg(feature = "v2")]
 pub fn get_vault_response_for_insert_payment_method_data<F>(
     router_data: VaultRouterData<F>,
 ) -> RouterResult<pm_types::AddVaultResponse> {
@@ -2370,11 +2433,18 @@ pub fn get_vault_response_for_insert_payment_method_data<F>(
             types::VaultResponseData::ExternalVaultInsertResponse {
                 connector_vault_id,
                 fingerprint_id,
-            } => Ok(pm_types::AddVaultResponse {
-                vault_id: domain::VaultId::generate(connector_vault_id),
-                fingerprint_id: Some(fingerprint_id),
-                entity_id: None,
-            }),
+            } => {
+                #[cfg(feature = "v2")]
+                let vault_id = domain::VaultId::generate(connector_vault_id);
+                #[cfg(not(feature = "v2"))]
+                let vault_id = connector_vault_id;
+
+                Ok(pm_types::AddVaultResponse {
+                    vault_id,
+                    fingerprint_id: Some(fingerprint_id),
+                    entity_id: None,
+                })
+            }
             types::VaultResponseData::ExternalVaultRetrieveResponse { .. }
             | types::VaultResponseData::ExternalVaultDeleteResponse { .. }
             | types::VaultResponseData::ExternalVaultCreateResponse { .. } => {
@@ -2701,7 +2771,7 @@ pub async fn retrieve_payment_method(
 
     let single_use_token_in_cache = get_single_use_token_from_store(
         &state.clone(),
-        payment_method_data::SingleUseTokenKey::store_key(&pm_id.clone()),
+        domain::SingleUseTokenKey::store_key(&pm_id.clone()),
     )
     .await
     .unwrap_or_default();
@@ -3686,7 +3756,7 @@ async fn create_single_use_tokenization_flow(
         .attach_printable("Failed while parsing value for ConnectorAuthType")?;
 
     let payment_method_data_request = types::PaymentMethodTokenizationData {
-        payment_method_data: payment_method_data::PaymentMethodData::try_from(
+        payment_method_data: domain::PaymentMethodData::try_from(
             payment_method_create_request.payment_method_data.clone(),
         )
         .change_context(errors::ApiErrorResponse::MissingRequiredField {
@@ -3793,12 +3863,12 @@ async fn create_single_use_tokenization_flow(
         }
     })?;
 
-    let value = payment_method_data::SingleUsePaymentMethodToken::get_single_use_token_from_payment_method_token(
-                                                       token_response.clone().into(),
-                                                connector_id.clone()
-                                            );
+    let value = domain::SingleUsePaymentMethodToken::get_single_use_token_from_payment_method_token(
+        token_response.clone().into(),
+        connector_id.clone(),
+    );
 
-    let key = payment_method_data::SingleUseTokenKey::store_key(&payment_method.id);
+    let key = domain::SingleUseTokenKey::store_key(&payment_method.id);
 
     add_single_use_token_to_store(&state, key, value)
         .await
@@ -3811,8 +3881,8 @@ async fn create_single_use_tokenization_flow(
 #[cfg(feature = "v2")]
 async fn add_single_use_token_to_store(
     state: &SessionState,
-    key: payment_method_data::SingleUseTokenKey,
-    value: payment_method_data::SingleUsePaymentMethodToken,
+    key: domain::SingleUseTokenKey,
+    value: domain::SingleUsePaymentMethodToken,
 ) -> CustomResult<(), errors::StorageError> {
     let redis_connection = state
         .store
@@ -3821,7 +3891,7 @@ async fn add_single_use_token_to_store(
 
     redis_connection
         .serialize_and_set_key_with_expiry(
-            &payment_method_data::SingleUseTokenKey::get_store_key(&key).into(),
+            &domain::SingleUseTokenKey::get_store_key(&key).into(),
             value,
             consts::DEFAULT_PAYMENT_METHOD_STORE_TTL,
         )
@@ -3834,16 +3904,16 @@ async fn add_single_use_token_to_store(
 #[cfg(feature = "v2")]
 async fn get_single_use_token_from_store(
     state: &SessionState,
-    key: payment_method_data::SingleUseTokenKey,
-) -> CustomResult<Option<payment_method_data::SingleUsePaymentMethodToken>, errors::StorageError> {
+    key: domain::SingleUseTokenKey,
+) -> CustomResult<Option<domain::SingleUsePaymentMethodToken>, errors::StorageError> {
     let redis_connection = state
         .store
         .get_redis_conn()
         .map_err(Into::<errors::StorageError>::into)?;
 
     redis_connection
-        .get_and_deserialize_key::<Option<payment_method_data::SingleUsePaymentMethodToken>>(
-            &payment_method_data::SingleUseTokenKey::get_store_key(&key).into(),
+        .get_and_deserialize_key::<Option<domain::SingleUsePaymentMethodToken>>(
+            &domain::SingleUseTokenKey::get_store_key(&key).into(),
             "SingleUsePaymentMethodToken",
         )
         .await
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 322557129d4..ac225861b45 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -131,6 +131,7 @@ impl PaymentMethodsController for PmCards<'_> {
         network_token_requestor_reference_id: Option<String>,
         network_token_locker_id: Option<String>,
         network_token_payment_method_data: crypto::OptionalEncryptableValue,
+        vault_source_details: Option<domain::PaymentMethodVaultSourceDetails>,
     ) -> errors::CustomResult<domain::PaymentMethod, errors::ApiErrorResponse> {
         let db = &*self.state.store;
         let customer = db
@@ -190,6 +191,8 @@ impl PaymentMethodsController for PmCards<'_> {
                     network_token_requestor_reference_id,
                     network_token_locker_id,
                     network_token_payment_method_data,
+                    vault_source_details: vault_source_details
+                        .unwrap_or(domain::PaymentMethodVaultSourceDetails::InternalVault),
                 },
                 self.merchant_context.get_merchant_account().storage_scheme,
             )
@@ -320,6 +323,7 @@ impl PaymentMethodsController for PmCards<'_> {
                         None,
                         None,
                         None,
+                        Default::default(),
                     )
                     .await
                 } else {
@@ -464,6 +468,7 @@ impl PaymentMethodsController for PmCards<'_> {
         network_token_requestor_reference_id: Option<String>,
         network_token_locker_id: Option<String>,
         network_token_payment_method_data: crypto::OptionalEncryptableValue,
+        vault_source_details: Option<domain::PaymentMethodVaultSourceDetails>,
     ) -> errors::RouterResult<domain::PaymentMethod> {
         let pm_card_details = resp.card.clone().map(|card| {
             PaymentMethodsData::Card(CardDetailsPaymentMethod::from((card.clone(), None)))
@@ -497,6 +502,7 @@ impl PaymentMethodsController for PmCards<'_> {
             network_token_requestor_reference_id,
             network_token_locker_id,
             network_token_payment_method_data,
+            vault_source_details,
         )
         .await
     }
@@ -1298,6 +1304,7 @@ impl PaymentMethodsController for PmCards<'_> {
                         None,
                         None,
                         None,
+                        Default::default(), //Currently this method is used for adding payment method via PaymentMethodCreate API which doesn't support external vault. hence Default i.e. InternalVault is passed for vault source and type
                     )
                     .await?;
 
@@ -1372,6 +1379,7 @@ pub async fn get_client_secret_or_add_payment_method(
                 None,
                 None,
                 None,
+                Default::default(), //Currently this method is used for adding payment method via PaymentMethodCreate API which doesn't support external vault. hence Default i.e. InternalVault is passed for vault type
             )
             .await?;
 
diff --git a/crates/router/src/core/payment_methods/tokenize/card_executor.rs b/crates/router/src/core/payment_methods/tokenize/card_executor.rs
index 905d2d3a126..8b405947af9 100644
--- a/crates/router/src/core/payment_methods/tokenize/card_executor.rs
+++ b/crates/router/src/core/payment_methods/tokenize/card_executor.rs
@@ -596,6 +596,7 @@ impl CardNetworkTokenizeExecutor<'_, domain::TokenizeCardRequest> {
             network_token_details.1.clone(),
             Some(stored_locker_resp.store_token_resp.card_reference.clone()),
             Some(enc_token_data),
+            Default::default(), // this method is used only for card bulk tokenization, and currently external vault is not supported for this hence passing Default i.e. InternalVault
         )
         .await
     }
diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs
index 7e2c5876ac8..771df3d97c7 100644
--- a/crates/router/src/core/payment_methods/vault.rs
+++ b/crates/router/src/core/payment_methods/vault.rs
@@ -9,10 +9,11 @@ use common_utils::{
 };
 use error_stack::{report, ResultExt};
 #[cfg(feature = "v2")]
+use hyperswitch_domain_models::router_flow_types::{
+    ExternalVaultDeleteFlow, ExternalVaultRetrieveFlow,
+};
 use hyperswitch_domain_models::{
-    router_data_v2::flow_common_types::VaultConnectorFlowData,
-    router_flow_types::{ExternalVaultDeleteFlow, ExternalVaultRetrieveFlow},
-    types::VaultRouterData,
+    router_data_v2::flow_common_types::VaultConnectorFlowData, types::VaultRouterData,
 };
 use masking::PeekInterface;
 use router_env::{instrument, tracing};
@@ -22,11 +23,15 @@ use scheduler::{types::process_data, utils as process_tracker_utils};
 use crate::types::api::payouts;
 use crate::{
     consts,
-    core::errors::{self, CustomResult, RouterResult},
+    core::{
+        errors::{self, ConnectorErrorExt, CustomResult, RouterResult},
+        payments, utils as core_utils,
+    },
     db, logger,
     routes::{self, metrics},
+    services::{self, connector_integration_interface::RouterDataConversion},
     types::{
-        api, domain,
+        self, api, domain,
         storage::{self, enums},
     },
     utils::StringExt,
@@ -34,16 +39,12 @@ use crate::{
 #[cfg(feature = "v2")]
 use crate::{
     core::{
-        errors::ConnectorErrorExt,
         errors::StorageErrorExt,
         payment_methods::{transformers as pm_transforms, utils},
         payments::{self as payments_core, helpers as payment_helpers},
-        utils as core_utils,
     },
-    headers,
-    services::{self, connector_integration_interface::RouterDataConversion},
-    settings,
-    types::{self, payment_methods as pm_types},
+    headers, settings,
+    types::payment_methods as pm_types,
     utils::{ext_traits::OptionExt, ConnectorResponseExt},
 };
 
@@ -1396,10 +1397,20 @@ pub async fn retrieve_payment_method_from_vault_external(
         .clone()
         .map(|id| id.get_string_repr().to_owned());
 
+    let merchant_connector_account = match &merchant_connector_account {
+        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(mca) => {
+            Ok(mca.as_ref())
+        }
+        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(_) => {
+            Err(report!(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("MerchantConnectorDetails not supported for vault operations"))
+        }
+    }?;
+
     let router_data = core_utils::construct_vault_router_data(
         state,
-        merchant_account,
-        &merchant_connector_account,
+        merchant_account.get_id(),
+        merchant_connector_account,
         None,
         connector_vault_id,
         None,
@@ -1412,16 +1423,13 @@ pub async fn retrieve_payment_method_from_vault_external(
             "Cannot construct router data for making the external vault retrieve api call",
         )?;
 
-    let connector_name = merchant_connector_account
-        .get_connector_name()
-        .ok_or(errors::ApiErrorResponse::InternalServerError)
-        .attach_printable("Connector name not present for external vault")?; // always get the connector name from this call
+    let connector_name = merchant_connector_account.get_connector_name_as_string(); // always get the connector name from this call
 
     let connector_data = api::ConnectorData::get_external_vault_connector_by_name(
         &state.conf.connectors,
-        &connector_name,
+        connector_name,
         api::GetToken::Connector,
-        merchant_connector_account.get_mca_id(),
+        Some(merchant_connector_account.get_id()),
     )
     .change_context(errors::ApiErrorResponse::InternalServerError)
     .attach_printable("Failed to get the connector data")?;
@@ -1744,10 +1752,21 @@ pub async fn delete_payment_method_data_from_vault_external(
 ) -> RouterResult<pm_types::VaultDeleteResponse> {
     let connector_vault_id = vault_id.get_string_repr().to_owned();
 
+    // Extract MerchantConnectorAccount from the enum
+    let merchant_connector_account = match &merchant_connector_account {
+        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(mca) => {
+            Ok(mca.as_ref())
+        }
+        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(_) => {
+            Err(report!(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("MerchantConnectorDetails not supported for vault operations"))
+        }
+    }?;
+
     let router_data = core_utils::construct_vault_router_data(
         state,
-        merchant_account,
-        &merchant_connector_account,
+        merchant_account.get_id(),
+        merchant_connector_account,
         None,
         Some(connector_vault_id),
         None,
@@ -1760,16 +1779,13 @@ pub async fn delete_payment_method_data_from_vault_external(
             "Cannot construct router data for making the external vault delete api call",
         )?;
 
-    let connector_name = merchant_connector_account
-        .get_connector_name()
-        .ok_or(errors::ApiErrorResponse::InternalServerError)
-        .attach_printable("Connector name not present for external vault")?; // always get the connector name from this call
+    let connector_name = merchant_connector_account.get_connector_name_as_string(); // always get the connector name from this call
 
     let connector_data = api::ConnectorData::get_external_vault_connector_by_name(
         &state.conf.connectors,
-        &connector_name,
+        connector_name,
         api::GetToken::Connector,
-        merchant_connector_account.get_mca_id(),
+        Some(merchant_connector_account.get_id()),
     )
     .change_context(errors::ApiErrorResponse::InternalServerError)
     .attach_printable("Failed to get the connector data")?;
@@ -1875,6 +1891,86 @@ pub async fn delete_payment_method_data_from_vault(
     }
 }
 
+#[cfg(feature = "v1")]
+#[instrument(skip_all)]
+pub async fn retrieve_payment_method_from_vault_external_v1(
+    state: &routes::SessionState,
+    merchant_id: &id_type::MerchantId,
+    pm: &domain::PaymentMethod,
+    merchant_connector_account: hyperswitch_domain_models::merchant_connector_account::MerchantConnectorAccount,
+) -> RouterResult<hyperswitch_domain_models::vault::PaymentMethodVaultingData> {
+    let connector_vault_id = pm.locker_id.clone().map(|id| id.to_string());
+
+    let router_data = core_utils::construct_vault_router_data(
+        state,
+        merchant_id,
+        &merchant_connector_account,
+        None,
+        connector_vault_id,
+        None,
+    )
+    .await?;
+
+    let old_router_data = VaultConnectorFlowData::to_old_router_data(router_data)
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable(
+            "Cannot construct router data for making the external vault retrieve api call",
+        )?;
+
+    let connector_name = merchant_connector_account.get_connector_name_as_string();
+
+    let connector_data = api::ConnectorData::get_external_vault_connector_by_name(
+        &state.conf.connectors,
+        connector_name,
+        api::GetToken::Connector,
+        Some(merchant_connector_account.get_id()),
+    )
+    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .attach_printable("Failed to get the connector data")?;
+
+    let connector_integration: services::BoxedVaultConnectorIntegrationInterface<
+        hyperswitch_domain_models::router_flow_types::ExternalVaultRetrieveFlow,
+        types::VaultRequestData,
+        types::VaultResponseData,
+    > = connector_data.connector.get_connector_integration();
+
+    let router_data_resp = services::execute_connector_processing_step(
+        state,
+        connector_integration,
+        &old_router_data,
+        payments::CallConnectorAction::Trigger,
+        None,
+        None,
+    )
+    .await
+    .to_vault_failed_response()?;
+
+    get_vault_response_for_retrieve_payment_method_data_v1(router_data_resp)
+}
+
+pub fn get_vault_response_for_retrieve_payment_method_data_v1<F>(
+    router_data: VaultRouterData<F>,
+) -> RouterResult<hyperswitch_domain_models::vault::PaymentMethodVaultingData> {
+    match router_data.response {
+        Ok(response) => match response {
+            types::VaultResponseData::ExternalVaultRetrieveResponse { vault_data } => {
+                Ok(vault_data)
+            }
+            types::VaultResponseData::ExternalVaultInsertResponse { .. }
+            | types::VaultResponseData::ExternalVaultDeleteResponse { .. }
+            | types::VaultResponseData::ExternalVaultCreateResponse { .. } => {
+                Err(report!(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Invalid Vault Response"))
+            }
+        },
+        Err(err) => {
+            logger::error!("Failed to retrieve payment method: {:?}", err);
+            Err(report!(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed to retrieve payment method"))
+        }
+    }
+}
+
 // ********************************************** PROCESS TRACKER **********************************************
 
 pub async fn add_delete_tokenized_data_task(
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 37703cd1bec..044466523d4 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -2196,7 +2196,7 @@ pub async fn retrieve_payment_method_data_with_permanent_token(
     _payment_method_id: &str,
     payment_intent: &PaymentIntent,
     card_token_data: Option<&domain::CardToken>,
-    _merchant_key_store: &domain::MerchantKeyStore,
+    merchant_key_store: &domain::MerchantKeyStore,
     _storage_scheme: enums::MerchantStorageScheme,
     mandate_id: Option<api_models::payments::MandateIds>,
     payment_method_info: domain::PaymentMethod,
@@ -2250,14 +2250,16 @@ pub async fn retrieve_payment_method_data_with_permanent_token(
                 .and_then(|vault_data| vault_data.get_card_vault_data())
                 .map(Ok)
                 .async_unwrap_or_else(|| async {
-                    fetch_card_details_from_locker(
+                    Box::pin(fetch_card_details_from_locker(
                         state,
                         customer_id,
                         &payment_intent.merchant_id,
                         locker_id,
                         card_token_data,
                         co_badged_card_data,
-                    )
+                        payment_method_info,
+                        merchant_key_store,
+                    ))
                     .await
                 })
                 .await?;
@@ -2301,14 +2303,16 @@ pub async fn retrieve_payment_method_data_with_permanent_token(
                             .and_then(|vault_data| vault_data.get_card_vault_data())
                             .map(Ok)
                             .async_unwrap_or_else(|| async {
-                                fetch_card_details_from_locker(
+                                Box::pin(fetch_card_details_from_locker(
                                     state,
                                     customer_id,
                                     &payment_intent.merchant_id,
                                     locker_id,
                                     card_token_data,
                                     co_badged_card_data,
-                                )
+                                    payment_method_info,
+                                    merchant_key_store,
+                                ))
                                 .await
                             })
                             .await?,
@@ -2363,7 +2367,7 @@ pub async fn retrieve_card_with_permanent_token_for_external_authentication(
             message: "no customer id provided for the payment".to_string(),
         })?;
     Ok(domain::PaymentMethodData::Card(
-        fetch_card_details_from_locker(
+        fetch_card_details_from_internal_locker(
             state,
             customer_id,
             &payment_intent.merchant_id,
@@ -2378,6 +2382,7 @@ pub async fn retrieve_card_with_permanent_token_for_external_authentication(
 }
 
 #[cfg(feature = "v1")]
+#[allow(clippy::too_many_arguments)]
 pub async fn fetch_card_details_from_locker(
     state: &SessionState,
     customer_id: &id_type::CustomerId,
@@ -2385,6 +2390,46 @@ pub async fn fetch_card_details_from_locker(
     locker_id: &str,
     card_token_data: Option<&domain::CardToken>,
     co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
+    payment_method_info: domain::PaymentMethod,
+    merchant_key_store: &domain::MerchantKeyStore,
+) -> RouterResult<domain::Card> {
+    match &payment_method_info.vault_source_details.clone() {
+        domain::PaymentMethodVaultSourceDetails::ExternalVault {
+            ref external_vault_source,
+        } => {
+            fetch_card_details_from_external_vault(
+                state,
+                merchant_id,
+                card_token_data,
+                co_badged_card_data,
+                payment_method_info,
+                merchant_key_store,
+                external_vault_source,
+            )
+            .await
+        }
+        domain::PaymentMethodVaultSourceDetails::InternalVault => {
+            fetch_card_details_from_internal_locker(
+                state,
+                customer_id,
+                merchant_id,
+                locker_id,
+                card_token_data,
+                co_badged_card_data,
+            )
+            .await
+        }
+    }
+}
+
+#[cfg(feature = "v1")]
+pub async fn fetch_card_details_from_internal_locker(
+    state: &SessionState,
+    customer_id: &id_type::CustomerId,
+    merchant_id: &id_type::MerchantId,
+    locker_id: &str,
+    card_token_data: Option<&domain::CardToken>,
+    co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
 ) -> RouterResult<domain::Card> {
     logger::debug!("Fetching card details from locker");
     let card = cards::get_card_from_locker(state, customer_id, merchant_id, locker_id)
@@ -2434,6 +2479,45 @@ pub async fn fetch_card_details_from_locker(
     Ok(domain::Card::from((api_card, co_badged_card_data)))
 }
 
+#[cfg(feature = "v1")]
+pub async fn fetch_card_details_from_external_vault(
+    state: &SessionState,
+    merchant_id: &id_type::MerchantId,
+    card_token_data: Option<&domain::CardToken>,
+    co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
+    payment_method_info: domain::PaymentMethod,
+    merchant_key_store: &domain::MerchantKeyStore,
+    external_vault_mca_id: &id_type::MerchantConnectorAccountId,
+) -> RouterResult<domain::Card> {
+    let key_manager_state = &state.into();
+
+    let merchant_connector_account_details = state
+        .store
+        .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
+            key_manager_state,
+            merchant_id,
+            external_vault_mca_id,
+            merchant_key_store,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
+            id: external_vault_mca_id.get_string_repr().to_string(),
+        })?;
+
+    let vault_resp = vault::retrieve_payment_method_from_vault_external_v1(
+        state,
+        merchant_id,
+        &payment_method_info,
+        merchant_connector_account_details,
+    )
+    .await?;
+
+    match vault_resp {
+        hyperswitch_domain_models::vault::PaymentMethodVaultingData::Card(card) => Ok(
+            domain::Card::from((card, card_token_data, co_badged_card_data)),
+        ),
+    }
+}
 #[cfg(feature = "v1")]
 pub async fn fetch_network_token_details_from_locker(
     state: &SessionState,
diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs
index 759db4ef963..3ee7e0a1d53 100644
--- a/crates/router/src/core/payments/tokenization.rs
+++ b/crates/router/src/core/payments/tokenization.rs
@@ -15,6 +15,7 @@ use common_utils::{
     metrics::utils::record_operation_time,
     pii,
 };
+use diesel_models::business_profile::ExternalVaultConnectorDetails;
 use error_stack::{report, ResultExt};
 #[cfg(feature = "v1")]
 use hyperswitch_domain_models::{
@@ -26,6 +27,8 @@ use masking::{ExposeInterface, Secret};
 use router_env::{instrument, tracing};
 
 use super::helpers;
+#[cfg(feature = "v1")]
+use crate::core::payment_methods::vault_payment_method_external_v1;
 use crate::{
     consts,
     core::{
@@ -50,6 +53,38 @@ use crate::{
     utils::{generate_id, OptionExt},
 };
 
+#[cfg(feature = "v1")]
+async fn save_in_locker(
+    state: &SessionState,
+    merchant_context: &domain::MerchantContext,
+    payment_method_request: api::PaymentMethodCreate,
+    card_detail: Option<api::CardDetail>,
+    business_profile: &domain::Profile,
+) -> RouterResult<(
+    api_models::payment_methods::PaymentMethodResponse,
+    Option<payment_methods::transformers::DataDuplicationCheck>,
+)> {
+    match &business_profile.external_vault_details {
+        domain::ExternalVaultDetails::ExternalVaultEnabled(external_vault_details) => {
+            logger::info!("External vault is enabled, using vault_payment_method_external_v1");
+
+            Box::pin(save_in_locker_external(
+                state,
+                merchant_context,
+                payment_method_request,
+                card_detail,
+                external_vault_details,
+            ))
+            .await
+        }
+        domain::ExternalVaultDetails::Skip => {
+            // Use internal vault (locker)
+            save_in_locker_internal(state, merchant_context, payment_method_request, card_detail)
+                .await
+        }
+    }
+}
+
 pub struct SavePaymentMethodData<Req> {
     request: Req,
     response: Result<types::PaymentsResponseData, types::ErrorResponse>,
@@ -241,6 +276,7 @@ where
                         merchant_context,
                         payment_method_create_request.clone(),
                         is_network_tokenization_enabled,
+                        business_profile,
                     )
                     .await?
                 };
@@ -333,6 +369,21 @@ where
 
                 let mut payment_method_id = resp.payment_method_id.clone();
                 let mut locker_id = None;
+                let (external_vault_details, vault_type) = match &business_profile.external_vault_details{
+                    hyperswitch_domain_models::business_profile::ExternalVaultDetails::ExternalVaultEnabled(external_vault_connector_details) => {
+                        (Some(external_vault_connector_details), Some(common_enums::VaultType::External))
+                    },
+                    hyperswitch_domain_models::business_profile::ExternalVaultDetails::Skip => (None, Some(common_enums::VaultType::Internal)),
+                };
+                let external_vault_mca_id = external_vault_details
+                    .map(|connector_details| connector_details.vault_connector_id.clone());
+
+                let vault_source_details = domain::PaymentMethodVaultSourceDetails::try_from((
+                    vault_type,
+                    external_vault_mca_id,
+                ))
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Unable to create vault source details")?;
 
                 match duplication_check {
                     Some(duplication_check) => match duplication_check {
@@ -425,6 +476,7 @@ where
                                                 network_token_requestor_ref_id,
                                                 network_token_locker_id,
                                                 pm_network_token_data_encrypted,
+                                                Some(vault_source_details),
                                             )
                                             .await
                                     } else {
@@ -544,6 +596,7 @@ where
                                                     network_token_requestor_ref_id,
                                                     network_token_locker_id,
                                                     pm_network_token_data_encrypted,
+                                                    Some(vault_source_details),
                                                 )
                                                 .await
                                         } else {
@@ -765,6 +818,7 @@ where
                                     network_token_requestor_ref_id.clone(),
                                     network_token_locker_id,
                                     pm_network_token_data_encrypted,
+                                    Some(vault_source_details),
                                 )
                                 .await?;
 
@@ -1043,7 +1097,7 @@ async fn skip_saving_card_in_locker(
 }
 
 #[cfg(feature = "v1")]
-pub async fn save_in_locker(
+pub async fn save_in_locker_internal(
     state: &SessionState,
     merchant_context: &domain::MerchantContext,
     payment_method_request: api::PaymentMethodCreate,
@@ -1093,8 +1147,100 @@ pub async fn save_in_locker(
     }
 }
 
+#[cfg(feature = "v1")]
+pub async fn save_in_locker_external(
+    state: &SessionState,
+    merchant_context: &domain::MerchantContext,
+    payment_method_request: api::PaymentMethodCreate,
+    card_detail: Option<api::CardDetail>,
+    external_vault_connector_details: &ExternalVaultConnectorDetails,
+) -> RouterResult<(
+    api_models::payment_methods::PaymentMethodResponse,
+    Option<payment_methods::transformers::DataDuplicationCheck>,
+)> {
+    let customer_id = payment_method_request
+        .customer_id
+        .clone()
+        .get_required_value("customer_id")?;
+    // For external vault, we need to convert the card data to PaymentMethodVaultingData
+    if let Some(card) = card_detail {
+        let payment_method_vaulting_data =
+            hyperswitch_domain_models::vault::PaymentMethodVaultingData::Card(card.clone());
+
+        let external_vault_mca_id = external_vault_connector_details.vault_connector_id.clone();
+
+        let key_manager_state = &state.into();
+
+        let merchant_connector_account_details = state
+            .store
+            .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
+                key_manager_state,
+                merchant_context.get_merchant_account().get_id(),
+                &external_vault_mca_id,
+                merchant_context.get_merchant_key_store(),
+            )
+            .await
+            .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
+                id: external_vault_mca_id.get_string_repr().to_string(),
+            })?;
+
+        // Call vault_payment_method_external_v1
+        let vault_response = vault_payment_method_external_v1(
+            state,
+            &payment_method_vaulting_data,
+            merchant_context.get_merchant_account(),
+            merchant_connector_account_details,
+        )
+        .await?;
+
+        let payment_method_id = vault_response.vault_id.to_string().to_owned();
+        let card_detail = CardDetailFromLocker::from(card);
+
+        let pm_resp = api::PaymentMethodResponse {
+            merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
+            customer_id: Some(customer_id),
+            payment_method_id,
+            payment_method: payment_method_request.payment_method,
+            payment_method_type: payment_method_request.payment_method_type,
+            card: Some(card_detail),
+            recurring_enabled: Some(false),
+            installment_payment_enabled: Some(false),
+            payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
+            metadata: None,
+            created: Some(common_utils::date_time::now()),
+            #[cfg(feature = "payouts")]
+            bank_transfer: None,
+            last_used_at: Some(common_utils::date_time::now()),
+            client_secret: None,
+        };
+
+        Ok((pm_resp, None))
+    } else {
+        //Similar implementation is done for save in locker internal
+        let pm_id = common_utils::generate_id(consts::ID_LENGTH, "pm");
+        let payment_method_response = api::PaymentMethodResponse {
+            merchant_id: merchant_context.get_merchant_account().get_id().to_owned(),
+            customer_id: Some(customer_id),
+            payment_method_id: pm_id,
+            payment_method: payment_method_request.payment_method,
+            payment_method_type: payment_method_request.payment_method_type,
+            #[cfg(feature = "payouts")]
+            bank_transfer: None,
+            card: None,
+            metadata: None,
+            created: Some(common_utils::date_time::now()),
+            recurring_enabled: Some(false),
+            installment_payment_enabled: Some(false),
+            payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219]
+            last_used_at: Some(common_utils::date_time::now()),
+            client_secret: None,
+        };
+        Ok((payment_method_response, None))
+    }
+}
+
 #[cfg(feature = "v2")]
-pub async fn save_in_locker(
+pub async fn save_in_locker_internal(
     _state: &SessionState,
     _merchant_context: &domain::MerchantContext,
     _payment_method_request: api::PaymentMethodCreate,
@@ -1595,6 +1741,7 @@ pub async fn save_card_and_network_token_in_locker(
     merchant_context: &domain::MerchantContext,
     payment_method_create_request: api::PaymentMethodCreate,
     is_network_tokenization_enabled: bool,
+    business_profile: &domain::Profile,
 ) -> RouterResult<(
     (
         api_models::payment_methods::PaymentMethodResponse,
@@ -1633,6 +1780,7 @@ pub async fn save_card_and_network_token_in_locker(
                 merchant_context,
                 payment_method_create_request.to_owned(),
                 Some(card_data),
+                business_profile,
             ))
             .await
             .change_context(errors::ApiErrorResponse::InternalServerError)
@@ -1654,7 +1802,7 @@ pub async fn save_card_and_network_token_in_locker(
             );
 
             if payment_method_status == common_enums::PaymentMethodStatus::Active {
-                let (res, dc) = Box::pin(save_in_locker(
+                let (res, dc) = Box::pin(save_in_locker_internal(
                     state,
                     merchant_context,
                     payment_method_create_request.to_owned(),
@@ -1699,7 +1847,7 @@ pub async fn save_card_and_network_token_in_locker(
                     )
                     .await;
                 }
-                let (res, dc) = Box::pin(save_in_locker(
+                let (res, dc) = Box::pin(save_in_locker_internal(
                     state,
                     merchant_context,
                     payment_method_create_request.to_owned(),
@@ -1713,13 +1861,17 @@ pub async fn save_card_and_network_token_in_locker(
             }
         }
         _ => {
+            let card_data = payment_method_create_request.card.clone();
             let (res, dc) = Box::pin(save_in_locker(
                 state,
                 merchant_context,
                 payment_method_create_request.to_owned(),
-                None,
+                card_data,
+                business_profile,
             ))
-            .await?;
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Add Card In Locker Failed")?;
 
             if is_network_tokenization_enabled {
                 match &payment_method_data {
diff --git a/crates/router/src/core/payments/vault_session.rs b/crates/router/src/core/payments/vault_session.rs
index 10b965786e5..228b72bd9a8 100644
--- a/crates/router/src/core/payments/vault_session.rs
+++ b/crates/router/src/core/payments/vault_session.rs
@@ -2,7 +2,7 @@ use std::{fmt::Debug, str::FromStr};
 
 pub use common_enums::enums::CallConnectorAction;
 use common_utils::id_type;
-use error_stack::ResultExt;
+use error_stack::{report, ResultExt};
 pub use hyperswitch_domain_models::{
     mandates::MandateData,
     payment_address::PaymentAddress,
@@ -349,11 +349,20 @@ where
         api::GetToken::Connector,
         merchant_connector_account_type.get_mca_id(),
     )?;
+    let merchant_connector_account = match &merchant_connector_account_type {
+        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorAccount(mca) => {
+            Ok(mca.as_ref())
+        }
+        domain::MerchantConnectorAccountTypeDetails::MerchantConnectorDetails(_) => {
+            Err(report!(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("MerchantConnectorDetails not supported for vault operations"))
+        }
+    }?;
 
     let mut router_data = core_utils::construct_vault_router_data(
         state,
-        merchant_context.get_merchant_account(),
-        merchant_connector_account_type,
+        merchant_context.get_merchant_account().get_id(),
+        merchant_connector_account,
         None,
         None,
         connector_customer_id,
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index c80a089e5d4..00bcc7a26f6 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -646,6 +646,7 @@ pub async fn save_payout_data_to_locker(
                 None,
                 None,
                 None,
+                Default::default(),
             )
             .await?,
         );
diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs
index 0ed160784cb..9823cc94d7e 100644
--- a/crates/router/src/core/pm_auth.rs
+++ b/crates/router/src/core/pm_auth.rs
@@ -529,6 +529,7 @@ async fn store_bank_details_in_payment_methods(
                 network_token_requestor_reference_id: None,
                 network_token_locker_id: None,
                 network_token_payment_method_data: None,
+                vault_source_details: Default::default(),
             };
 
             new_entries.push(pm_new);
diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs
index 432a148fc41..38b9566d359 100644
--- a/crates/router/src/core/utils.rs
+++ b/crates/router/src/core/utils.rs
@@ -19,12 +19,12 @@ use error_stack::{report, ResultExt};
 #[cfg(feature = "v2")]
 use hyperswitch_domain_models::types::VaultRouterData;
 use hyperswitch_domain_models::{
-    merchant_connector_account::MerchantConnectorAccount, payment_address::PaymentAddress,
-    router_data::ErrorResponse, router_request_types, types::OrderDetailsWithAmount,
-};
-#[cfg(feature = "v2")]
-use hyperswitch_domain_models::{
-    router_data_v2::flow_common_types::VaultConnectorFlowData, types::VaultRouterDataV2,
+    merchant_connector_account::MerchantConnectorAccount,
+    payment_address::PaymentAddress,
+    router_data::ErrorResponse,
+    router_data_v2::flow_common_types::VaultConnectorFlowData,
+    router_request_types,
+    types::{OrderDetailsWithAmount, VaultRouterDataV2},
 };
 use hyperswitch_interfaces::api::ConnectorSpecifications;
 #[cfg(feature = "v2")]
@@ -2350,25 +2350,22 @@ pub(crate) fn validate_profile_id_from_auth_layer<T: GetProfileId + std::fmt::De
     }
 }
 
-#[cfg(feature = "v2")]
 pub async fn construct_vault_router_data<F>(
     state: &SessionState,
-    merchant_account: &domain::MerchantAccount,
-    merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
-    payment_method_vaulting_data: Option<domain::PaymentMethodVaultingData>,
+    merchant_id: &common_utils::id_type::MerchantId,
+    merchant_connector_account: &MerchantConnectorAccount,
+    payment_method_vaulting_data: Option<
+        hyperswitch_domain_models::vault::PaymentMethodVaultingData,
+    >,
     connector_vault_id: Option<String>,
     connector_customer_id: Option<String>,
 ) -> RouterResult<VaultRouterDataV2<F>> {
-    let connector_name = merchant_connector_account
-        .get_connector_name()
-        .ok_or(errors::ApiErrorResponse::InternalServerError)
-        .attach_printable("Connector name not present for external vault")?; // always get the connector name from the merchant_connector_account
     let connector_auth_type = merchant_connector_account
         .get_connector_account_details()
         .change_context(errors::ApiErrorResponse::InternalServerError)?;
 
     let resource_common_data = VaultConnectorFlowData {
-        merchant_id: merchant_account.get_id().to_owned(),
+        merchant_id: merchant_id.to_owned(),
     };
 
     let router_data = types::RouterDataV2 {
diff --git a/crates/router/src/db/events.rs b/crates/router/src/db/events.rs
index 94adf92e3df..a5ca7e29922 100644
--- a/crates/router/src/db/events.rs
+++ b/crates/router/src/db/events.rs
@@ -1291,6 +1291,7 @@ mod tests {
             dispute_polling_interval: None,
             is_manual_retry_enabled: None,
             always_enable_overcapture: None,
+            external_vault_details: domain::ExternalVaultDetails::Skip,
         });
 
         let business_profile = state
diff --git a/crates/router/src/types/api/admin.rs b/crates/router/src/types/api/admin.rs
index 0e8cb60ff81..3f96235c43f 100644
--- a/crates/router/src/types/api/admin.rs
+++ b/crates/router/src/types/api/admin.rs
@@ -172,6 +172,8 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
         let card_testing_guard_config = item
             .card_testing_guard_config
             .or(Some(CardTestingGuardConfig::default()));
+        let (is_external_vault_enabled, external_vault_connector_details) =
+            item.external_vault_details.into();
 
         Ok(Self {
             merchant_id: item.merchant_id,
@@ -235,6 +237,9 @@ impl ForeignTryFrom<domain::Profile> for ProfileResponse {
             dispute_polling_interval: item.dispute_polling_interval,
             is_manual_retry_enabled: item.is_manual_retry_enabled,
             always_enable_overcapture: item.always_enable_overcapture,
+            is_external_vault_enabled,
+            external_vault_connector_details: external_vault_connector_details
+                .map(ForeignFrom::foreign_from),
         })
     }
 }
@@ -495,5 +500,13 @@ pub async fn create_profile_from_merchant_account(
         dispute_polling_interval: request.dispute_polling_interval,
         is_manual_retry_enabled: request.is_manual_retry_enabled,
         always_enable_overcapture: request.always_enable_overcapture,
+        external_vault_details: domain::ExternalVaultDetails::try_from((
+            request.is_external_vault_enabled,
+            request
+                .external_vault_connector_details
+                .map(ForeignInto::foreign_into),
+        ))
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("error while generating external_vault_details")?,
     }))
 }
diff --git a/crates/router/src/types/api/connector_mapping.rs b/crates/router/src/types/api/connector_mapping.rs
index adef987b03d..f8ee7842fd9 100644
--- a/crates/router/src/types/api/connector_mapping.rs
+++ b/crates/router/src/types/api/connector_mapping.rs
@@ -76,21 +76,19 @@ impl ConnectorData {
         })
     }
 
-    #[cfg(feature = "v2")]
     pub fn get_external_vault_connector_by_name(
         _connectors: &Connectors,
-        connector: &enums::Connector,
+        connector: String,
         connector_type: GetToken,
         connector_id: Option<common_utils::id_type::MerchantConnectorAccountId>,
     ) -> CustomResult<Self, errors::ApiErrorResponse> {
-        let connector_enum = Self::convert_connector(&connector.to_string())?;
-        let external_vault_connector_name =
-            enums::VaultConnectors::from_str(&connector.to_string())
-                .change_context(errors::ConnectorError::InvalidConnectorName)
-                .change_context(errors::ApiErrorResponse::InternalServerError)
-                .attach_printable_lazy(|| {
-                    format!("unable to parse external vault connector name {connector:?}")
-                })?;
+        let connector_enum = Self::convert_connector(&connector)?;
+        let external_vault_connector_name = enums::VaultConnectors::from_str(&connector)
+            .change_context(errors::ConnectorError::InvalidConnectorName)
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable_lazy(|| {
+                format!("unable to parse external vault connector name {connector:?}")
+            })?;
         let connector_name = enums::Connector::from(external_vault_connector_name);
         Ok(Self {
             connector: connector_enum,
diff --git a/crates/router/src/types/domain.rs b/crates/router/src/types/domain.rs
index c5efabce398..29cbe3e735d 100644
--- a/crates/router/src/types/domain.rs
+++ b/crates/router/src/types/domain.rs
@@ -10,12 +10,20 @@ mod merchant_account {
     pub use hyperswitch_domain_models::merchant_account::*;
 }
 
+#[cfg(feature = "v2")]
 mod business_profile {
     pub use hyperswitch_domain_models::business_profile::{
         Profile, ProfileGeneralUpdate, ProfileSetter, ProfileUpdate,
     };
 }
 
+#[cfg(feature = "v1")]
+mod business_profile {
+    pub use hyperswitch_domain_models::business_profile::{
+        ExternalVaultDetails, Profile, ProfileGeneralUpdate, ProfileSetter, ProfileUpdate,
+    };
+}
+
 pub mod merchant_context {
     pub use hyperswitch_domain_models::merchant_context::{Context, MerchantContext};
 }
diff --git a/crates/router/src/types/payment_methods.rs b/crates/router/src/types/payment_methods.rs
index 88d60e7b3d4..45ee498967b 100644
--- a/crates/router/src/types/payment_methods.rs
+++ b/crates/router/src/types/payment_methods.rs
@@ -51,11 +51,16 @@ pub struct AddVaultRequest<D> {
     pub ttl: i64,
 }
 
-#[cfg(feature = "v2")]
 #[derive(Debug, serde::Deserialize, serde::Serialize)]
 pub struct AddVaultResponse {
+    #[cfg(feature = "v2")]
     pub entity_id: Option<id_type::GlobalCustomerId>,
+    #[cfg(feature = "v1")]
+    pub entity_id: Option<id_type::CustomerId>,
+    #[cfg(feature = "v2")]
     pub vault_id: domain::VaultId,
+    #[cfg(feature = "v1")]
+    pub vault_id: String,
     pub fingerprint_id: Option<String>,
 }
 
diff --git a/migrations/2025-09-20-190742_add_external_vault_source_in_payment_method_and_is_external_vault_enabled_in_profile/down.sql b/migrations/2025-09-20-190742_add_external_vault_source_in_payment_method_and_is_external_vault_enabled_in_profile/down.sql
new file mode 100644
index 00000000000..2763c4865e7
--- /dev/null
+++ b/migrations/2025-09-20-190742_add_external_vault_source_in_payment_method_and_is_external_vault_enabled_in_profile/down.sql
@@ -0,0 +1,9 @@
+-- This file should undo anything in `up.sql`
+ALTER TABLE payment_methods DROP COLUMN IF EXISTS external_vault_source;
+
+ALTER TABLE payment_methods DROP COLUMN IF EXISTS vault_type;
+
+-- This file should undo anything in `up.sql`
+ALTER TABLE business_profile DROP COLUMN IF EXISTS external_vault_mode;
+
+ALTER TABLE business_profile DROP COLUMN IF EXISTS external_vault_connector_details;
\ No newline at end of file
diff --git a/migrations/2025-09-20-190742_add_external_vault_source_in_payment_method_and_is_external_vault_enabled_in_profile/up.sql b/migrations/2025-09-20-190742_add_external_vault_source_in_payment_method_and_is_external_vault_enabled_in_profile/up.sql
new file mode 100644
index 00000000000..503b8d3b3e9
--- /dev/null
+++ b/migrations/2025-09-20-190742_add_external_vault_source_in_payment_method_and_is_external_vault_enabled_in_profile/up.sql
@@ -0,0 +1,11 @@
+-- Your SQL goes here
+ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS external_vault_source VARCHAR(64);
+
+ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS vault_type VARCHAR(64);
+
+-- Your SQL goes here
+ALTER TABLE business_profile
+ADD COLUMN IF NOT EXISTS is_external_vault_enabled BOOLEAN;
+
+ALTER TABLE business_profile 
+ADD COLUMN IF NOT EXISTS external_vault_connector_details JSONB;
\ 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 external vault support in v1 payments flow.
Currently we only save card in hs-card-vault
Added new support to save card in external vault based merchant-profile configuration.

Changes in code - 
During First CIT (fresh card for a customer c1 - setup future usage - on_session with customer acceptance)
- based on profile level config, vault is decided, vault creds are fetched from MCA. payment method data is stored in respective vault.
During Repeat CIT (Saved card for a customer c1 - payment token for c1)
- based on pm entry - vault type, and vault mca id, if external, mca creds are fetched, if internal, default flow.


DB changes - 
In business profile in api level & db level- 
```
is_external_vault_enabled: Option<bool>, //Indicates if external vault is enabled or not.
external_vault_connector_details: Option<ExternalVaultConnectorDetails>,// holds the active External Vault Connector Details
```
In Payment method table in db level (diesel model) - 
```
pub external_vault_source: Option<common_utils::id_type::MerchantConnectorAccountId>, //holds the mca of external vault with which payment method data has been stored
pub vault_type: Option<storage_enums::VaultType>, //enum variant whether it is ext vault or internal vault
```

### Additional Changes

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

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

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


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

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
- Create Vault Connector MCA (Eg - VGS)
```
curl --location 'http://localhost:8080/account/merchant_1758632854/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_jN7RVfxJgyz3GB7OASKFved09yY2lA17xEJSBbj47tBN03inP9rCADUooCF5Ozz6' \
--data '{
    "connector_type": "vault_processor",
    "connector_name": "vgs",
    "connector_account_details": {
        "auth_type": "SignatureKey",
        "api_key": "api key",
        "key1": "key 1",
        "api_secret": "api_secret"
    },
    "test_mode": true,
    "disabled": false,
    "business_country": "US",
    "business_label": "default",
    "payment_methods_enabled": [
    ],
    "metadata": {
        "endpoint_prefix": "ghjg",
        "google_pay": {
            "allowed_payment_methods": [
                {
                    "type": "CARD",
                    "parameters": {
                        "allowed_auth_methods": [
                            "PAN_ONLY",
                            "CRYPTOGRAM_3DS"
                        ],
                        "allowed_card_networks": [
                            "AMEX",
                            "DISCOVER",
                            "INTERAC",
                            "JCB",
                            "MASTERCARD",
                            "VISA"
                        ]
                    },
                    "tokenization_specification": {
                        "type": "PAYMENT_GATEWAY"
                    }
                }
            ],
            "merchant_info": {
                "merchant_name": "Narayan Bhat"
            }
        }
    },
     "connector_webhook_details": {
        "merchant_secret": "7091687210DF6DCA38B2E670B3D68EB53516A26CA85590E29024FFBD7CD23980"
    },
    "profile_id":"pro_KH7MujUjH2miLhfzGlAB"
}'
```
- Update Profile with below config to enable external vault
```
"is_external_vault_enabled": "enable",
    "external_vault_connector_details": {
        "vault_connector_id": "mca_lRJXlrSQ557zrIJUalxK"
    }
```
- Create payment with customer acceptance, and setup_future_usage - on_session/off_session
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key:api key' \
--data-raw '
{
    "amount": 1000,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    
    "customer_id": "cu_1758488194",
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
"payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "card_number",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "card_cvc": "737"
        }
    },

    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX",
            "last_name": "ss"
        }
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "John",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "browser_info": {
        "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.110 Safari\/537.36",
        "accept_header": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "125.0.0.1"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {},
    "order_details": [
        {
            "product_name": "Apple iphone 15",
            "quantity": 1,
            "amount": 0,
            "account_name": "transaction_processing"
        }
    ],
    "profile_id": "pro_KH7MujUjH2miLhfzGlAB"
}'
```

- Payment method should be saved with
 external_vault_source - mca_lRJXlrSQ557zrIJUalxK (VGS mca id)
vault_type   - external
<img width="1536" height="587" alt="Screenshot 2025-09-22 at 2 35 04 AM" src="https://github.com/user-attachments/assets/a7837f92-fd4f-4ddb-a887-190f3f1b3bc3" />

- If VGS is not enabled, then 
 external_vault_source - <Empty>
vault_type   - internal
<img width="1466" height="583" alt="Screenshot 2025-09-22 at 2 36 08 AM" src="https://github.com/user-attachments/assets/69b98983-1cae-478c-bc55-8fc1997e44ca" />

- make repeat CIT

Please note, test backward compatibility 
how to -make a payment with existing customer's saved payment method


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

- [ ] I formatted the code `cargo +nightly fmt --all`
- [ ] I addressed lints thrown by `cargo clippy`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
