Bug: [FEATURE] Add support for network tokenization for v2/payment-methods



Description:
Add support for network tokenization for v2/payment-methods create api.

Implementation:
for v2/payment-methods api, if the payment method is card and merchant opted for network tokenization, then card should be tokenized with network via token service.
diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json
index ba795d40594..f386d554dda 100644
--- a/api-reference-v2/openapi_spec.json
+++ b/api-reference-v2/openapi_spec.json
@@ -13741,6 +13741,14 @@
               }
             ],
             "nullable": true
+          },
+          "network_tokenization": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/NetworkTokenization"
+              }
+            ],
+            "nullable": true
           }
         },
         "additionalProperties": false
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index ba18cbba506..a228f5fbda1 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -135,6 +135,10 @@ pub struct PaymentMethodCreate {
     /// The billing details of the payment method
     #[schema(value_type = Option<Address>)]
     pub billing: Option<payments::Address>,
+
+    /// The network tokenization configuration if applicable
+    #[schema(value_type = Option<NetworkTokenization>)]
+    pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -547,7 +551,15 @@ pub struct CardDetail {
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[derive(
-    Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema, strum::EnumString, strum::Display,
+    Debug,
+    serde::Deserialize,
+    serde::Serialize,
+    Clone,
+    ToSchema,
+    strum::EnumString,
+    strum::Display,
+    Eq,
+    PartialEq,
 )]
 #[serde(rename_all = "snake_case")]
 pub enum CardType {
diff --git a/crates/cards/src/lib.rs b/crates/cards/src/lib.rs
index 0c0fb9d47a1..765fa7c6f8c 100644
--- a/crates/cards/src/lib.rs
+++ b/crates/cards/src/lib.rs
@@ -7,7 +7,7 @@ use masking::{PeekInterface, StrongSecret};
 use serde::{de, Deserialize, Serialize};
 use time::{util::days_in_year_month, Date, Duration, PrimitiveDateTime, Time};
 
-pub use crate::validate::{CardNumber, CardNumberStrategy, CardNumberValidationErr};
+pub use crate::validate::{CardNumber, CardNumberStrategy, CardNumberValidationErr, NetworkToken};
 
 #[derive(Serialize)]
 pub struct CardSecurityCode(StrongSecret<u16>);
diff --git a/crates/cards/src/validate.rs b/crates/cards/src/validate.rs
index 725d05b4807..b8b9cdbf185 100644
--- a/crates/cards/src/validate.rs
+++ b/crates/cards/src/validate.rs
@@ -24,6 +24,10 @@ pub struct CardNumberValidationErr(&'static str);
 #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
 pub struct CardNumber(StrongSecret<String, CardNumberStrategy>);
 
+//Network Token
+#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
+pub struct NetworkToken(StrongSecret<String, CardNumberStrategy>);
+
 impl CardNumber {
     pub fn get_card_isin(&self) -> String {
         self.0.peek().chars().take(6).collect::<String>()
@@ -102,6 +106,30 @@ impl CardNumber {
     }
 }
 
+impl NetworkToken {
+    pub fn get_card_isin(&self) -> String {
+        self.0.peek().chars().take(6).collect::<String>()
+    }
+
+    pub fn get_extended_card_bin(&self) -> String {
+        self.0.peek().chars().take(8).collect::<String>()
+    }
+    pub fn get_card_no(&self) -> String {
+        self.0.peek().chars().collect::<String>()
+    }
+    pub fn get_last4(&self) -> String {
+        self.0
+            .peek()
+            .chars()
+            .rev()
+            .take(4)
+            .collect::<String>()
+            .chars()
+            .rev()
+            .collect::<String>()
+    }
+}
+
 impl FromStr for CardNumber {
     type Err = CardNumberValidationErr;
 
@@ -131,6 +159,35 @@ impl FromStr for CardNumber {
     }
 }
 
+impl FromStr for NetworkToken {
+    type Err = CardNumberValidationErr;
+
+    fn from_str(network_token: &str) -> Result<Self, Self::Err> {
+        // Valid test cards for threedsecureio
+        let valid_test_network_tokens = vec![
+            "4000100511112003",
+            "6000100611111203",
+            "3000100811111072",
+            "9000100111111111",
+        ];
+        #[cfg(not(target_arch = "wasm32"))]
+        let valid_test_network_tokens = match router_env_which() {
+            Env::Development | Env::Sandbox => valid_test_network_tokens,
+            Env::Production => vec![],
+        };
+
+        let network_token = network_token.split_whitespace().collect::<String>();
+
+        let is_network_token_valid = sanitize_card_number(&network_token)?;
+
+        if valid_test_network_tokens.contains(&network_token.as_str()) || is_network_token_valid {
+            Ok(Self(StrongSecret::new(network_token)))
+        } else {
+            Err(CardNumberValidationErr("network token invalid"))
+        }
+    }
+}
+
 pub fn sanitize_card_number(card_number: &str) -> Result<bool, CardNumberValidationErr> {
     let is_card_number_valid = Ok(card_number)
         .and_then(validate_card_number_chars)
@@ -195,6 +252,14 @@ impl TryFrom<String> for CardNumber {
     }
 }
 
+impl TryFrom<String> for NetworkToken {
+    type Error = CardNumberValidationErr;
+
+    fn try_from(value: String) -> Result<Self, Self::Error> {
+        Self::from_str(&value)
+    }
+}
+
 impl Deref for CardNumber {
     type Target = StrongSecret<String, CardNumberStrategy>;
 
@@ -203,6 +268,14 @@ impl Deref for CardNumber {
     }
 }
 
+impl Deref for NetworkToken {
+    type Target = StrongSecret<String, CardNumberStrategy>;
+
+    fn deref(&self) -> &StrongSecret<String, CardNumberStrategy> {
+        &self.0
+    }
+}
+
 impl<'de> Deserialize<'de> for CardNumber {
     fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
         let s = String::deserialize(d)?;
@@ -210,6 +283,13 @@ impl<'de> Deserialize<'de> for CardNumber {
     }
 }
 
+impl<'de> Deserialize<'de> for NetworkToken {
+    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
+        let s = String::deserialize(d)?;
+        Self::from_str(&s).map_err(serde::de::Error::custom)
+    }
+}
+
 pub enum CardNumberStrategy {}
 
 impl<T> Strategy<T> for CardNumberStrategy
diff --git a/crates/hyperswitch_connectors/Cargo.toml b/crates/hyperswitch_connectors/Cargo.toml
index 6b76e6ac195..13d5266dabd 100644
--- a/crates/hyperswitch_connectors/Cargo.toml
+++ b/crates/hyperswitch_connectors/Cargo.toml
@@ -9,6 +9,7 @@ license.workspace = true
 frm = ["hyperswitch_domain_models/frm", "hyperswitch_interfaces/frm"]
 payouts = ["hyperswitch_domain_models/payouts", "api_models/payouts", "hyperswitch_interfaces/payouts"]
 v1 = ["api_models/v1", "hyperswitch_domain_models/v1", "common_utils/v1"]
+v2 = ["api_models/v2", "hyperswitch_domain_models/v2", "common_utils/v2"]
 
 [dependencies]
 actix-http = "3.6.0"
diff --git a/crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs b/crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
index b42c02606c1..b953fa73754 100644
--- a/crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs
@@ -18,6 +18,7 @@ use hyperswitch_domain_models::{
     types::PayoutsRouterData,
 };
 use hyperswitch_domain_models::{
+    network_tokenization::NetworkTokenNumber,
     payment_method_data::{
         ApplePayWalletData, GooglePayWalletData, NetworkTokenData, PaymentMethodData,
         SamsungPayWalletData, WalletData,
@@ -430,7 +431,7 @@ pub struct CaptureOptions {
 #[derive(Debug, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct NetworkTokenizedCard {
-    number: cards::CardNumber,
+    number: NetworkTokenNumber,
     expiration_month: Secret<String>,
     expiration_year: Secret<String>,
     cryptogram: Option<Secret<String>>,
@@ -1400,10 +1401,10 @@ impl
         let payment_information =
             PaymentInformation::NetworkToken(Box::new(NetworkTokenPaymentInformation {
                 tokenized_card: NetworkTokenizedCard {
-                    number: token_data.token_number,
-                    expiration_month: token_data.token_exp_month,
-                    expiration_year: token_data.token_exp_year,
-                    cryptogram: token_data.token_cryptogram.clone(),
+                    number: token_data.get_network_token(),
+                    expiration_month: token_data.get_network_token_expiry_month(),
+                    expiration_year: token_data.get_network_token_expiry_year(),
+                    cryptogram: token_data.get_cryptogram().clone(),
                     transaction_type: "1".to_string(),
                 },
             }));
diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs
index aec4d31072d..741d87ac6a1 100644
--- a/crates/hyperswitch_connectors/src/utils.rs
+++ b/crates/hyperswitch_connectors/src/utils.rs
@@ -19,6 +19,7 @@ use common_utils::{
 use error_stack::{report, ResultExt};
 use hyperswitch_domain_models::{
     address::{Address, AddressDetails, PhoneDetails},
+    network_tokenization::NetworkTokenNumber,
     payment_method_data::{self, Card, CardDetailsForNetworkTransactionId, PaymentMethodData},
     router_data::{
         ApplePayPredecryptData, ErrorResponse, PaymentMethodToken, RecurringMandatePaymentData,
@@ -2922,13 +2923,24 @@ impl CardData for api_models::payouts::CardPayout {
 pub trait NetworkTokenData {
     fn get_card_issuer(&self) -> Result<CardIssuer, Error>;
     fn get_expiry_year_4_digit(&self) -> Secret<String>;
+    fn get_network_token(&self) -> NetworkTokenNumber;
+    fn get_network_token_expiry_month(&self) -> Secret<String>;
+    fn get_network_token_expiry_year(&self) -> Secret<String>;
+    fn get_cryptogram(&self) -> Option<Secret<String>>;
 }
 
 impl NetworkTokenData for payment_method_data::NetworkTokenData {
+    #[cfg(feature = "v1")]
     fn get_card_issuer(&self) -> Result<CardIssuer, Error> {
         get_card_issuer(self.token_number.peek())
     }
 
+    #[cfg(feature = "v2")]
+    fn get_card_issuer(&self) -> Result<CardIssuer, Error> {
+        get_card_issuer(self.network_token.peek())
+    }
+
+    #[cfg(feature = "v1")]
     fn get_expiry_year_4_digit(&self) -> Secret<String> {
         let mut year = self.token_exp_year.peek().clone();
         if year.len() == 2 {
@@ -2936,4 +2948,53 @@ impl NetworkTokenData for payment_method_data::NetworkTokenData {
         }
         Secret::new(year)
     }
+
+    #[cfg(feature = "v2")]
+    fn get_expiry_year_4_digit(&self) -> Secret<String> {
+        let mut year = self.network_token_exp_year.peek().clone();
+        if year.len() == 2 {
+            year = format!("20{}", year);
+        }
+        Secret::new(year)
+    }
+
+    #[cfg(feature = "v1")]
+    fn get_network_token(&self) -> NetworkTokenNumber {
+        self.token_number.clone()
+    }
+
+    #[cfg(feature = "v2")]
+    fn get_network_token(&self) -> NetworkTokenNumber {
+        self.network_token.clone()
+    }
+
+    #[cfg(feature = "v1")]
+    fn get_network_token_expiry_month(&self) -> Secret<String> {
+        self.token_exp_month.clone()
+    }
+
+    #[cfg(feature = "v2")]
+    fn get_network_token_expiry_month(&self) -> Secret<String> {
+        self.network_token_exp_month.clone()
+    }
+
+    #[cfg(feature = "v1")]
+    fn get_network_token_expiry_year(&self) -> Secret<String> {
+        self.token_exp_year.clone()
+    }
+
+    #[cfg(feature = "v2")]
+    fn get_network_token_expiry_year(&self) -> Secret<String> {
+        self.network_token_exp_year.clone()
+    }
+
+    #[cfg(feature = "v1")]
+    fn get_cryptogram(&self) -> Option<Secret<String>> {
+        self.token_cryptogram.clone()
+    }
+
+    #[cfg(feature = "v2")]
+    fn get_cryptogram(&self) -> Option<Secret<String>> {
+        self.cryptogram.clone()
+    }
 }
diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs
index bd6dd2e5371..c47353f282d 100644
--- a/crates/hyperswitch_domain_models/src/lib.rs
+++ b/crates/hyperswitch_domain_models/src/lib.rs
@@ -11,6 +11,7 @@ pub mod mandates;
 pub mod merchant_account;
 pub mod merchant_connector_account;
 pub mod merchant_key_store;
+pub mod network_tokenization;
 pub mod payment_address;
 pub mod payment_method_data;
 pub mod payment_methods;
diff --git a/crates/hyperswitch_domain_models/src/network_tokenization.rs b/crates/hyperswitch_domain_models/src/network_tokenization.rs
new file mode 100644
index 00000000000..bf87c750509
--- /dev/null
+++ b/crates/hyperswitch_domain_models/src/network_tokenization.rs
@@ -0,0 +1,231 @@
+use std::fmt::Debug;
+
+use api_models::enums as api_enums;
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+use cards::CardNumber;
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use cards::{CardNumber, NetworkToken};
+use common_utils::id_type;
+use masking::Secret;
+use serde::{Deserialize, Serialize};
+
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CardData {
+    pub card_number: CardNumber,
+    pub exp_month: Secret<String>,
+    pub exp_year: Secret<String>,
+    pub card_security_code: Secret<String>,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CardData {
+    pub card_number: CardNumber,
+    pub exp_month: Secret<String>,
+    pub exp_year: Secret<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub card_security_code: Option<Secret<String>>,
+}
+
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct OrderData {
+    pub consent_id: String,
+    pub customer_id: id_type::CustomerId,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct OrderData {
+    pub consent_id: String,
+    pub customer_id: id_type::GlobalCustomerId,
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ApiPayload {
+    pub service: String,
+    pub card_data: Secret<String>, //encrypted card data
+    pub order_data: OrderData,
+    pub key_id: String,
+    pub should_send_token: bool,
+}
+
+#[derive(Debug, Deserialize, Eq, PartialEq)]
+pub struct CardNetworkTokenResponse {
+    pub payload: Secret<String>, //encrypted payload
+}
+
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+#[derive(Debug, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CardNetworkTokenResponsePayload {
+    pub card_brand: api_enums::CardNetwork,
+    pub card_fingerprint: Option<Secret<String>>,
+    pub card_reference: String,
+    pub correlation_id: String,
+    pub customer_id: String,
+    pub par: String,
+    pub token: CardNumber,
+    pub token_expiry_month: Secret<String>,
+    pub token_expiry_year: Secret<String>,
+    pub token_isin: String,
+    pub token_last_four: String,
+    pub token_status: String,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, Clone, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct GenerateNetworkTokenResponsePayload {
+    pub card_brand: api_enums::CardNetwork,
+    pub card_fingerprint: Option<Secret<String>>,
+    pub card_reference: String,
+    pub correlation_id: String,
+    pub customer_id: String,
+    pub par: String,
+    pub token: NetworkToken,
+    pub token_expiry_month: Secret<String>,
+    pub token_expiry_year: Secret<String>,
+    pub token_isin: String,
+    pub token_last_four: String,
+    pub token_status: String,
+}
+
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+#[derive(Debug, Serialize)]
+pub struct GetCardToken {
+    pub card_reference: String,
+    pub customer_id: id_type::CustomerId,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, Serialize)]
+pub struct GetCardToken {
+    pub card_reference: String,
+    pub customer_id: id_type::GlobalCustomerId,
+}
+#[derive(Debug, Deserialize)]
+pub struct AuthenticationDetails {
+    pub cryptogram: Secret<String>,
+    pub token: CardNumber, //network token
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct TokenDetails {
+    pub exp_month: Secret<String>,
+    pub exp_year: Secret<String>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct TokenResponse {
+    pub authentication_details: AuthenticationDetails,
+    pub network: api_enums::CardNetwork,
+    pub token_details: TokenDetails,
+}
+
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+#[derive(Debug, Serialize, Deserialize)]
+pub struct DeleteCardToken {
+    pub card_reference: String, //network token requestor ref id
+    pub customer_id: id_type::CustomerId,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, Serialize, Deserialize)]
+pub struct DeleteCardToken {
+    pub card_reference: String, //network token requestor ref id
+    pub customer_id: id_type::GlobalCustomerId,
+}
+
+#[derive(Debug, Deserialize, Eq, PartialEq)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum DeleteNetworkTokenStatus {
+    Success,
+}
+
+#[derive(Debug, Deserialize, Eq, PartialEq)]
+pub struct NetworkTokenErrorInfo {
+    pub code: String,
+    pub developer_message: String,
+}
+
+#[derive(Debug, Deserialize, Eq, PartialEq)]
+pub struct NetworkTokenErrorResponse {
+    pub error_message: String,
+    pub error_info: NetworkTokenErrorInfo,
+}
+
+#[derive(Debug, Deserialize, Eq, PartialEq)]
+pub struct DeleteNetworkTokenResponse {
+    pub status: DeleteNetworkTokenStatus,
+}
+
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+#[derive(Debug, Serialize, Deserialize)]
+pub struct CheckTokenStatus {
+    pub card_reference: String,
+    pub customer_id: id_type::CustomerId,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, Serialize, Deserialize)]
+pub struct CheckTokenStatus {
+    pub card_reference: String,
+    pub customer_id: id_type::GlobalCustomerId,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum TokenStatus {
+    Active,
+    Inactive,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CheckTokenStatusResponsePayload {
+    pub token_expiry_month: Secret<String>,
+    pub token_expiry_year: Secret<String>,
+    pub token_status: TokenStatus,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct CheckTokenStatusResponse {
+    pub payload: CheckTokenStatusResponsePayload,
+}
+
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+pub type NetworkTokenNumber = CardNumber;
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub type NetworkTokenNumber = NetworkToken;
diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs
index e96368080d9..2f8375b47c0 100644
--- a/crates/hyperswitch_domain_models/src/payment_method_data.rs
+++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs
@@ -1,5 +1,6 @@
 use api_models::{
-    mandates, payment_methods,
+    mandates,
+    payment_methods::{self},
     payments::{
         additional_info as payment_additional_types, AmazonPayRedirectData, ExtendedCardInfo,
     },
@@ -587,6 +588,10 @@ pub struct SepaAndBacsBillingDetails {
     pub name: Secret<String>,
 }
 
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
 pub struct NetworkTokenData {
     pub token_number: cards::CardNumber,
@@ -602,6 +607,37 @@ pub struct NetworkTokenData {
     pub eci: Option<String>,
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
+pub struct NetworkTokenData {
+    pub network_token: cards::NetworkToken,
+    pub network_token_exp_month: Secret<String>,
+    pub network_token_exp_year: Secret<String>,
+    pub cryptogram: Option<Secret<String>>,
+    pub card_issuer: Option<String>, //since network token is tied to card, so its issuer will be same as card issuer
+    pub card_network: Option<common_enums::CardNetwork>,
+    pub card_type: Option<payment_methods::CardType>,
+    pub card_issuing_country: Option<String>,
+    pub bank_code: Option<String>,
+    pub card_holder_name: Option<Secret<String>>,
+    pub nick_name: Option<Secret<String>>,
+    pub eci: Option<String>,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
+pub struct NetworkTokenDetails {
+    pub network_token: cards::NetworkToken,
+    pub network_token_exp_month: Secret<String>,
+    pub network_token_exp_year: Secret<String>,
+    pub card_issuer: Option<String>, //since network token is tied to card, so its issuer will be same as card issuer
+    pub card_network: Option<common_enums::CardNetwork>,
+    pub card_type: Option<payment_methods::CardType>,
+    pub card_issuing_country: Option<api_enums::CountryAlpha2>,
+    pub card_holder_name: Option<Secret<String>>,
+    pub nick_name: Option<Secret<String>>,
+}
+
 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum MobilePaymentData {
@@ -1726,3 +1762,85 @@ impl From<GooglePayWalletData> for payment_methods::PaymentMethodDataWalletInfo
         }
     }
 }
+
+#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub enum PaymentMethodsData {
+    Card(CardDetailsPaymentMethod),
+    BankDetails(payment_methods::PaymentMethodDataBankCreds), //PaymentMethodDataBankCreds and its transformations should be moved to the domain models
+    WalletDetails(payment_methods::PaymentMethodDataWalletInfo), //PaymentMethodDataWalletInfo and its transformations should be moved to the domain models
+    NetworkToken(NetworkTokenDetailsPaymentMethod),
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub struct NetworkTokenDetailsPaymentMethod {
+    pub last4_digits: Option<String>,
+    pub issuer_country: Option<String>,
+    pub network_token_expiry_month: Option<Secret<String>>,
+    pub network_token_expiry_year: Option<Secret<String>>,
+    pub nick_name: Option<Secret<String>>,
+    pub card_holder_name: Option<Secret<String>>,
+    pub card_isin: Option<String>,
+    pub card_issuer: Option<String>,
+    pub card_network: Option<api_enums::CardNetwork>,
+    pub card_type: Option<String>,
+    #[serde(default = "saved_in_locker_default")]
+    pub saved_to_locker: bool,
+}
+
+fn saved_in_locker_default() -> bool {
+    true
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub struct CardDetailsPaymentMethod {
+    pub last4_digits: Option<String>,
+    pub issuer_country: Option<String>,
+    pub expiry_month: Option<Secret<String>>,
+    pub expiry_year: Option<Secret<String>>,
+    pub nick_name: Option<Secret<String>>,
+    pub card_holder_name: Option<Secret<String>>,
+    pub card_isin: Option<String>,
+    pub card_issuer: Option<String>,
+    pub card_network: Option<api_enums::CardNetwork>,
+    pub card_type: Option<String>,
+    #[serde(default = "saved_in_locker_default")]
+    pub saved_to_locker: bool,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+impl From<payment_methods::CardDetail> for CardDetailsPaymentMethod {
+    fn from(item: payment_methods::CardDetail) -> Self {
+        Self {
+            issuer_country: item.card_issuing_country.map(|c| c.to_string()),
+            last4_digits: Some(item.card_number.get_last4()),
+            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,
+        }
+    }
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+impl From<NetworkTokenDetails> for NetworkTokenDetailsPaymentMethod {
+    fn from(item: NetworkTokenDetails) -> Self {
+        Self {
+            issuer_country: item.card_issuing_country.map(|c| c.to_string()),
+            last4_digits: Some(item.network_token.get_last4()),
+            network_token_expiry_month: Some(item.network_token_exp_month),
+            network_token_expiry_year: Some(item.network_token_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,
+        }
+    }
+}
diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs
index 0c90b0d0244..e3a8264217c 100644
--- a/crates/hyperswitch_domain_models/src/router_data.rs
+++ b/crates/hyperswitch_domain_models/src/router_data.rs
@@ -9,7 +9,10 @@ use common_utils::{
 use error_stack::ResultExt;
 use masking::{ExposeInterface, Secret};
 
-use crate::{payment_address::PaymentAddress, payment_method_data, payments};
+use crate::{
+    network_tokenization::NetworkTokenNumber, payment_address::PaymentAddress, payment_method_data,
+    payments,
+};
 #[cfg(feature = "v2")]
 use crate::{
     payments::{
@@ -294,7 +297,7 @@ pub struct PazeDecryptedData {
 #[derive(Debug, Clone, serde::Deserialize)]
 #[serde(rename_all = "camelCase")]
 pub struct PazeToken {
-    pub payment_token: cards::CardNumber,
+    pub payment_token: NetworkTokenNumber,
     pub token_expiration_month: Secret<String>,
     pub token_expiration_year: Secret<String>,
     pub payment_account_reference: Secret<String>,
diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml
index 6257d3e0832..d590797d642 100644
--- a/crates/router/Cargo.toml
+++ b/crates/router/Cargo.toml
@@ -33,8 +33,8 @@ payouts = ["api_models/payouts", "common_enums/payouts", "hyperswitch_connectors
 payout_retry = ["payouts"]
 recon = ["email", "api_models/recon"]
 retry = []
-v2 = ["customer_v2", "payment_methods_v2", "common_default", "api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "storage_impl/v2", "kgraph_utils/v2", "common_utils/v2"]
-v1 = ["common_default", "api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1", "hyperswitch_interfaces/v1", "kgraph_utils/v1", "common_utils/v1"]
+v2 = ["customer_v2", "payment_methods_v2", "common_default", "api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "storage_impl/v2", "kgraph_utils/v2", "common_utils/v2", "hyperswitch_connectors/v2"]
+v1 = ["common_default", "api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1", "hyperswitch_interfaces/v1", "kgraph_utils/v1", "common_utils/v1", "hyperswitch_connectors/v1"]
 customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2", "hyperswitch_domain_models/customer_v2", "storage_impl/customer_v2"]
 payment_methods_v2 = ["api_models/payment_methods_v2", "diesel_models/payment_methods_v2", "hyperswitch_domain_models/payment_methods_v2", "storage_impl/payment_methods_v2", "common_utils/payment_methods_v2"]
 dynamic_routing = ["external_services/dynamic_routing", "storage_impl/dynamic_routing", "api_models/dynamic_routing"]
diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs
index 69749500dab..a7e4e0f61d3 100644
--- a/crates/router/src/connector/adyen/transformers.rs
+++ b/crates/router/src/connector/adyen/transformers.rs
@@ -4,7 +4,9 @@ use api_models::{enums, payments, webhooks};
 use cards::CardNumber;
 use common_utils::{errors::ParsingError, ext_traits::Encode, id_type, pii, types::MinorUnit};
 use error_stack::{report, ResultExt};
-use hyperswitch_domain_models::router_request_types::SubmitEvidenceRequestData;
+use hyperswitch_domain_models::{
+    network_tokenization::NetworkTokenNumber, router_request_types::SubmitEvidenceRequestData,
+};
 use masking::{ExposeInterface, PeekInterface};
 use reqwest::Url;
 use serde::{Deserialize, Serialize};
@@ -640,6 +642,7 @@ pub enum AdyenPaymentMethod<'a> {
     PayEasy(Box<JCSVoucherData>),
     Pix(Box<PmdForPaymentType>),
     NetworkToken(Box<AdyenNetworkTokenData>),
+    AdyenPaze(Box<AdyenPazeData>),
 }
 
 #[derive(Debug, Clone, Serialize)]
@@ -1145,6 +1148,21 @@ pub struct AdyenCard {
     network_payment_reference: Option<Secret<String>>,
 }
 
+#[serde_with::skip_serializing_none]
+#[derive(Debug, Clone, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct AdyenPazeData {
+    #[serde(rename = "type")]
+    payment_type: PaymentType,
+    number: NetworkTokenNumber,
+    expiry_month: Secret<String>,
+    expiry_year: Secret<String>,
+    cvc: Option<Secret<String>>,
+    holder_name: Option<Secret<String>>,
+    brand: Option<CardBrand>, //Mandatory for mandate using network_txns_id
+    network_payment_reference: Option<Secret<String>>,
+}
+
 #[derive(Debug, Clone, Serialize, Deserialize)]
 #[serde(rename_all = "lowercase")]
 pub enum CardBrand {
@@ -1244,7 +1262,7 @@ pub struct AdyenApplePay {
 pub struct AdyenNetworkTokenData {
     #[serde(rename = "type")]
     payment_type: PaymentType,
-    number: CardNumber,
+    number: NetworkTokenNumber,
     expiry_month: Secret<String>,
     expiry_year: Secret<String>,
     holder_name: Option<Secret<String>>,
@@ -2208,7 +2226,7 @@ impl TryFrom<(&domain::WalletData, &types::PaymentsAuthorizeRouterData)>
             }
             domain::WalletData::Paze(_) => match item.payment_method_token.clone() {
                 Some(types::PaymentMethodToken::PazeDecrypt(paze_decrypted_data)) => {
-                    let data = AdyenCard {
+                    let data = AdyenPazeData {
                         payment_type: PaymentType::NetworkToken,
                         number: paze_decrypted_data.token.payment_token,
                         expiry_month: paze_decrypted_data.token.token_expiration_month,
@@ -2222,7 +2240,7 @@ impl TryFrom<(&domain::WalletData, &types::PaymentsAuthorizeRouterData)>
                             .and_then(get_adyen_card_network),
                         network_payment_reference: None,
                     };
-                    Ok(AdyenPaymentMethod::AdyenCard(Box::new(data)))
+                    Ok(AdyenPaymentMethod::AdyenPaze(Box::new(data)))
                 }
                 _ => Err(errors::ConnectorError::NotImplemented(
                     utils::get_unimplemented_payment_method_error_message("Cybersource"),
@@ -2737,8 +2755,8 @@ impl
                         let card_holder_name = item.router_data.get_optional_billing_full_name();
                         let adyen_network_token = AdyenNetworkTokenData {
                             payment_type: PaymentType::NetworkToken,
-                            number: token_data.token_number.clone(),
-                            expiry_month: token_data.token_exp_month.clone(),
+                            number: token_data.get_network_token(),
+                            expiry_month: token_data.get_network_token_expiry_month(),
                             expiry_year: token_data.get_expiry_year_4_digit(),
                             holder_name: card_holder_name,
                             brand: Some(brand), // FIXME: Remove hardcoding
@@ -5600,8 +5618,8 @@ impl TryFrom<(&domain::NetworkTokenData, Option<Secret<String>>)> for AdyenPayme
     ) -> Result<Self, Self::Error> {
         let adyen_network_token = AdyenNetworkTokenData {
             payment_type: PaymentType::NetworkToken,
-            number: token_data.token_number.clone(),
-            expiry_month: token_data.token_exp_month.clone(),
+            number: token_data.get_network_token(),
+            expiry_month: token_data.get_network_token_expiry_month(),
             expiry_year: token_data.get_expiry_year_4_digit(),
             holder_name: card_holder_name,
             brand: None, // FIXME: Remove hardcoding
@@ -5650,7 +5668,7 @@ impl
             directory_response: "Y".to_string(),
             authentication_response: "Y".to_string(),
             token_authentication_verification_value: token_data
-                .token_cryptogram
+                .get_cryptogram()
                 .clone()
                 .unwrap_or_default(),
             eci: Some("02".to_string()),
diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs
index 28f5d016e5a..0aca263b5c7 100644
--- a/crates/router/src/connector/utils.rs
+++ b/crates/router/src/connector/utils.rs
@@ -22,6 +22,7 @@ use diesel_models::{enums, types::OrderDetailsWithAmount};
 use error_stack::{report, ResultExt};
 use hyperswitch_domain_models::{
     mandates,
+    network_tokenization::NetworkTokenNumber,
     payments::payment_attempt::PaymentAttempt,
     router_request_types::{
         AuthoriseIntegrityObject, CaptureIntegrityObject, RefundIntegrityObject,
@@ -3181,13 +3182,30 @@ pub fn get_refund_integrity_object<T>(
 pub trait NetworkTokenData {
     fn get_card_issuer(&self) -> Result<CardIssuer, Error>;
     fn get_expiry_year_4_digit(&self) -> Secret<String>;
+    fn get_network_token(&self) -> NetworkTokenNumber;
+    fn get_network_token_expiry_month(&self) -> Secret<String>;
+    fn get_network_token_expiry_year(&self) -> Secret<String>;
+    fn get_cryptogram(&self) -> Option<Secret<String>>;
 }
 
 impl NetworkTokenData for domain::NetworkTokenData {
+    #[cfg(all(
+        any(feature = "v1", feature = "v2"),
+        not(feature = "payment_methods_v2")
+    ))]
     fn get_card_issuer(&self) -> Result<CardIssuer, Error> {
         get_card_issuer(self.token_number.peek())
     }
 
+    #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+    fn get_card_issuer(&self) -> Result<CardIssuer, Error> {
+        get_card_issuer(self.network_token.peek())
+    }
+
+    #[cfg(all(
+        any(feature = "v1", feature = "v2"),
+        not(feature = "payment_methods_v2")
+    ))]
     fn get_expiry_year_4_digit(&self) -> Secret<String> {
         let mut year = self.token_exp_year.peek().clone();
         if year.len() == 2 {
@@ -3195,6 +3213,67 @@ impl NetworkTokenData for domain::NetworkTokenData {
         }
         Secret::new(year)
     }
+
+    #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+    fn get_expiry_year_4_digit(&self) -> Secret<String> {
+        let mut year = self.network_token_exp_year.peek().clone();
+        if year.len() == 2 {
+            year = format!("20{}", year);
+        }
+        Secret::new(year)
+    }
+
+    #[cfg(all(
+        any(feature = "v1", feature = "v2"),
+        not(feature = "payment_methods_v2")
+    ))]
+    fn get_network_token(&self) -> NetworkTokenNumber {
+        self.token_number.clone()
+    }
+
+    #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+    fn get_network_token(&self) -> NetworkTokenNumber {
+        self.network_token.clone()
+    }
+
+    #[cfg(all(
+        any(feature = "v1", feature = "v2"),
+        not(feature = "payment_methods_v2")
+    ))]
+    fn get_network_token_expiry_month(&self) -> Secret<String> {
+        self.token_exp_month.clone()
+    }
+
+    #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+    fn get_network_token_expiry_month(&self) -> Secret<String> {
+        self.network_token_exp_month.clone()
+    }
+
+    #[cfg(all(
+        any(feature = "v1", feature = "v2"),
+        not(feature = "payment_methods_v2")
+    ))]
+    fn get_network_token_expiry_year(&self) -> Secret<String> {
+        self.token_exp_year.clone()
+    }
+
+    #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+    fn get_network_token_expiry_year(&self) -> Secret<String> {
+        self.network_token_exp_year.clone()
+    }
+
+    #[cfg(all(
+        any(feature = "v1", feature = "v2"),
+        not(feature = "payment_methods_v2")
+    ))]
+    fn get_cryptogram(&self) -> Option<Secret<String>> {
+        self.token_cryptogram.clone()
+    }
+
+    #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+    fn get_cryptogram(&self) -> Option<Secret<String>> {
+        self.cryptogram.clone()
+    }
 }
 
 pub fn convert_uppercase<'de, D, T>(v: D) -> Result<T, D::Error>
diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs
index 54cae42ceb3..82d05956fc8 100644
--- a/crates/router/src/core/errors.rs
+++ b/crates/router/src/core/errors.rs
@@ -444,4 +444,6 @@ pub enum NetworkTokenizationError {
     DeleteNetworkTokenFailed,
     #[error("Network token service not configured")]
     NetworkTokenizationServiceNotConfigured,
+    #[error("Failed while calling Network Token Service API")]
+    ApiError,
 }
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 5bdb0f0819e..6ebc7bde5e4 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -47,9 +47,9 @@ use hyperswitch_domain_models::api::{GenericLinks, GenericLinksData};
     feature = "customer_v2"
 ))]
 use hyperswitch_domain_models::mandates::CommonMandateReference;
-use hyperswitch_domain_models::payments::{payment_attempt::PaymentAttempt, PaymentIntent};
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-use masking::ExposeInterface;
+use hyperswitch_domain_models::payment_method_data;
+use hyperswitch_domain_models::payments::{payment_attempt::PaymentAttempt, PaymentIntent};
 use masking::{PeekInterface, Secret};
 use router_env::{instrument, tracing};
 use time::Duration;
@@ -737,6 +737,7 @@ pub(crate) async fn get_payment_method_create_request(
                             card_detail,
                         ),
                         billing: None,
+                        network_tokenization: None,
                     };
                     Ok(payment_method_request)
                 }
@@ -853,6 +854,7 @@ pub async fn create_payment_method(
     req: api::PaymentMethodCreate,
     merchant_account: &domain::MerchantAccount,
     key_store: &domain::MerchantKeyStore,
+    profile: &domain::Profile,
 ) -> RouterResponse<api::PaymentMethodResponse> {
     use common_utils::ext_traits::ValueExt;
 
@@ -910,6 +912,9 @@ pub async fn create_payment_method(
 
     let payment_method_data = pm_types::PaymentMethodVaultingData::from(req.payment_method_data);
 
+    let payment_method_data =
+        populate_bin_details_for_payment_method(state, &payment_method_data).await;
+
     let vaulting_result = vault_payment_method(
         state,
         &payment_method_data,
@@ -919,6 +924,25 @@ pub async fn create_payment_method(
     )
     .await;
 
+    let network_tokenization_resp = network_tokenize_and_vault_the_pmd(
+        state,
+        &payment_method_data,
+        merchant_account,
+        key_store,
+        req.network_tokenization,
+        profile.is_network_tokenization_enabled,
+        &customer_id,
+    )
+    .await
+    .map_err(|e| {
+        services::logger::error!(
+            "Failed to network tokenize the payment method for customer: {}. Error: {} ",
+            customer_id.get_string_repr(),
+            e
+        );
+    })
+    .ok();
+
     let response = match vaulting_result {
         Ok((vaulting_resp, fingerprint_id)) => {
             let pm_update = create_pm_additional_data_update(
@@ -929,6 +953,7 @@ pub async fn create_payment_method(
                 Some(req.payment_method_type),
                 Some(req.payment_method_subtype),
                 Some(fingerprint_id),
+                network_tokenization_resp,
             )
             .await
             .attach_printable("Unable to create Payment method data")?;
@@ -972,6 +997,145 @@ pub async fn create_payment_method(
     Ok(services::ApplicationResponse::Json(response))
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Clone, Debug)]
+pub struct NetworkTokenPaymentMethodDetails {
+    network_token_requestor_reference_id: String,
+    network_token_locker_id: String,
+    network_token_pmd: Encryptable<Secret<serde_json::Value>>,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub async fn network_tokenize_and_vault_the_pmd(
+    state: &SessionState,
+    payment_method_data: &pm_types::PaymentMethodVaultingData,
+    merchant_account: &domain::MerchantAccount,
+    key_store: &domain::MerchantKeyStore,
+    network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
+    network_tokenization_enabled_for_profile: bool,
+    customer_id: &id_type::GlobalCustomerId,
+) -> RouterResult<NetworkTokenPaymentMethodDetails> {
+    when(!network_tokenization_enabled_for_profile, || {
+        Err(report!(errors::ApiErrorResponse::NotSupported {
+            message: "Network Tokenization is not enabled for this payment method".to_string()
+        }))
+    })?;
+
+    let is_network_tokenization_enabled_for_pm = network_tokenization
+        .as_ref()
+        .map(|nt| matches!(nt.enable, common_enums::NetworkTokenizationToggle::Enable))
+        .unwrap_or(false);
+
+    let card_data = match payment_method_data {
+        pm_types::PaymentMethodVaultingData::Card(data)
+            if is_network_tokenization_enabled_for_pm =>
+        {
+            Ok(data)
+        }
+        _ => Err(report!(errors::ApiErrorResponse::NotSupported {
+            message: "Network Tokenization is not supported for this payment method".to_string()
+        })),
+    }?;
+
+    let (resp, network_token_req_ref_id) =
+        network_tokenization::make_card_network_tokenization_request(state, card_data, customer_id)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to generate network token")?;
+
+    let network_token_vaulting_data = pm_types::PaymentMethodVaultingData::NetworkToken(resp);
+    let vaulting_resp = vault::add_payment_method_to_vault(
+        state,
+        merchant_account,
+        &network_token_vaulting_data,
+        None,
+    )
+    .await
+    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .attach_printable("Failed to vault the network token data")?;
+
+    let key_manager_state = &(state).into();
+    let network_token = match network_token_vaulting_data {
+        pm_types::PaymentMethodVaultingData::Card(card) => {
+            payment_method_data::PaymentMethodsData::Card(
+                payment_method_data::CardDetailsPaymentMethod::from(card.clone()),
+            )
+        }
+        pm_types::PaymentMethodVaultingData::NetworkToken(network_token) => {
+            payment_method_data::PaymentMethodsData::NetworkToken(
+                payment_method_data::NetworkTokenDetailsPaymentMethod::from(network_token.clone()),
+            )
+        }
+    };
+
+    let network_token_pmd =
+        cards::create_encrypted_data(key_manager_state, key_store, network_token)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Unable to encrypt Payment method data")?;
+
+    Ok(NetworkTokenPaymentMethodDetails {
+        network_token_requestor_reference_id: network_token_req_ref_id,
+        network_token_locker_id: vaulting_resp.vault_id.get_string_repr().clone(),
+        network_token_pmd,
+    })
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub async fn populate_bin_details_for_payment_method(
+    state: &SessionState,
+    payment_method_data: &pm_types::PaymentMethodVaultingData,
+) -> pm_types::PaymentMethodVaultingData {
+    match payment_method_data {
+        pm_types::PaymentMethodVaultingData::Card(card) => {
+            let card_isin = card.card_number.get_card_isin();
+
+            if card.card_issuer.is_some()
+                && card.card_network.is_some()
+                && card.card_type.is_some()
+                && card.card_issuing_country.is_some()
+            {
+                pm_types::PaymentMethodVaultingData::Card(card.clone())
+            } else {
+                let card_info = state
+                    .store
+                    .get_card_info(&card_isin)
+                    .await
+                    .map_err(|error| services::logger::error!(card_info_error=?error))
+                    .ok()
+                    .flatten();
+
+                pm_types::PaymentMethodVaultingData::Card(payment_methods::CardDetail {
+                    card_number: card.card_number.clone(),
+                    card_exp_month: card.card_exp_month.clone(),
+                    card_exp_year: card.card_exp_year.clone(),
+                    card_holder_name: card.card_holder_name.clone(),
+                    nick_name: card.nick_name.clone(),
+                    card_issuing_country: card_info.as_ref().and_then(|val| {
+                        val.card_issuing_country
+                            .as_ref()
+                            .map(|c| api_enums::CountryAlpha2::from_str(c))
+                            .transpose()
+                            .ok()
+                            .flatten()
+                    }),
+                    card_network: card_info.as_ref().and_then(|val| val.card_network.clone()),
+                    card_issuer: card_info.as_ref().and_then(|val| val.card_issuer.clone()),
+                    card_type: card_info.as_ref().and_then(|val| {
+                        val.card_type
+                            .as_ref()
+                            .map(|c| payment_methods::CardType::from_str(c))
+                            .transpose()
+                            .ok()
+                            .flatten()
+                    }),
+                })
+            }
+        }
+        _ => payment_method_data.clone(),
+    }
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[instrument(skip_all)]
 pub async fn payment_method_intent_create(
@@ -1293,6 +1457,7 @@ pub async fn create_payment_method_for_intent(
     Ok(response)
 }
 
+#[allow(clippy::too_many_arguments)]
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 pub async fn create_pm_additional_data_update(
     pmd: &pm_types::PaymentMethodVaultingData,
@@ -1302,10 +1467,18 @@ pub async fn create_pm_additional_data_update(
     payment_method_type: Option<api_enums::PaymentMethod>,
     payment_method_subtype: Option<api_enums::PaymentMethodType>,
     vault_fingerprint_id: Option<String>,
+    nt_data: Option<NetworkTokenPaymentMethodDetails>,
 ) -> RouterResult<storage::PaymentMethodUpdate> {
     let card = match pmd {
         pm_types::PaymentMethodVaultingData::Card(card) => {
-            api::PaymentMethodsData::Card(card.clone().into())
+            payment_method_data::PaymentMethodsData::Card(
+                payment_method_data::CardDetailsPaymentMethod::from(card.clone()),
+            )
+        }
+        pm_types::PaymentMethodVaultingData::NetworkToken(network_token) => {
+            payment_method_data::PaymentMethodsData::NetworkToken(
+                payment_method_data::NetworkTokenDetailsPaymentMethod::from(network_token.clone()),
+            )
         }
     };
     let key_manager_state = &(state).into();
@@ -1321,9 +1494,11 @@ pub async fn create_pm_additional_data_update(
         payment_method_type_v2: payment_method_type,
         payment_method_subtype,
         payment_method_data: Some(pmd.into()),
-        network_token_requestor_reference_id: None,
-        network_token_locker_id: None,
-        network_token_payment_method_data: None,
+        network_token_requestor_reference_id: nt_data
+            .clone()
+            .map(|data| data.network_token_requestor_reference_id),
+        network_token_locker_id: nt_data.clone().map(|data| data.network_token_locker_id),
+        network_token_payment_method_data: nt_data.map(|data| data.network_token_pmd.into()),
         locker_fingerprint_id: vault_fingerprint_id,
     };
 
@@ -1633,6 +1808,7 @@ pub async fn update_payment_method_core(
         payment_method.get_payment_method_type(),
         payment_method.get_payment_method_subtype(),
         Some(fingerprint_id),
+        None,
     )
     .await
     .attach_printable("Unable to create Payment method data")?;
diff --git a/crates/router/src/core/payment_methods/network_tokenization.rs b/crates/router/src/core/payment_methods/network_tokenization.rs
index bb730caad2b..6799a1cf5ba 100644
--- a/crates/router/src/core/payment_methods/network_tokenization.rs
+++ b/crates/router/src/core/payment_methods/network_tokenization.rs
@@ -1,7 +1,9 @@
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use std::fmt::Debug;
 
-use api_models::{enums as api_enums, payment_methods::PaymentMethodsData};
-use cards::CardNumber;
+use api_models::payment_methods as api_payment_methods;
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use cards::{CardNumber, NetworkToken};
 use common_utils::{
     errors::CustomResult,
     ext_traits::{BytesExt, Encode},
@@ -9,10 +11,17 @@ use common_utils::{
     metrics::utils::record_operation_time,
     request::RequestContent,
 };
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 use error_stack::ResultExt;
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use error_stack::{report, ResultExt};
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use hyperswitch_domain_models::payment_method_data::NetworkTokenDetails;
 use josekit::jwe;
 use masking::{ExposeInterface, Mask, PeekInterface, Secret};
-use serde::{Deserialize, Serialize};
 
 use super::transformers::DeleteCardResp;
 use crate::{
@@ -24,142 +33,132 @@ use crate::{
     types::{api, domain},
 };
 
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct CardData {
-    card_number: CardNumber,
-    exp_month: Secret<String>,
-    exp_year: Secret<String>,
-    card_security_code: Secret<String>,
-}
+pub const NETWORK_TOKEN_SERVICE: &str = "NETWORK_TOKEN";
 
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct OrderData {
-    consent_id: String,
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
+pub async fn mk_tokenization_req(
+    state: &routes::SessionState,
+    payload_bytes: &[u8],
     customer_id: id_type::CustomerId,
-}
-
-#[derive(Debug, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub struct ApiPayload {
-    service: String,
-    card_data: Secret<String>, //encrypted card data
-    order_data: OrderData,
-    key_id: String,
-    should_send_token: bool,
-}
-
-#[derive(Debug, Deserialize, Eq, PartialEq)]
-pub struct CardNetworkTokenResponse {
-    payload: Secret<String>, //encrypted payload
-}
+    tokenization_service: &settings::NetworkTokenizationService,
+) -> CustomResult<
+    (domain::CardNetworkTokenResponsePayload, Option<String>),
+    errors::NetworkTokenizationError,
+> {
+    let enc_key = tokenization_service.public_key.peek().clone();
 
-#[derive(Debug, Clone, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct CardNetworkTokenResponsePayload {
-    pub card_brand: api_enums::CardNetwork,
-    pub card_fingerprint: Option<Secret<String>>,
-    pub card_reference: String,
-    pub correlation_id: String,
-    pub customer_id: String,
-    pub par: String,
-    pub token: CardNumber,
-    pub token_expiry_month: Secret<String>,
-    pub token_expiry_year: Secret<String>,
-    pub token_isin: String,
-    pub token_last_four: String,
-    pub token_status: String,
-}
+    let key_id = tokenization_service.key_id.clone();
 
-#[derive(Debug, Serialize)]
-pub struct GetCardToken {
-    card_reference: String,
-    customer_id: id_type::CustomerId,
-}
-#[derive(Debug, Deserialize)]
-pub struct AuthenticationDetails {
-    cryptogram: Secret<String>,
-    token: CardNumber, //network token
-}
+    let jwt = encryption::encrypt_jwe(
+        payload_bytes,
+        enc_key,
+        services::EncryptionAlgorithm::A128GCM,
+        Some(key_id.as_str()),
+    )
+    .await
+    .change_context(errors::NetworkTokenizationError::SaveNetworkTokenFailed)
+    .attach_printable("Error on jwe encrypt")?;
 
-#[derive(Debug, Serialize, Deserialize)]
-pub struct TokenDetails {
-    exp_month: Secret<String>,
-    exp_year: Secret<String>,
-}
+    let order_data = domain::OrderData {
+        consent_id: uuid::Uuid::new_v4().to_string(),
+        customer_id,
+    };
 
-#[derive(Debug, Deserialize)]
-pub struct TokenResponse {
-    authentication_details: AuthenticationDetails,
-    network: api_enums::CardNetwork,
-    token_details: TokenDetails,
-}
+    let api_payload = domain::ApiPayload {
+        service: NETWORK_TOKEN_SERVICE.to_string(),
+        card_data: Secret::new(jwt),
+        order_data,
+        key_id,
+        should_send_token: true,
+    };
 
-#[derive(Debug, Serialize, Deserialize)]
-pub struct DeleteCardToken {
-    card_reference: String, //network token requestor ref id
-    customer_id: id_type::CustomerId,
-}
+    let mut request = services::Request::new(
+        services::Method::Post,
+        tokenization_service.generate_token_url.as_str(),
+    );
+    request.add_header(headers::CONTENT_TYPE, "application/json".into());
+    request.add_header(
+        headers::AUTHORIZATION,
+        tokenization_service
+            .token_service_api_key
+            .peek()
+            .clone()
+            .into_masked(),
+    );
+    request.add_default_headers();
 
-#[derive(Debug, Deserialize, Eq, PartialEq)]
-#[serde(rename_all = "UPPERCASE")]
-pub enum DeleteNetworkTokenStatus {
-    Success,
-}
+    request.set_body(RequestContent::Json(Box::new(api_payload)));
 
-#[derive(Debug, Deserialize, Eq, PartialEq)]
-pub struct NetworkTokenErrorInfo {
-    code: String,
-    developer_message: String,
-}
+    logger::info!("Request to generate token: {:?}", request);
 
-#[derive(Debug, Deserialize, Eq, PartialEq)]
-pub struct NetworkTokenErrorResponse {
-    error_message: String,
-    error_info: NetworkTokenErrorInfo,
-}
+    let response = services::call_connector_api(state, request, "generate_token")
+        .await
+        .change_context(errors::NetworkTokenizationError::ApiError);
 
-#[derive(Debug, Deserialize, Eq, PartialEq)]
-pub struct DeleteNetworkTokenResponse {
-    status: DeleteNetworkTokenStatus,
-}
+    let res = response
+        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)
+        .attach_printable("Error while receiving response")
+        .and_then(|inner| match inner {
+            Err(err_res) => {
+                let parsed_error: domain::NetworkTokenErrorResponse = err_res
+                    .response
+                    .parse_struct("Card Network Tokenization Response")
+                    .change_context(
+                        errors::NetworkTokenizationError::ResponseDeserializationFailed,
+                    )?;
+                logger::error!(
+                    error_code = %parsed_error.error_info.code,
+                    developer_message = %parsed_error.error_info.developer_message,
+                    "Network tokenization error: {}",
+                    parsed_error.error_message
+                );
+                Err(errors::NetworkTokenizationError::ResponseDeserializationFailed)
+                    .attach_printable(format!("Response Deserialization Failed: {err_res:?}"))
+            }
+            Ok(res) => Ok(res),
+        })
+        .inspect_err(|err| {
+            logger::error!("Error while deserializing response: {:?}", err);
+        })?;
 
-#[derive(Debug, Serialize, Deserialize)]
-pub struct CheckTokenStatus {
-    card_reference: String,
-    customer_id: id_type::CustomerId,
-}
+    let network_response: domain::CardNetworkTokenResponse = res
+        .response
+        .parse_struct("Card Network Tokenization Response")
+        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;
 
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "UPPERCASE")]
-pub enum TokenStatus {
-    Active,
-    Inactive,
-}
+    let dec_key = tokenization_service.private_key.peek().clone();
 
-#[derive(Debug, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct CheckTokenStatusResponsePayload {
-    token_expiry_month: Secret<String>,
-    token_expiry_year: Secret<String>,
-    token_status: TokenStatus,
-}
+    let card_network_token_response = services::decrypt_jwe(
+        network_response.payload.peek(),
+        services::KeyIdCheck::SkipKeyIdCheck,
+        dec_key,
+        jwe::RSA_OAEP_256,
+    )
+    .await
+    .change_context(errors::NetworkTokenizationError::SaveNetworkTokenFailed)
+    .attach_printable(
+        "Failed to decrypt the tokenization response from the tokenization service",
+    )?;
 
-#[derive(Debug, Deserialize)]
-pub struct CheckTokenStatusResponse {
-    payload: CheckTokenStatusResponsePayload,
+    let cn_response: domain::CardNetworkTokenResponsePayload =
+        serde_json::from_str(&card_network_token_response)
+            .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;
+    Ok((cn_response.clone(), Some(cn_response.card_reference)))
 }
 
-pub const NETWORK_TOKEN_SERVICE: &str = "NETWORK_TOKEN";
-
-pub async fn mk_tokenization_req(
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub async fn generate_network_token(
     state: &routes::SessionState,
     payload_bytes: &[u8],
-    customer_id: id_type::CustomerId,
+    customer_id: id_type::GlobalCustomerId,
     tokenization_service: &settings::NetworkTokenizationService,
-) -> CustomResult<(CardNetworkTokenResponsePayload, Option<String>), errors::NetworkTokenizationError>
-{
+) -> CustomResult<
+    (domain::GenerateNetworkTokenResponsePayload, String),
+    errors::NetworkTokenizationError,
+> {
     let enc_key = tokenization_service.public_key.peek().clone();
 
     let key_id = tokenization_service.key_id.clone();
@@ -174,12 +173,12 @@ pub async fn mk_tokenization_req(
     .change_context(errors::NetworkTokenizationError::SaveNetworkTokenFailed)
     .attach_printable("Error on jwe encrypt")?;
 
-    let order_data = OrderData {
+    let order_data = domain::OrderData {
         consent_id: uuid::Uuid::new_v4().to_string(),
         customer_id,
     };
 
-    let api_payload = ApiPayload {
+    let api_payload = domain::ApiPayload {
         service: NETWORK_TOKEN_SERVICE.to_string(),
         card_data: Secret::new(jwt),
         order_data,
@@ -208,14 +207,14 @@ pub async fn mk_tokenization_req(
 
     let response = services::call_connector_api(state, request, "generate_token")
         .await
-        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed);
+        .change_context(errors::NetworkTokenizationError::ApiError);
 
     let res = response
         .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)
         .attach_printable("Error while receiving response")
         .and_then(|inner| match inner {
             Err(err_res) => {
-                let parsed_error: NetworkTokenErrorResponse = err_res
+                let parsed_error: domain::NetworkTokenErrorResponse = err_res
                     .response
                     .parse_struct("Card Network Tokenization Response")
                     .change_context(
@@ -236,11 +235,11 @@ pub async fn mk_tokenization_req(
             logger::error!("Error while deserializing response: {:?}", err);
         })?;
 
-    let network_response: CardNetworkTokenResponse = res
+    let network_response: domain::CardNetworkTokenResponse = res
         .response
         .parse_struct("Card Network Tokenization Response")
         .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;
-    logger::debug!("Network Token Response: {:?}", network_response); //added for debugging, will be removed
+    logger::debug!("Network Token Response: {:?}", network_response);
 
     let dec_key = tokenization_service.private_key.peek().clone();
 
@@ -256,19 +255,25 @@ pub async fn mk_tokenization_req(
         "Failed to decrypt the tokenization response from the tokenization service",
     )?;
 
-    let cn_response: CardNetworkTokenResponsePayload =
+    let cn_response: domain::GenerateNetworkTokenResponsePayload =
         serde_json::from_str(&card_network_token_response)
             .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;
-    Ok((cn_response.clone(), Some(cn_response.card_reference)))
+    Ok((cn_response.clone(), cn_response.card_reference))
 }
 
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 pub async fn make_card_network_tokenization_request(
     state: &routes::SessionState,
     card: &domain::Card,
     customer_id: &id_type::CustomerId,
-) -> CustomResult<(CardNetworkTokenResponsePayload, Option<String>), errors::NetworkTokenizationError>
-{
-    let card_data = CardData {
+) -> CustomResult<
+    (domain::CardNetworkTokenResponsePayload, Option<String>),
+    errors::NetworkTokenizationError,
+> {
+    let card_data = domain::CardData {
         card_number: card.card_number.clone(),
         exp_month: card.card_exp_month.clone(),
         exp_year: card.card_exp_year.clone(),
@@ -308,18 +313,74 @@ pub async fn make_card_network_tokenization_request(
     }
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub async fn make_card_network_tokenization_request(
+    state: &routes::SessionState,
+    card: &api_payment_methods::CardDetail,
+    customer_id: &id_type::GlobalCustomerId,
+) -> CustomResult<(NetworkTokenDetails, String), errors::NetworkTokenizationError> {
+    let card_data = domain::CardData {
+        card_number: card.card_number.clone(),
+        exp_month: card.card_exp_month.clone(),
+        exp_year: card.card_exp_year.clone(),
+        card_security_code: None,
+    };
+
+    let payload = card_data
+        .encode_to_string_of_json()
+        .and_then(|x| x.encode_to_string_of_json())
+        .change_context(errors::NetworkTokenizationError::RequestEncodingFailed)?;
+
+    let payload_bytes = payload.as_bytes();
+    let network_tokenization_service = match &state.conf.network_tokenization_service {
+        Some(nt_service) => Ok(nt_service.get_inner()),
+        None => Err(report!(
+            errors::NetworkTokenizationError::NetworkTokenizationServiceNotConfigured
+        )),
+    }?;
+
+    let (resp, network_token_req_ref_id) = record_operation_time(
+        async {
+            generate_network_token(
+                state,
+                payload_bytes,
+                customer_id.clone(),
+                network_tokenization_service,
+            )
+            .await
+            .inspect_err(|e| logger::error!(error=?e, "Error while making tokenization request"))
+        },
+        &metrics::GENERATE_NETWORK_TOKEN_TIME,
+        router_env::metric_attributes!(("locker", "rust")),
+    )
+    .await?;
+
+    let network_token_details = NetworkTokenDetails {
+        network_token: resp.token,
+        network_token_exp_month: resp.token_expiry_month,
+        network_token_exp_year: resp.token_expiry_year,
+        card_issuer: card.card_issuer.clone(),
+        card_network: Some(resp.card_brand),
+        card_type: card.card_type.clone(),
+        card_issuing_country: card.card_issuing_country,
+        card_holder_name: card.card_holder_name.clone(),
+        nick_name: card.nick_name.clone(),
+    };
+    Ok((network_token_details, network_token_req_ref_id))
+}
+
 #[cfg(feature = "v1")]
 pub async fn get_network_token(
     state: &routes::SessionState,
     customer_id: id_type::CustomerId,
     network_token_requestor_ref_id: String,
     tokenization_service: &settings::NetworkTokenizationService,
-) -> CustomResult<TokenResponse, errors::NetworkTokenizationError> {
+) -> CustomResult<domain::TokenResponse, errors::NetworkTokenizationError> {
     let mut request = services::Request::new(
         services::Method::Post,
         tokenization_service.fetch_token_url.as_str(),
     );
-    let payload = GetCardToken {
+    let payload = domain::GetCardToken {
         card_reference: network_token_requestor_ref_id,
         customer_id,
     };
@@ -342,14 +403,14 @@ pub async fn get_network_token(
     // Send the request using `call_connector_api`
     let response = services::call_connector_api(state, request, "get network token")
         .await
-        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed);
+        .change_context(errors::NetworkTokenizationError::ApiError);
 
     let res = response
         .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)
         .attach_printable("Error while receiving response")
         .and_then(|inner| match inner {
             Err(err_res) => {
-                let parsed_error: NetworkTokenErrorResponse = err_res
+                let parsed_error: domain::NetworkTokenErrorResponse = err_res
                     .response
                     .parse_struct("Card Network Tokenization Response")
                     .change_context(
@@ -367,7 +428,75 @@ pub async fn get_network_token(
             Ok(res) => Ok(res),
         })?;
 
-    let token_response: TokenResponse = res
+    let token_response: domain::TokenResponse = res
+        .response
+        .parse_struct("Get Network Token Response")
+        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;
+    logger::info!("Fetch Network Token Response: {:?}", token_response);
+
+    Ok(token_response)
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub async fn get_network_token(
+    state: &routes::SessionState,
+    customer_id: &id_type::GlobalCustomerId,
+    network_token_requestor_ref_id: String,
+    tokenization_service: &settings::NetworkTokenizationService,
+) -> CustomResult<domain::TokenResponse, errors::NetworkTokenizationError> {
+    let mut request = services::Request::new(
+        services::Method::Post,
+        tokenization_service.fetch_token_url.as_str(),
+    );
+    let payload = domain::GetCardToken {
+        card_reference: network_token_requestor_ref_id,
+        customer_id: customer_id.clone(),
+    };
+
+    request.add_header(headers::CONTENT_TYPE, "application/json".into());
+    request.add_header(
+        headers::AUTHORIZATION,
+        tokenization_service
+            .token_service_api_key
+            .clone()
+            .peek()
+            .clone()
+            .into_masked(),
+    );
+    request.add_default_headers();
+    request.set_body(RequestContent::Json(Box::new(payload)));
+
+    logger::info!("Request to fetch network token: {:?}", request);
+
+    // Send the request using `call_connector_api`
+    let response = services::call_connector_api(state, request, "get network token")
+        .await
+        .change_context(errors::NetworkTokenizationError::ApiError);
+
+    let res = response
+        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)
+        .attach_printable("Error while receiving response")
+        .and_then(|inner| match inner {
+            Err(err_res) => {
+                let parsed_error: domain::NetworkTokenErrorResponse = err_res
+                    .response
+                    .parse_struct("Card Network Tokenization Response")
+                    .change_context(
+                        errors::NetworkTokenizationError::ResponseDeserializationFailed,
+                    )?;
+                logger::error!(
+                    error_code = %parsed_error.error_info.code,
+                    developer_message = %parsed_error.error_info.developer_message,
+                    "Network tokenization error: {}",
+                    parsed_error.error_message
+                );
+                Err(errors::NetworkTokenizationError::ResponseDeserializationFailed)
+                    .attach_printable(format!("Response Deserialization Failed: {err_res:?}"))
+            }
+            Ok(res) => Ok(res),
+        })?;
+
+    let token_response: domain::TokenResponse = res
         .response
         .parse_struct("Get Network Token Response")
         .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;
@@ -415,9 +544,11 @@ pub async fn get_token_from_tokenization_service(
         .network_token_payment_method_data
         .clone()
         .map(|x| x.into_inner().expose())
-        .and_then(|v| serde_json::from_value::<PaymentMethodsData>(v).ok())
+        .and_then(|v| serde_json::from_value::<api_payment_methods::PaymentMethodsData>(v).ok())
         .and_then(|pmd| match pmd {
-            PaymentMethodsData::Card(token) => Some(api::CardDetailFromLocker::from(token)),
+            api_payment_methods::PaymentMethodsData::Card(token) => {
+                Some(api::CardDetailFromLocker::from(token))
+            }
             _ => None,
         })
         .ok_or(errors::ApiErrorResponse::InternalServerError)
@@ -452,9 +583,11 @@ pub async fn do_status_check_for_network_token(
         .network_token_payment_method_data
         .clone()
         .map(|x| x.into_inner().expose())
-        .and_then(|v| serde_json::from_value::<PaymentMethodsData>(v).ok())
+        .and_then(|v| serde_json::from_value::<api_payment_methods::PaymentMethodsData>(v).ok())
         .and_then(|pmd| match pmd {
-            PaymentMethodsData::Card(token) => Some(api::CardDetailFromLocker::from(token)),
+            api_payment_methods::PaymentMethodsData::Card(token) => {
+                Some(api::CardDetailFromLocker::from(token))
+            }
             _ => None,
         });
     let network_token_requestor_reference_id = payment_method_info
@@ -507,6 +640,10 @@ pub async fn do_status_check_for_network_token(
     }
 }
 
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 pub async fn check_token_status_with_tokenization_service(
     state: &routes::SessionState,
     customer_id: &id_type::CustomerId,
@@ -518,7 +655,7 @@ pub async fn check_token_status_with_tokenization_service(
         services::Method::Post,
         tokenization_service.check_token_status_url.as_str(),
     );
-    let payload = CheckTokenStatus {
+    let payload = domain::CheckTokenStatus {
         card_reference: network_token_requestor_reference_id,
         customer_id: customer_id.clone(),
     };
@@ -539,13 +676,13 @@ pub async fn check_token_status_with_tokenization_service(
     // Send the request using `call_connector_api`
     let response = services::call_connector_api(state, request, "Check Network token Status")
         .await
-        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed);
+        .change_context(errors::NetworkTokenizationError::ApiError);
     let res = response
         .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)
         .attach_printable("Error while receiving response")
         .and_then(|inner| match inner {
             Err(err_res) => {
-                let parsed_error: NetworkTokenErrorResponse = err_res
+                let parsed_error: domain::NetworkTokenErrorResponse = err_res
                     .response
                     .parse_struct("Delete Network Tokenization Response")
                     .change_context(
@@ -566,20 +703,35 @@ pub async fn check_token_status_with_tokenization_service(
             logger::error!("Error while deserializing response: {:?}", err);
         })?;
 
-    let check_token_status_response: CheckTokenStatusResponse = res
+    let check_token_status_response: domain::CheckTokenStatusResponse = res
         .response
         .parse_struct("Delete Network Tokenization Response")
         .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;
 
     match check_token_status_response.payload.token_status {
-        TokenStatus::Active => Ok((
+        domain::TokenStatus::Active => Ok((
             Some(check_token_status_response.payload.token_expiry_month),
             Some(check_token_status_response.payload.token_expiry_year),
         )),
-        TokenStatus::Inactive => Ok((None, None)),
+        domain::TokenStatus::Inactive => Ok((None, None)),
     }
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub async fn check_token_status_with_tokenization_service(
+    _state: &routes::SessionState,
+    _customer_id: &id_type::GlobalCustomerId,
+    _network_token_requestor_reference_id: String,
+    _tokenization_service: &settings::NetworkTokenizationService,
+) -> CustomResult<(Option<Secret<String>>, Option<Secret<String>>), errors::NetworkTokenizationError>
+{
+    todo!()
+}
+
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 pub async fn delete_network_token_from_locker_and_token_service(
     state: &routes::SessionState,
     customer_id: &id_type::CustomerId,
@@ -624,6 +776,10 @@ pub async fn delete_network_token_from_locker_and_token_service(
     Ok(resp)
 }
 
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 pub async fn delete_network_token_from_tokenization_service(
     state: &routes::SessionState,
     network_token_requestor_reference_id: String,
@@ -634,7 +790,7 @@ pub async fn delete_network_token_from_tokenization_service(
         services::Method::Post,
         tokenization_service.delete_token_url.as_str(),
     );
-    let payload = DeleteCardToken {
+    let payload = domain::DeleteCardToken {
         card_reference: network_token_requestor_reference_id,
         customer_id: customer_id.clone(),
     };
@@ -657,13 +813,13 @@ pub async fn delete_network_token_from_tokenization_service(
     // Send the request using `call_connector_api`
     let response = services::call_connector_api(state, request, "delete network token")
         .await
-        .change_context(errors::NetworkTokenizationError::DeleteNetworkTokenFailed);
+        .change_context(errors::NetworkTokenizationError::ApiError);
     let res = response
         .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)
         .attach_printable("Error while receiving response")
         .and_then(|inner| match inner {
             Err(err_res) => {
-                let parsed_error: NetworkTokenErrorResponse = err_res
+                let parsed_error: domain::NetworkTokenErrorResponse = err_res
                     .response
                     .parse_struct("Delete Network Tokenization Response")
                     .change_context(
@@ -684,17 +840,29 @@ pub async fn delete_network_token_from_tokenization_service(
             logger::error!("Error while deserializing response: {:?}", err);
         })?;
 
-    let delete_token_response: DeleteNetworkTokenResponse = res
+    let delete_token_response: domain::DeleteNetworkTokenResponse = res
         .response
         .parse_struct("Delete Network Tokenization Response")
         .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;
 
     logger::info!("Delete Network Token Response: {:?}", delete_token_response);
 
-    if delete_token_response.status == DeleteNetworkTokenStatus::Success {
+    if delete_token_response.status == domain::DeleteNetworkTokenStatus::Success {
         Ok(true)
     } else {
         Err(errors::NetworkTokenizationError::DeleteNetworkTokenFailed)
             .attach_printable("Delete Token at Token service failed")
     }
 }
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub async fn delete_network_token_from_locker_and_token_service(
+    _state: &routes::SessionState,
+    _customer_id: &id_type::GlobalCustomerId,
+    _merchant_id: &id_type::MerchantId,
+    _payment_method_id: String,
+    _network_token_locker_id: Option<String>,
+    _network_token_requestor_reference_id: String,
+) -> errors::RouterResult<DeleteCardResp> {
+    todo!()
+}
diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs
index c4d3eafe463..947ae97b119 100644
--- a/crates/router/src/core/payment_methods/transformers.rs
+++ b/crates/router/src/core/payment_methods/transformers.rs
@@ -545,6 +545,7 @@ pub fn generate_pm_vaulting_req_from_update_request(
             card_holder_name: update_card.card_holder_name,
             nick_name: update_card.nick_name,
         }),
+        _ => todo!(), //todo! - since support for network tokenization is not added PaymentMethodUpdateData. should be handled later.
     }
 }
 
diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs
index 86f1874ab09..49018faa634 100644
--- a/crates/router/src/routes/payment_methods.rs
+++ b/crates/router/src/routes/payment_methods.rs
@@ -85,6 +85,7 @@ pub async fn create_payment_method_api(
                 req,
                 &auth.merchant_account,
                 &auth.key_store,
+                &auth.profile,
             ))
             .await
         },
diff --git a/crates/router/src/types/domain.rs b/crates/router/src/types/domain.rs
index 9a87b6d28be..270ed3ca64d 100644
--- a/crates/router/src/types/domain.rs
+++ b/crates/router/src/types/domain.rs
@@ -20,6 +20,10 @@ mod callback_mapper {
     pub use hyperswitch_domain_models::callback_mapper::CallbackMapper;
 }
 
+mod network_tokenization {
+    pub use hyperswitch_domain_models::network_tokenization::*;
+}
+
 pub use customers::*;
 pub use merchant_account::*;
 
@@ -48,6 +52,7 @@ pub use consts::*;
 pub use event::*;
 pub use merchant_connector_account::*;
 pub use merchant_key_store::*;
+pub use network_tokenization::*;
 pub use payment_methods::*;
 pub use payments::*;
 #[cfg(feature = "olap")]
diff --git a/crates/router/src/types/payment_methods.rs b/crates/router/src/types/payment_methods.rs
index c40d6fedfe7..d639bc44bc8 100644
--- a/crates/router/src/types/payment_methods.rs
+++ b/crates/router/src/types/payment_methods.rs
@@ -1,6 +1,8 @@
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use common_utils::generate_id;
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use hyperswitch_domain_models::payment_method_data::NetworkTokenDetails;
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use masking::Secret;
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -115,6 +117,7 @@ impl VaultingInterface for VaultDelete {
 #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
 pub enum PaymentMethodVaultingData {
     Card(api::CardDetail),
+    NetworkToken(NetworkTokenDetails),
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -122,6 +125,7 @@ impl VaultingDataInterface for PaymentMethodVaultingData {
     fn get_vaulting_data_key(&self) -> String {
         match &self {
             Self::Card(card) => card.card_number.to_string(),
+            Self::NetworkToken(network_token) => network_token.network_token.to_string(),
         }
     }
 }

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

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

## Description
<!-- Describe your changes in detail -->
add support for network tokenization for v2/payment-methods
- added network tokenization support for create+confirm payment methods api v2
- introduced new type for network token

### 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)?
-->
test cases - 
enable network tokenization for profile
payment-method create api - 
```
curl --location 'http://localhost:8080/v2/payment-methods' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'X-Profile-Id: pro_1Z1F459LoQzRTieDsLW2' \
--header 'api-key: dev_sewkgvR4aMq0tWNzDD6Y7IsNr9kPTS9ee19eQOGUaNLXWsqfxusLWu0ZGy2XU3pK' \
--data '{
    "customer_id": "12345_cus_0194f66341a27da1af6dc6b7b86cfaeb",
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4242424242424242",
            "card_exp_month": "03",
            "card_exp_year": "2025",
            "card_holder_name": "joseph Doe"
        }
    },
    "network_tokenization":{
        "enable":"Enable"
    }
}'
```
verify in payment methods table.
<img width="1726" alt="Screenshot 2025-02-14 at 1 08 29 PM" src="https://github.com/user-attachments/assets/2721dce4-c1ad-4a6f-b548-73939211f9a5" />


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

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