Bug: [FEATURE]: Save Payment Method on Payments Confirm (V2)



Add functionality to save a payment method after a successful payment
diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json
index e3b41ce3899..b0a60046574 100644
--- a/api-reference-v2/openapi_spec.json
+++ b/api-reference-v2/openapi_spec.json
@@ -3043,7 +3043,7 @@
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/PaymentMethodListResponse"
+                  "$ref": "#/components/schemas/PaymentMethodListResponseForSession"
                 }
               }
             }
@@ -9471,18 +9471,19 @@
           }
         }
       },
-      "CustomerPaymentMethod": {
+      "CustomerPaymentMethodResponseItem": {
         "type": "object",
         "required": [
           "id",
+          "payment_token",
           "customer_id",
           "payment_method_type",
           "payment_method_subtype",
           "recurring_enabled",
           "created",
           "requires_cvv",
-          "is_default",
-          "psp_tokenization_enabled"
+          "last_used_at",
+          "is_default"
         ],
         "properties": {
           "id": {
@@ -9490,6 +9491,11 @@
             "description": "The unique identifier of the payment method.",
             "example": "12345_pm_01926c58bc6e77c09e809964e72af8c8"
           },
+          "payment_token": {
+            "type": "string",
+            "description": "Temporary Token for payment method in vault which gets refreshed for every payment",
+            "example": "7ebf443f-a050-4067-84e5-e6f6d4800aef"
+          },
           "customer_id": {
             "type": "string",
             "description": "The unique identifier of the customer.",
@@ -9553,18 +9559,6 @@
               }
             ],
             "nullable": true
-          },
-          "network_tokenization": {
-            "allOf": [
-              {
-                "$ref": "#/components/schemas/NetworkTokenResponse"
-              }
-            ],
-            "nullable": true
-          },
-          "psp_tokenization_enabled": {
-            "type": "boolean",
-            "description": "Whether psp_tokenization is enabled for the payment_method, this will be true when at least\none multi-use token with status `Active` is available for the payment method"
           }
         }
       },
@@ -9577,7 +9571,7 @@
           "customer_payment_methods": {
             "type": "array",
             "items": {
-              "$ref": "#/components/schemas/CustomerPaymentMethod"
+              "$ref": "#/components/schemas/PaymentMethodResponseItem"
             },
             "description": "List of payment methods for customer"
           }
@@ -16751,49 +16745,49 @@
         },
         "additionalProperties": false
       },
-      "PaymentMethodListResponse": {
+      "PaymentMethodListResponseForPayments": {
         "type": "object",
         "required": [
-          "payment_methods_enabled",
-          "customer_payment_methods"
+          "payment_methods_enabled"
         ],
         "properties": {
           "payment_methods_enabled": {
             "type": "array",
             "items": {
-              "$ref": "#/components/schemas/ResponsePaymentMethodTypes"
+              "$ref": "#/components/schemas/ResponsePaymentMethodTypesForPayments"
             },
             "description": "The list of payment methods that are enabled for the business profile"
           },
           "customer_payment_methods": {
             "type": "array",
             "items": {
-              "$ref": "#/components/schemas/CustomerPaymentMethod"
+              "$ref": "#/components/schemas/CustomerPaymentMethodResponseItem"
             },
-            "description": "The list of saved payment methods of the customer"
+            "description": "The list of payment methods that are saved by the given customer\nThis field is only returned if the customer_id is provided in the request",
+            "nullable": true
           }
         }
       },
-      "PaymentMethodListResponseForPayments": {
+      "PaymentMethodListResponseForSession": {
         "type": "object",
         "required": [
-          "payment_methods_enabled"
+          "payment_methods_enabled",
+          "customer_payment_methods"
         ],
         "properties": {
           "payment_methods_enabled": {
             "type": "array",
             "items": {
-              "$ref": "#/components/schemas/ResponsePaymentMethodTypesForPayments"
+              "$ref": "#/components/schemas/ResponsePaymentMethodTypes"
             },
             "description": "The list of payment methods that are enabled for the business profile"
           },
           "customer_payment_methods": {
             "type": "array",
             "items": {
-              "$ref": "#/components/schemas/CustomerPaymentMethod"
+              "$ref": "#/components/schemas/CustomerPaymentMethodResponseItem"
             },
-            "description": "The list of payment methods that are saved by the given customer\nThis field is only returned if the customer_id is provided in the request",
-            "nullable": true
+            "description": "The list of saved payment methods of the customer"
           }
         }
       },
@@ -16895,6 +16889,103 @@
           }
         ]
       },
+      "PaymentMethodResponseItem": {
+        "type": "object",
+        "required": [
+          "id",
+          "customer_id",
+          "payment_method_type",
+          "payment_method_subtype",
+          "recurring_enabled",
+          "created",
+          "requires_cvv",
+          "is_default",
+          "psp_tokenization_enabled"
+        ],
+        "properties": {
+          "id": {
+            "type": "string",
+            "description": "The unique identifier of the payment method.",
+            "example": "12345_pm_01926c58bc6e77c09e809964e72af8c8"
+          },
+          "customer_id": {
+            "type": "string",
+            "description": "The unique identifier of the customer.",
+            "example": "12345_cus_01926c58bc6e77c09e809964e72af8c8",
+            "maxLength": 64,
+            "minLength": 32
+          },
+          "payment_method_type": {
+            "$ref": "#/components/schemas/PaymentMethod"
+          },
+          "payment_method_subtype": {
+            "$ref": "#/components/schemas/PaymentMethodType"
+          },
+          "recurring_enabled": {
+            "type": "boolean",
+            "description": "Indicates whether the payment method is eligible for recurring payments",
+            "example": true
+          },
+          "payment_method_data": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/PaymentMethodListData"
+              }
+            ],
+            "nullable": true
+          },
+          "bank": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/MaskedBankDetails"
+              }
+            ],
+            "nullable": true
+          },
+          "created": {
+            "type": "string",
+            "format": "date-time",
+            "description": "A timestamp (ISO 8601 code) that determines when the payment method was created",
+            "example": "2023-01-18T11:04:09.922Z"
+          },
+          "requires_cvv": {
+            "type": "boolean",
+            "description": "Whether this payment method requires CVV to be collected",
+            "example": true
+          },
+          "last_used_at": {
+            "type": "string",
+            "format": "date-time",
+            "description": "A timestamp (ISO 8601 code) that determines when the payment method was last used",
+            "example": "2024-02-24T11:04:09.922Z"
+          },
+          "is_default": {
+            "type": "boolean",
+            "description": "Indicates if the payment method has been set to default or not",
+            "example": true
+          },
+          "billing": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/Address"
+              }
+            ],
+            "nullable": true
+          },
+          "network_tokenization": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/NetworkTokenResponse"
+              }
+            ],
+            "nullable": true
+          },
+          "psp_tokenization_enabled": {
+            "type": "boolean",
+            "description": "Whether psp_tokenization is enabled for the payment_method, this will be true when at least\none multi-use token with status `Active` is available for the payment method"
+          }
+        }
+      },
       "PaymentMethodSessionConfirmRequest": {
         "type": "object",
         "required": [
@@ -17617,6 +17708,12 @@
             "type": "string",
             "description": "The payment_method_id to be associated with the payment",
             "nullable": true
+          },
+          "payment_token": {
+            "type": "string",
+            "description": "Provide a reference to a stored payment method",
+            "example": "187282ab-40ef-47a9-9206-5099ba31e432",
+            "nullable": true
           }
         },
         "additionalProperties": false
diff --git a/crates/api_models/src/events/payment.rs b/crates/api_models/src/events/payment.rs
index 76d1201c2e7..851e2500f7e 100644
--- a/crates/api_models/src/events/payment.rs
+++ b/crates/api_models/src/events/payment.rs
@@ -5,23 +5,29 @@ use super::{
     PaymentStartRedirectionRequest, PaymentsCreateIntentRequest, PaymentsGetIntentRequest,
     PaymentsIntentResponse, PaymentsRequest,
 };
+#[cfg(feature = "v2")]
+use crate::payment_methods::PaymentMethodListResponseForSession;
 #[cfg(feature = "v1")]
-use crate::payments::{
-    ExtendedCardInfoResponse, PaymentIdType, PaymentListFilterConstraints, PaymentListResponseV2,
-    PaymentsApproveRequest, PaymentsCancelRequest, PaymentsCaptureRequest,
-    PaymentsCompleteAuthorizeRequest, PaymentsDynamicTaxCalculationRequest,
-    PaymentsDynamicTaxCalculationResponse, PaymentsExternalAuthenticationRequest,
-    PaymentsExternalAuthenticationResponse, PaymentsIncrementalAuthorizationRequest,
-    PaymentsManualUpdateRequest, PaymentsManualUpdateResponse, PaymentsPostSessionTokensRequest,
-    PaymentsPostSessionTokensResponse, PaymentsRejectRequest, PaymentsRetrieveRequest,
-    PaymentsStartRequest, PaymentsUpdateMetadataRequest, PaymentsUpdateMetadataResponse,
+use crate::{
+    payment_methods::PaymentMethodListResponse,
+    payments::{
+        ExtendedCardInfoResponse, PaymentIdType, PaymentListFilterConstraints,
+        PaymentListResponseV2, PaymentsApproveRequest, PaymentsCancelRequest,
+        PaymentsCaptureRequest, PaymentsCompleteAuthorizeRequest,
+        PaymentsDynamicTaxCalculationRequest, PaymentsDynamicTaxCalculationResponse,
+        PaymentsExternalAuthenticationRequest, PaymentsExternalAuthenticationResponse,
+        PaymentsIncrementalAuthorizationRequest, PaymentsManualUpdateRequest,
+        PaymentsManualUpdateResponse, PaymentsPostSessionTokensRequest,
+        PaymentsPostSessionTokensResponse, PaymentsRejectRequest, PaymentsRetrieveRequest,
+        PaymentsStartRequest, PaymentsUpdateMetadataRequest, PaymentsUpdateMetadataResponse,
+    },
 };
 use crate::{
     payment_methods::{
         self, ListCountriesCurrenciesRequest, ListCountriesCurrenciesResponse,
         PaymentMethodCollectLinkRenderRequest, PaymentMethodCollectLinkRequest,
-        PaymentMethodCollectLinkResponse, PaymentMethodListRequest, PaymentMethodListResponse,
-        PaymentMethodMigrateResponse, PaymentMethodResponse, PaymentMethodUpdate,
+        PaymentMethodCollectLinkResponse, PaymentMethodListRequest, PaymentMethodMigrateResponse,
+        PaymentMethodResponse, PaymentMethodUpdate,
     },
     payments::{
         self, PaymentListConstraints, PaymentListFilters, PaymentListFiltersV2,
@@ -304,6 +310,8 @@ impl ApiEventMetric for PaymentMethodListRequest {
 impl ApiEventMetric for ListCountriesCurrenciesRequest {}
 
 impl ApiEventMetric for ListCountriesCurrenciesResponse {}
+
+#[cfg(feature = "v1")]
 impl ApiEventMetric for PaymentMethodListResponse {}
 
 #[cfg(feature = "v1")]
@@ -454,6 +462,9 @@ impl ApiEventMetric for payments::PaymentMethodListResponseForPayments {
     }
 }
 
+#[cfg(feature = "v2")]
+impl ApiEventMetric for PaymentMethodListResponseForSession {}
+
 #[cfg(feature = "v2")]
 impl ApiEventMetric for payments::PaymentsCaptureResponse {
     fn get_api_event_type(&self) -> Option<ApiEventsType> {
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 92761192d1c..2153bda7320 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -1225,12 +1225,12 @@ impl From<CardDetailFromLocker> for payments::AdditionalCardInfo {
 
 #[cfg(feature = "v2")]
 #[derive(Debug, serde::Serialize, ToSchema)]
-pub struct PaymentMethodListResponse {
+pub struct PaymentMethodListResponseForSession {
     /// The list of payment methods that are enabled for the business profile
     pub payment_methods_enabled: Vec<ResponsePaymentMethodTypes>,
 
     /// The list of saved payment methods of the customer
-    pub customer_payment_methods: Vec<CustomerPaymentMethod>,
+    pub customer_payment_methods: Vec<CustomerPaymentMethodResponseItem>,
 }
 
 #[cfg(all(
@@ -1930,11 +1930,12 @@ pub struct CustomerPaymentMethodsListResponse {
     pub is_guest_customer: Option<bool>,
 }
 
+// OLAP PML Response
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[derive(Debug, serde::Serialize, ToSchema)]
 pub struct CustomerPaymentMethodsListResponse {
     /// List of payment methods for customer
-    pub customer_payment_methods: Vec<CustomerPaymentMethod>,
+    pub customer_payment_methods: Vec<PaymentMethodResponseItem>,
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -2073,7 +2074,7 @@ pub struct CustomerDefaultPaymentMethodResponse {
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[derive(Debug, Clone, serde::Serialize, ToSchema)]
-pub struct CustomerPaymentMethod {
+pub struct PaymentMethodResponseItem {
     /// The unique identifier of the payment method.
     #[schema(value_type = String, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
     pub id: id_type::GlobalPaymentMethodId,
@@ -2136,6 +2137,68 @@ pub struct CustomerPaymentMethod {
     pub psp_tokenization_enabled: bool,
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, Clone, serde::Serialize, ToSchema)]
+pub struct CustomerPaymentMethodResponseItem {
+    /// The unique identifier of the payment method.
+    #[schema(value_type = String, example = "12345_pm_01926c58bc6e77c09e809964e72af8c8")]
+    pub id: id_type::GlobalPaymentMethodId,
+
+    /// Temporary Token for payment method in vault which gets refreshed for every payment   
+    #[schema(example = "7ebf443f-a050-4067-84e5-e6f6d4800aef")]
+    pub payment_token: String,
+
+    /// The unique identifier of the customer.
+    #[schema(
+        min_length = 32,
+        max_length = 64,
+        example = "12345_cus_01926c58bc6e77c09e809964e72af8c8",
+        value_type = String
+    )]
+    pub customer_id: id_type::GlobalCustomerId,
+
+    /// The type of payment method use for the payment.
+    #[schema(value_type = PaymentMethod,example = "card")]
+    pub payment_method_type: api_enums::PaymentMethod,
+
+    /// This is a sub-category of payment method.
+    #[schema(value_type = PaymentMethodType,example = "credit")]
+    pub payment_method_subtype: api_enums::PaymentMethodType,
+
+    /// Indicates whether the payment method is eligible for recurring payments
+    #[schema(example = true)]
+    pub recurring_enabled: bool,
+
+    /// PaymentMethod Data from locker
+    pub payment_method_data: Option<PaymentMethodListData>,
+
+    /// Masked bank details from PM auth services
+    #[schema(example = json!({"mask": "0000"}))]
+    pub bank: Option<MaskedBankDetails>,
+
+    /// A timestamp (ISO 8601 code) that determines when the payment method was created
+    #[schema(value_type = PrimitiveDateTime, example = "2023-01-18T11:04:09.922Z")]
+    #[serde(with = "common_utils::custom_serde::iso8601")]
+    pub created: time::PrimitiveDateTime,
+
+    /// Whether this payment method requires CVV to be collected
+    #[schema(example = true)]
+    pub requires_cvv: bool,
+
+    ///  A timestamp (ISO 8601 code) that determines when the payment method was last used
+    #[schema(value_type = PrimitiveDateTime,example = "2024-02-24T11:04:09.922Z")]
+    #[serde(with = "common_utils::custom_serde::iso8601")]
+    pub last_used_at: time::PrimitiveDateTime,
+
+    /// Indicates if the payment method has been set to default or not
+    #[schema(example = true)]
+    pub is_default: bool,
+
+    /// The billing details of the payment method
+    #[schema(value_type = Option<Address>)]
+    pub billing: Option<payments::Address>,
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[derive(Debug, Clone, serde::Serialize, ToSchema)]
 #[serde(rename_all = "snake_case")]
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index 7ab8bc19361..33d489716c6 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -5328,6 +5328,10 @@ pub struct PaymentsConfirmIntentRequest {
     /// The payment_method_id to be associated with the payment
     #[schema(value_type = Option<String>)]
     pub payment_method_id: Option<id_type::GlobalPaymentMethodId>,
+
+    /// Provide a reference to a stored payment method
+    #[schema(example = "187282ab-40ef-47a9-9206-5099ba31e432")]
+    pub payment_token: Option<String>,
 }
 
 #[cfg(feature = "v2")]
@@ -5550,6 +5554,7 @@ impl From<&PaymentsRequest> for PaymentsConfirmIntentRequest {
             customer_acceptance: request.customer_acceptance.clone(),
             browser_info: request.browser_info.clone(),
             payment_method_id: request.payment_method_id.clone(),
+            payment_token: None,
         }
     }
 }
@@ -7590,8 +7595,8 @@ pub struct PaymentMethodListResponseForPayments {
 
     /// The list of payment methods that are saved by the given customer
     /// This field is only returned if the customer_id is provided in the request
-    #[schema(value_type = Option<Vec<CustomerPaymentMethod>>)]
-    pub customer_payment_methods: Option<Vec<payment_methods::CustomerPaymentMethod>>,
+    #[schema(value_type = Option<Vec<CustomerPaymentMethodResponseItem>>)]
+    pub customer_payment_methods: Option<Vec<payment_methods::CustomerPaymentMethodResponseItem>>,
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs
index f351c884a05..a694f3fc0ca 100644
--- a/crates/diesel_models/src/payment_attempt.rs
+++ b/crates/diesel_models/src/payment_attempt.rs
@@ -833,7 +833,7 @@ pub struct PaymentAttemptUpdateInternal {
     pub authentication_type: Option<storage_enums::AuthenticationType>,
     pub error_message: Option<String>,
     pub connector_payment_id: Option<String>,
-    // payment_method_id: Option<String>,
+    pub payment_method_id: Option<id_type::GlobalPaymentMethodId>,
     // cancellation_reason: Option<String>,
     pub modified_at: PrimitiveDateTime,
     pub browser_info: Option<serde_json::Value>,
diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs
index 2240df7241f..6b93394d134 100644
--- a/crates/hyperswitch_domain_models/src/payment_method_data.rs
+++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs
@@ -843,6 +843,56 @@ impl
     }
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+impl
+    From<(
+        payment_methods::CardDetail,
+        Secret<String>,
+        Option<Secret<String>>,
+    )> for Card
+{
+    fn from(
+        (card_detail, card_cvc, card_holder_name): (
+            payment_methods::CardDetail,
+            Secret<String>,
+            Option<Secret<String>>,
+        ),
+    ) -> Self {
+        Self {
+            card_number: card_detail.card_number,
+            card_exp_month: card_detail.card_exp_month,
+            card_exp_year: card_detail.card_exp_year,
+            card_cvc,
+            card_issuer: card_detail.card_issuer,
+            card_network: card_detail.card_network,
+            card_type: card_detail.card_type.map(|val| val.to_string()),
+            card_issuing_country: card_detail.card_issuing_country.map(|val| val.to_string()),
+            bank_code: None,
+            nick_name: card_detail.nick_name,
+            card_holder_name: card_holder_name.or(card_detail.card_holder_name),
+            co_badged_card_data: None,
+        }
+    }
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+impl From<Card> for payment_methods::CardDetail {
+    fn from(card: Card) -> Self {
+        Self {
+            card_number: card.card_number,
+            card_exp_month: card.card_exp_month,
+            card_exp_year: card.card_exp_year,
+            card_holder_name: card.card_holder_name,
+            nick_name: card.nick_name,
+            card_issuing_country: None,
+            card_network: card.card_network,
+            card_issuer: card.card_issuer,
+            card_type: None,
+            card_cvc: Some(card.card_cvc),
+        }
+    }
+}
+
 impl From<api_models::payments::CardRedirectData> for CardRedirectData {
     fn from(value: api_models::payments::CardRedirectData) -> Self {
         match value {
diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs
index 42d1ef1a426..6adc7f2a394 100644
--- a/crates/hyperswitch_domain_models/src/payments.rs
+++ b/crates/hyperswitch_domain_models/src/payments.rs
@@ -43,7 +43,7 @@ use self::payment_attempt::PaymentAttempt;
 use crate::{
     address::Address, business_profile, customer, errors, merchant_account,
     merchant_connector_account, merchant_context, payment_address, payment_method_data,
-    revenue_recovery, routing, ApiModelToDieselModelConvertor,
+    payment_methods, revenue_recovery, routing, ApiModelToDieselModelConvertor,
 };
 #[cfg(feature = "v1")]
 use crate::{payment_method_data, RemoteStorageObject};
@@ -853,6 +853,7 @@ where
     pub payment_method_data: Option<payment_method_data::PaymentMethodData>,
     pub payment_address: payment_address::PaymentAddress,
     pub mandate_data: Option<api_models::payments::MandateIds>,
+    pub payment_method: Option<payment_methods::PaymentMethod>,
 }
 
 #[cfg(feature = "v2")]
@@ -871,6 +872,22 @@ impl<F: Clone> PaymentConfirmData<F> {
                 .get_connector_customer_id_from_feature_metadata(),
         }
     }
+
+    pub fn update_payment_method_data(
+        &mut self,
+        payment_method_data: payment_method_data::PaymentMethodData,
+    ) {
+        self.payment_method_data = Some(payment_method_data);
+    }
+
+    pub fn update_payment_method_and_pm_id(
+        &mut self,
+        payment_method_id: id_type::GlobalPaymentMethodId,
+        payment_method: payment_methods::PaymentMethod,
+    ) {
+        self.payment_attempt.payment_method_id = Some(payment_method_id);
+        self.payment_method = Some(payment_method);
+    }
 }
 
 #[cfg(feature = "v2")]
diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
index c7342590e35..fb655280fe9 100644
--- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
+++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
@@ -6,7 +6,9 @@ use common_types::primitive_wrappers::{
 };
 #[cfg(feature = "v2")]
 use common_utils::{
-    crypto::Encryptable, encryption::Encryption, ext_traits::ValueExt,
+    crypto::Encryptable,
+    encryption::Encryption,
+    ext_traits::{Encode, ValueExt},
     types::keymanager::ToEncryptable,
 };
 use common_utils::{
@@ -562,7 +564,7 @@ impl PaymentAttempt {
             last_synced: None,
             cancellation_reason: None,
             browser_info: request.browser_info.clone(),
-            payment_token: None,
+            payment_token: request.payment_token.clone(),
             connector_metadata: None,
             payment_experience: None,
             payment_method_data: None,
@@ -581,7 +583,14 @@ impl PaymentAttempt {
             charges: None,
             client_source: None,
             client_version: None,
-            customer_acceptance: None,
+            customer_acceptance: request
+                .customer_acceptance
+                .as_ref()
+                .map(Encode::encode_to_value)
+                .transpose()
+                .change_context(errors::api_error_response::ApiErrorResponse::InternalServerError)
+                .attach_printable("Unable to encode customer_acceptance")?
+                .map(Secret::new),
             profile_id: payment_intent.profile_id.clone(),
             organization_id: payment_intent.organization_id.clone(),
             payment_method_type: request.payment_method_type,
@@ -1747,6 +1756,15 @@ pub enum PaymentAttemptUpdate {
         merchant_connector_id: id_type::MerchantConnectorAccountId,
         authentication_type: storage_enums::AuthenticationType,
     },
+    /// Update the payment attempt on confirming the intent, before calling the connector, when payment_method_id is present
+    ConfirmIntentTokenized {
+        status: storage_enums::AttemptStatus,
+        updated_by: String,
+        connector: String,
+        merchant_connector_id: id_type::MerchantConnectorAccountId,
+        authentication_type: storage_enums::AuthenticationType,
+        payment_method_id: id_type::GlobalPaymentMethodId,
+    },
     /// Update the payment attempt on confirming the intent, after calling the connector on success response
     ConfirmIntentResponse(Box<ConfirmIntentResponseUpdate>),
     /// Update the payment attempt after force syncing with the connector
@@ -2523,6 +2541,7 @@ impl From<PaymentAttemptUpdate> for diesel_models::PaymentAttemptUpdateInternal
                 authentication_type,
             } => Self {
                 status: Some(status),
+                payment_method_id: None,
                 error_message: None,
                 modified_at: common_utils::date_time::now(),
                 browser_info: None,
@@ -2553,6 +2572,7 @@ impl From<PaymentAttemptUpdate> for diesel_models::PaymentAttemptUpdateInternal
                 updated_by,
             } => Self {
                 status: Some(status),
+                payment_method_id: None,
                 error_message: Some(error.message),
                 error_code: Some(error.code),
                 modified_at: common_utils::date_time::now(),
@@ -2587,6 +2607,7 @@ impl From<PaymentAttemptUpdate> for diesel_models::PaymentAttemptUpdateInternal
                 } = *confirm_intent_response_update;
                 Self {
                     status: Some(status),
+                    payment_method_id: None,
                     amount_capturable,
                     error_message: None,
                     error_code: None,
@@ -2617,6 +2638,7 @@ impl From<PaymentAttemptUpdate> for diesel_models::PaymentAttemptUpdateInternal
                 updated_by,
             } => Self {
                 status: Some(status),
+                payment_method_id: None,
                 amount_capturable,
                 error_message: None,
                 error_code: None,
@@ -2645,6 +2667,7 @@ impl From<PaymentAttemptUpdate> for diesel_models::PaymentAttemptUpdateInternal
                 updated_by,
             } => Self {
                 status: Some(status),
+                payment_method_id: None,
                 amount_capturable,
                 amount_to_capture: None,
                 error_message: None,
@@ -2672,6 +2695,7 @@ impl From<PaymentAttemptUpdate> for diesel_models::PaymentAttemptUpdateInternal
                 updated_by,
             } => Self {
                 amount_to_capture,
+                payment_method_id: None,
                 error_message: None,
                 modified_at: common_utils::date_time::now(),
                 browser_info: None,
@@ -2694,6 +2718,38 @@ impl From<PaymentAttemptUpdate> for diesel_models::PaymentAttemptUpdateInternal
                 network_decline_code: None,
                 network_error_message: None,
             },
+            PaymentAttemptUpdate::ConfirmIntentTokenized {
+                status,
+                updated_by,
+                connector,
+                merchant_connector_id,
+                authentication_type,
+                payment_method_id,
+            } => Self {
+                status: Some(status),
+                payment_method_id: Some(payment_method_id),
+                error_message: None,
+                modified_at: common_utils::date_time::now(),
+                browser_info: None,
+                error_code: None,
+                error_reason: None,
+                updated_by,
+                merchant_connector_id: Some(merchant_connector_id),
+                unified_code: None,
+                unified_message: None,
+                connector_payment_id: None,
+                connector: Some(connector),
+                redirection_data: None,
+                connector_metadata: None,
+                amount_capturable: None,
+                amount_to_capture: None,
+                connector_token_details: None,
+                authentication_type: Some(authentication_type),
+                feature_metadata: None,
+                network_advice_code: None,
+                network_decline_code: None,
+                network_error_message: None,
+            },
         }
     }
 }
diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs
index f43712782f6..7191d9fda26 100644
--- a/crates/openapi/src/openapi_v2.rs
+++ b/crates/openapi/src/openapi_v2.rs
@@ -232,9 +232,11 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payment_methods::AuthenticationDetails,
         api_models::payment_methods::PaymentMethodResponse,
         api_models::payment_methods::PaymentMethodResponseData,
-        api_models::payment_methods::CustomerPaymentMethod,
+        api_models::payment_methods::CustomerPaymentMethodResponseItem,
+        api_models::payment_methods::PaymentMethodResponseItem,
         api_models::payment_methods::PaymentMethodListRequest,
-        api_models::payment_methods::PaymentMethodListResponse,
+        api_models::payment_methods::PaymentMethodListResponseForSession,
+        api_models::payment_methods::CustomerPaymentMethodsListResponse,
         api_models::payment_methods::ResponsePaymentMethodsEnabled,
         api_models::payment_methods::PaymentMethodSubtypeSpecificData,
         api_models::payment_methods::ResponsePaymentMethodTypes,
@@ -242,7 +244,6 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payment_methods::CardNetworkTypes,
         api_models::payment_methods::BankDebitTypes,
         api_models::payment_methods::BankTransferTypes,
-        api_models::payment_methods::CustomerPaymentMethodsListResponse,
         api_models::payment_methods::PaymentMethodDeleteResponse,
         api_models::payment_methods::PaymentMethodUpdate,
         api_models::payment_methods::PaymentMethodUpdateData,
diff --git a/crates/openapi/src/routes/payment_method.rs b/crates/openapi/src/routes/payment_method.rs
index fd16b2ee2b2..2e991063644 100644
--- a/crates/openapi/src/routes/payment_method.rs
+++ b/crates/openapi/src/routes/payment_method.rs
@@ -401,7 +401,7 @@ pub fn payment_method_session_retrieve() {}
         ("id" = String, Path, description = "The unique identifier for the Payment Method Session"),
     ),
     responses(
-        (status = 200, description = "The payment method session is retrieved successfully", body = PaymentMethodListResponse),
+        (status = 200, description = "The payment method session is retrieved successfully", body = PaymentMethodListResponseForSession),
         (status = 404, description = "The request is invalid")
     ),
     tag = "Payment Method Session",
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 96ac030f57f..0350a507aeb 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -37,6 +37,8 @@ use diesel_models::{
     enums, GenericLinkNew, PaymentMethodCollectLink, PaymentMethodCollectLinkData,
 };
 use error_stack::{report, ResultExt};
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use futures::TryStreamExt;
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
 use hyperswitch_domain_models::api::{GenericLinks, GenericLinksData};
 #[cfg(all(
@@ -899,7 +901,8 @@ pub async fn create_payment_method(
     merchant_context: &domain::MerchantContext,
     profile: &domain::Profile,
 ) -> RouterResponse<api::PaymentMethodResponse> {
-    let response =
+    // payment_method is for internal use, can never be populated in response
+    let (response, _payment_method) =
         create_payment_method_core(state, request_state, req, merchant_context, profile).await?;
 
     Ok(services::ApplicationResponse::Json(response))
@@ -913,7 +916,7 @@ pub async fn create_payment_method_core(
     req: api::PaymentMethodCreate,
     merchant_context: &domain::MerchantContext,
     profile: &domain::Profile,
-) -> RouterResult<api::PaymentMethodResponse> {
+) -> RouterResult<(api::PaymentMethodResponse, domain::PaymentMethod)> {
     use common_utils::ext_traits::ValueExt;
 
     req.validate()?;
@@ -1055,7 +1058,7 @@ pub async fn create_payment_method_core(
         }
     }?;
 
-    Ok(response)
+    Ok((response, payment_method))
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -1345,7 +1348,7 @@ pub async fn list_payment_methods_for_session(
     merchant_context: domain::MerchantContext,
     profile: domain::Profile,
     payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
-) -> RouterResponse<api::PaymentMethodListResponse> {
+) -> RouterResponse<api::PaymentMethodListResponseForSession> {
     let key_manager_state = &(&state).into();
 
     let db = &*state.store;
@@ -1371,7 +1374,7 @@ pub async fn list_payment_methods_for_session(
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("error when fetching merchant connector accounts")?;
 
-    let customer_payment_methods = list_customer_payment_method_core(
+    let customer_payment_methods = list_customer_payment_methods_core(
         &state,
         &merchant_context,
         &payment_method_session.customer_id,
@@ -1382,7 +1385,7 @@ pub async fn list_payment_methods_for_session(
         hyperswitch_domain_models::merchant_connector_account::FlattenedPaymentMethodsEnabled::from_payment_connectors_list(payment_connector_accounts)
             .perform_filtering()
             .get_required_fields(RequiredFieldsInput::new(state.conf.required_fields.clone()))
-            .generate_response(customer_payment_methods.customer_payment_methods);
+            .generate_response_for_session(customer_payment_methods);
 
     Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
         response,
@@ -1395,9 +1398,9 @@ pub async fn list_saved_payment_methods_for_customer(
     state: SessionState,
     merchant_context: domain::MerchantContext,
     customer_id: id_type::GlobalCustomerId,
-) -> RouterResponse<api::CustomerPaymentMethodsListResponse> {
+) -> RouterResponse<payment_methods::CustomerPaymentMethodsListResponse> {
     let customer_payment_methods =
-        list_customer_payment_method_core(&state, &merchant_context, &customer_id).await?;
+        list_payment_methods_core(&state, &merchant_context, &customer_id).await?;
 
     Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
         customer_payment_methods,
@@ -1628,10 +1631,10 @@ struct RequiredFieldsForEnabledPaymentMethodTypes(Vec<RequiredFieldsForEnabledPa
 
 #[cfg(feature = "v2")]
 impl RequiredFieldsForEnabledPaymentMethodTypes {
-    fn generate_response(
+    fn generate_response_for_session(
         self,
-        customer_payment_methods: Vec<payment_methods::CustomerPaymentMethod>,
-    ) -> payment_methods::PaymentMethodListResponse {
+        customer_payment_methods: Vec<payment_methods::CustomerPaymentMethodResponseItem>,
+    ) -> payment_methods::PaymentMethodListResponseForSession {
         let response_payment_methods = self
             .0
             .into_iter()
@@ -1645,7 +1648,7 @@ impl RequiredFieldsForEnabledPaymentMethodTypes {
             )
             .collect();
 
-        payment_methods::PaymentMethodListResponse {
+        payment_methods::PaymentMethodListResponseForSession {
             payment_methods_enabled: response_payment_methods,
             customer_payment_methods,
         }
@@ -1798,7 +1801,9 @@ pub async fn create_pm_additional_data_update(
         .map(From::from);
 
     let pm_update = storage::PaymentMethodUpdate::GenericUpdate {
-        status: Some(enums::PaymentMethodStatus::Active),
+        // A new payment method is created with inactive state
+        // It will be marked active after payment succeeds
+        status: Some(enums::PaymentMethodStatus::Inactive),
         locker_id: vault_id,
         payment_method_type_v2: payment_method_type,
         payment_method_subtype,
@@ -2006,8 +2011,6 @@ pub async fn vault_payment_method(
     }
 }
 
-// TODO: check if this function will be used for listing the customer payment methods for payments
-#[allow(unused)]
 #[cfg(all(
     feature = "v2",
     feature = "payment_methods_v2",
@@ -2029,7 +2032,7 @@ fn get_pm_list_context(
                 card_details: api::CardDetailFromLocker::from(card),
                 token_data: is_payment_associated.then_some(
                     storage::PaymentTokenData::permanent_card(
-                        Some(payment_method.get_id().clone()),
+                        payment_method.get_id().clone(),
                         payment_method
                             .locker_id
                             .as_ref()
@@ -2095,12 +2098,38 @@ fn get_pm_list_context(
     Ok(payment_method_retrieval_context)
 }
 
+#[cfg(all(
+    feature = "v2",
+    feature = "payment_methods_v2",
+    feature = "customer_v2"
+))]
+fn get_pm_list_token_data(
+    payment_method_type: enums::PaymentMethod,
+    payment_method: &domain::PaymentMethod,
+) -> Result<Option<storage::PaymentTokenData>, error_stack::Report<errors::ApiErrorResponse>> {
+    let pm_list_context = get_pm_list_context(payment_method_type, payment_method, true)?
+        .get_required_value("PaymentMethodListContext")?;
+
+    match pm_list_context {
+        PaymentMethodListContext::Card {
+            card_details: _,
+            token_data,
+        } => Ok(token_data),
+        PaymentMethodListContext::Bank { token_data } => Ok(token_data),
+        PaymentMethodListContext::BankTransfer {
+            bank_transfer_details: _,
+            token_data,
+        } => Ok(token_data),
+        PaymentMethodListContext::TemporaryToken { token_data } => Ok(token_data),
+    }
+}
+
 #[cfg(all(feature = "v2", feature = "olap"))]
-pub async fn list_customer_payment_method_core(
+pub async fn list_payment_methods_core(
     state: &SessionState,
     merchant_context: &domain::MerchantContext,
     customer_id: &id_type::GlobalCustomerId,
-) -> RouterResult<api::CustomerPaymentMethodsListResponse> {
+) -> RouterResult<payment_methods::CustomerPaymentMethodsListResponse> {
     let db = &*state.store;
     let key_manager_state = &(state).into();
 
@@ -2120,16 +2149,84 @@ pub async fn list_customer_payment_method_core(
     let customer_payment_methods = saved_payment_methods
         .into_iter()
         .map(ForeignTryFrom::foreign_try_from)
-        .collect::<Result<Vec<api::CustomerPaymentMethod>, _>>()
+        .collect::<Result<Vec<payment_methods::PaymentMethodResponseItem>, _>>()
         .change_context(errors::ApiErrorResponse::InternalServerError)?;
 
-    let response = api::CustomerPaymentMethodsListResponse {
+    let response = payment_methods::CustomerPaymentMethodsListResponse {
         customer_payment_methods,
     };
 
     Ok(response)
 }
 
+#[cfg(all(feature = "v2", feature = "oltp"))]
+pub async fn list_customer_payment_methods_core(
+    state: &SessionState,
+    merchant_context: &domain::MerchantContext,
+    customer_id: &id_type::GlobalCustomerId,
+) -> RouterResult<Vec<payment_methods::CustomerPaymentMethodResponseItem>> {
+    let db = &*state.store;
+    let key_manager_state = &(state).into();
+
+    let saved_payment_methods = db
+        .find_payment_method_by_global_customer_id_merchant_id_status(
+            key_manager_state,
+            merchant_context.get_merchant_key_store(),
+            customer_id,
+            merchant_context.get_merchant_account().get_id(),
+            common_enums::PaymentMethodStatus::Active,
+            None,
+            merchant_context.get_merchant_account().storage_scheme,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
+
+    let mut customer_payment_methods = Vec::new();
+
+    let payment_method_results: Result<Vec<_>, error_stack::Report<errors::ApiErrorResponse>> =
+        saved_payment_methods
+            .into_iter()
+            .map(|pm| async move {
+                let parent_payment_method_token = generate_id(consts::ID_LENGTH, "token");
+
+                // For payment methods that are active we should always have the payment method type
+                let payment_method_type = pm
+                    .payment_method_type
+                    .get_required_value("payment_method_type")?;
+
+                let intent_fulfillment_time = common_utils::consts::DEFAULT_INTENT_FULFILLMENT_TIME;
+
+                let token_data = get_pm_list_token_data(payment_method_type, &pm)?;
+
+                if let Some(token_data) = token_data {
+                    pm_routes::ParentPaymentMethodToken::create_key_for_token((
+                        &parent_payment_method_token,
+                        payment_method_type,
+                    ))
+                    .insert(intent_fulfillment_time, token_data, state)
+                    .await?;
+
+                    let final_pm = api::CustomerPaymentMethodResponseItem::foreign_try_from((
+                        pm,
+                        parent_payment_method_token,
+                    ))
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed to convert payment method to response format")?;
+
+                    Ok(Some(final_pm))
+                } else {
+                    Ok(None)
+                }
+            })
+            .collect::<futures::stream::FuturesUnordered<_>>()
+            .try_collect::<Vec<_>>()
+            .await;
+
+    customer_payment_methods.extend(payment_method_results?.into_iter().flatten());
+
+    Ok(customer_payment_methods)
+}
+
 #[cfg(all(feature = "v2", feature = "olap"))]
 pub async fn get_total_payment_method_count_core(
     state: &SessionState,
@@ -2184,6 +2281,48 @@ pub async fn retrieve_payment_method(
         .map(services::ApplicationResponse::Json)
 }
 
+// TODO: When we separate out microservices, this function will be an endpoint in payment_methods
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn update_payment_method_status_internal(
+    state: &SessionState,
+    key_store: &domain::MerchantKeyStore,
+    storage_scheme: enums::MerchantStorageScheme,
+    status: enums::PaymentMethodStatus,
+    payment_method_id: &id_type::GlobalPaymentMethodId,
+) -> RouterResult<domain::PaymentMethod> {
+    let db = &*state.store;
+    let key_manager_state = &state.into();
+
+    let payment_method = db
+        .find_payment_method(
+            &((state).into()),
+            key_store,
+            payment_method_id,
+            storage_scheme,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
+
+    let pm_update = storage::PaymentMethodUpdate::StatusUpdate {
+        status: Some(status),
+    };
+
+    let updated_pm = db
+        .update_payment_method(
+            key_manager_state,
+            key_store,
+            payment_method.clone(),
+            pm_update,
+            storage_scheme,
+        )
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to update payment method in db")?;
+
+    Ok(updated_pm)
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[instrument(skip_all)]
 pub async fn update_payment_method(
@@ -2896,7 +3035,7 @@ pub async fn payment_methods_session_confirm(
     )
     .attach_printable("Failed to create payment method request")?;
 
-    let payment_method = create_payment_method_core(
+    let (payment_method_response, _payment_method) = create_payment_method_core(
         &state,
         &req_state,
         create_payment_method_request.clone(),
@@ -2913,7 +3052,7 @@ pub async fn payment_methods_session_confirm(
             let zero_auth_request = construct_zero_auth_payments_request(
                 &request,
                 &payment_method_session,
-                &payment_method,
+                &payment_method_response,
             )?;
             let payments_response = Box::pin(create_zero_auth_payment(
                 state.clone(),
@@ -2936,7 +3075,7 @@ pub async fn payment_methods_session_confirm(
                 merchant_context.clone(),
                 profile.clone(),
                 &create_payment_method_request.clone(),
-                &payment_method,
+                &payment_method_response,
                 &payment_method_session,
             ))
             .await?;
@@ -3013,7 +3152,7 @@ impl pm_types::SavedPMLPaymentsInfo {
         &self,
         state: &SessionState,
         parent_payment_method_token: Option<String>,
-        pma: &api::CustomerPaymentMethod,
+        pma: &api::CustomerPaymentMethodResponseItem,
         pm_list_context: PaymentMethodListContext,
     ) -> RouterResult<()> {
         let token = parent_payment_method_token
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 47d74d29deb..539298ac534 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -4591,7 +4591,7 @@ pub async fn perform_surcharge_ops(
     _state: &routes::SessionState,
     _merchant_context: &domain::MerchantContext,
     _business_profile: Option<Profile>,
-    _response: &mut api::CustomerPaymentMethodsListResponse,
+    _response: &mut api_models::payment_methods::CustomerPaymentMethodsListResponse,
 ) -> Result<(), error_stack::Report<errors::ApiErrorResponse>> {
     todo!()
 }
diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs
index fd36f6d0ab7..3e64e846153 100644
--- a/crates/router/src/core/payment_methods/transformers.rs
+++ b/crates/router/src/core/payment_methods/transformers.rs
@@ -1,4 +1,6 @@
 pub use ::payment_methods::controller::{DataDuplicationCheck, DeleteCardResp};
+#[cfg(feature = "v2")]
+use api_models::payment_methods::PaymentMethodResponseItem;
 use api_models::{enums as api_enums, payment_methods::Card};
 use common_utils::{
     ext_traits::{Encode, StringExt},
@@ -930,7 +932,73 @@ pub fn mk_card_value2(
 }
 
 #[cfg(feature = "v2")]
-impl transformers::ForeignTryFrom<domain::PaymentMethod> for api::CustomerPaymentMethod {
+impl transformers::ForeignTryFrom<(domain::PaymentMethod, String)>
+    for api::CustomerPaymentMethodResponseItem
+{
+    type Error = error_stack::Report<errors::ValidationError>;
+
+    fn foreign_try_from(
+        (item, payment_token): (domain::PaymentMethod, String),
+    ) -> Result<Self, Self::Error> {
+        // For payment methods that are active we should always have the payment method subtype
+        let payment_method_subtype =
+            item.payment_method_subtype
+                .ok_or(errors::ValidationError::MissingRequiredField {
+                    field_name: "payment_method_subtype".to_string(),
+                })?;
+
+        // For payment methods that are active we should always have the payment method type
+        let payment_method_type =
+            item.payment_method_type
+                .ok_or(errors::ValidationError::MissingRequiredField {
+                    field_name: "payment_method_type".to_string(),
+                })?;
+
+        let payment_method_data = item
+            .payment_method_data
+            .map(|payment_method_data| payment_method_data.into_inner())
+            .map(|payment_method_data| match payment_method_data {
+                api_models::payment_methods::PaymentMethodsData::Card(
+                    card_details_payment_method,
+                ) => {
+                    let card_details = api::CardDetailFromLocker::from(card_details_payment_method);
+                    api_models::payment_methods::PaymentMethodListData::Card(card_details)
+                }
+                api_models::payment_methods::PaymentMethodsData::BankDetails(..) => todo!(),
+                api_models::payment_methods::PaymentMethodsData::WalletDetails(..) => {
+                    todo!()
+                }
+            });
+
+        let payment_method_billing = item
+            .payment_method_billing_address
+            .clone()
+            .map(|billing| billing.into_inner())
+            .map(From::from);
+
+        // TODO: check how we can get this field
+        let recurring_enabled = true;
+
+        Ok(Self {
+            id: item.id,
+            customer_id: item.customer_id,
+            payment_method_type,
+            payment_method_subtype,
+            created: item.created_at,
+            last_used_at: item.last_used_at,
+            recurring_enabled,
+            payment_method_data,
+            bank: None,
+            requires_cvv: true,
+            is_default: false,
+            billing: payment_method_billing,
+            payment_token,
+        })
+    }
+}
+
+#[cfg(feature = "v2")]
+impl transformers::ForeignTryFrom<domain::PaymentMethod> for PaymentMethodResponseItem {
     type Error = error_stack::Report<errors::ValidationError>;
 
     fn foreign_try_from(item: domain::PaymentMethod) -> Result<Self, Self::Error> {
diff --git a/crates/router/src/core/payment_methods/utils.rs b/crates/router/src/core/payment_methods/utils.rs
index 5885b830e7a..512c40fc8d2 100644
--- a/crates/router/src/core/payment_methods/utils.rs
+++ b/crates/router/src/core/payment_methods/utils.rs
@@ -6,6 +6,10 @@ use api_models::{
     payment_methods::RequestPaymentMethodTypes,
 };
 use common_enums::enums;
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use common_utils::ext_traits::{OptionExt, StringExt};
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use error_stack::ResultExt;
 use euclid::frontend::dir;
 use hyperswitch_constraint_graph as cgraph;
 use kgraph_utils::{error::KgraphError, transformers::IntoDirValue};
@@ -13,6 +17,14 @@ use masking::ExposeInterface;
 use storage_impl::redis::cache::{CacheKey, PM_FILTERS_CGRAPH_CACHE};
 
 use crate::{configs::settings, routes::SessionState};
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use crate::{
+    db::{
+        errors,
+        storage::{self, enums as storage_enums},
+    },
+    services::logger,
+};
 
 pub fn make_pm_graph(
     builder: &mut cgraph::ConstraintGraphBuilder<dir::DirValue>,
@@ -798,3 +810,63 @@ fn compile_accepted_currency_for_mca(
             .map_err(KgraphError::GraphConstructionError)?,
     ))
 }
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub(super) async fn retrieve_payment_token_data(
+    state: &SessionState,
+    token: String,
+    payment_method: Option<&storage_enums::PaymentMethod>,
+) -> errors::RouterResult<storage::PaymentTokenData> {
+    let redis_conn = state
+        .store
+        .get_redis_conn()
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to get redis connection")?;
+
+    let key = format!(
+        "pm_token_{}_{}_hyperswitch",
+        token,
+        payment_method
+            .get_required_value("payment_method")
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Payment method is required")?
+    );
+
+    let token_data_string = redis_conn
+        .get_key::<Option<String>>(&key.into())
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to fetch the token from redis")?
+        .ok_or(error_stack::Report::new(
+            errors::ApiErrorResponse::UnprocessableEntity {
+                message: "Token is invalid or expired".to_owned(),
+            },
+        ))?;
+
+    token_data_string
+        .clone()
+        .parse_struct("PaymentTokenData")
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("failed to deserialize hyperswitch token data")
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub(super) async fn delete_payment_token_data(
+    state: &SessionState,
+    key_for_token: &str,
+) -> errors::RouterResult<()> {
+    let redis_conn = state
+        .store
+        .get_redis_conn()
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to get redis connection")?;
+    match redis_conn.delete_key(&key_for_token.into()).await {
+        Ok(_) => Ok(()),
+        Err(err) => {
+            {
+                logger::error!("Error while deleting redis key: {:?}", err)
+            };
+            Ok(())
+        }
+    }
+}
diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs
index 9a2c096d66a..fbdff25107c 100644
--- a/crates/router/src/core/payment_methods/vault.rs
+++ b/crates/router/src/core/payment_methods/vault.rs
@@ -23,8 +23,8 @@ use crate::types::api::payouts;
 use crate::{
     consts,
     core::errors::{self, CustomResult, RouterResult},
-    db, logger, routes,
-    routes::metrics,
+    db, logger,
+    routes::{self, metrics},
     types::{
         api, domain,
         storage::{self, enums},
@@ -35,7 +35,8 @@ use crate::{
 use crate::{
     core::{
         errors::ConnectorErrorExt,
-        payment_methods::transformers as pm_transforms,
+        errors::StorageErrorExt,
+        payment_methods::{transformers as pm_transforms, utils},
         payments::{self as payments_core, helpers as payment_helpers},
         utils as core_utils,
     },
@@ -45,6 +46,7 @@ use crate::{
     types::{self, payment_methods as pm_types},
     utils::{ext_traits::OptionExt, ConnectorResponseExt},
 };
+
 const VAULT_SERVICE_NAME: &str = "CARD";
 
 pub struct SupplementaryVaultData {
@@ -1463,6 +1465,87 @@ pub fn get_vault_response_for_retrieve_payment_method_data<F>(
     }
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn retrieve_payment_method_from_vault_using_payment_token(
+    state: &routes::SessionState,
+    merchant_context: &domain::MerchantContext,
+    profile: &domain::Profile,
+    payment_token: &String,
+    payment_method_type: &common_enums::PaymentMethod,
+) -> RouterResult<(domain::PaymentMethod, domain::PaymentMethodVaultingData)> {
+    let pm_token_data = utils::retrieve_payment_token_data(
+        state,
+        payment_token.to_string(),
+        Some(payment_method_type),
+    )
+    .await?;
+
+    let payment_method_id = match pm_token_data {
+        storage::PaymentTokenData::PermanentCard(card_token_data) => {
+            card_token_data.payment_method_id
+        }
+        storage::PaymentTokenData::TemporaryGeneric(_) => {
+            Err(errors::ApiErrorResponse::NotImplemented {
+                message: errors::NotImplementedMessage::Reason(
+                    "TemporaryGeneric Token not implemented".to_string(),
+                ),
+            })?
+        }
+        storage::PaymentTokenData::AuthBankDebit(_) => {
+            Err(errors::ApiErrorResponse::NotImplemented {
+                message: errors::NotImplementedMessage::Reason(
+                    "AuthBankDebit Token not implemented".to_string(),
+                ),
+            })?
+        }
+    };
+    let db = &*state.store;
+    let key_manager_state = &state.into();
+
+    let storage_scheme = merchant_context.get_merchant_account().storage_scheme;
+
+    let payment_method = db
+        .find_payment_method(
+            key_manager_state,
+            merchant_context.get_merchant_key_store(),
+            &payment_method_id,
+            storage_scheme,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
+
+    let vault_data =
+        retrieve_payment_method_from_vault(state, merchant_context, profile, &payment_method)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to retrieve payment method from vault")?
+            .data;
+
+    Ok((payment_method, vault_data))
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn delete_payment_token(
+    state: &routes::SessionState,
+    key_for_token: &str,
+    intent_status: enums::IntentStatus,
+) -> RouterResult<()> {
+    if ![
+        enums::IntentStatus::RequiresCustomerAction,
+        enums::IntentStatus::RequiresMerchantAction,
+    ]
+    .contains(&intent_status)
+    {
+        utils::delete_payment_token_data(state, key_for_token)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Unable to delete payment_token")?;
+    }
+    Ok(())
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[instrument(skip_all)]
 pub async fn retrieve_payment_method_from_vault(
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 2cd9f507893..6372caa0225 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -92,6 +92,8 @@ use super::{
 use crate::core::debit_routing;
 #[cfg(feature = "frm")]
 use crate::core::fraud_check as frm_core;
+#[cfg(feature = "v2")]
+use crate::core::payment_methods::vault;
 #[cfg(feature = "v1")]
 use crate::core::routing::helpers as routing_helpers;
 #[cfg(all(feature = "v1", feature = "dynamic_routing"))]
@@ -169,6 +171,11 @@ where
     // Get the trackers related to track the state of the payment
     let operations::GetTrackerResponse { mut payment_data } = get_tracker_response;
 
+    operation
+        .to_domain()?
+        .create_or_fetch_payment_method(state, &merchant_context, profile, &mut payment_data)
+        .await?;
+
     let (_operation, customer) = operation
         .to_domain()?
         .get_customer_details(
@@ -294,6 +301,22 @@ where
         ConnectorCallType::Skip => payment_data,
     };
 
+    let payment_intent_status = payment_data.get_payment_intent().status;
+
+    // Delete the tokens after payment
+    payment_data
+        .get_payment_attempt()
+        .payment_token
+        .as_ref()
+        .zip(Some(payment_data.get_payment_attempt().payment_method_type))
+        .map(ParentPaymentMethodToken::return_key_for_token)
+        .async_map(|key_for_token| async move {
+            let _ = vault::delete_payment_token(state, &key_for_token, payment_intent_status)
+                .await
+                .inspect_err(|err| logger::error!("Failed to delete payment_token: {:?}", err));
+        })
+        .await;
+
     Ok((payment_data, req, customer, None, None))
 }
 
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index a166c54139d..a94d7322e4d 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -2482,6 +2482,10 @@ pub async fn retrieve_payment_method_from_db_with_token_data(
     }
 }
 
+#[cfg(all(
+    any(feature = "v2", feature = "v1"),
+    not(feature = "payment_methods_v2")
+))]
 pub async fn retrieve_payment_token_data(
     state: &SessionState,
     token: String,
diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs
index ebbece06850..ff873b13779 100644
--- a/crates/router/src/core/payments/operations.rs
+++ b/crates/router/src/core/payments/operations.rs
@@ -373,6 +373,17 @@ pub trait Domain<F: Clone, R, D>: Send + Sync {
         Ok(())
     }
 
+    #[cfg(feature = "v2")]
+    async fn create_or_fetch_payment_method<'a>(
+        &'a self,
+        state: &SessionState,
+        merchant_context: &domain::MerchantContext,
+        business_profile: &domain::Profile,
+        payment_data: &mut D,
+    ) -> CustomResult<(), errors::ApiErrorResponse> {
+        Ok(())
+    }
+
     // #[cfg(feature = "v2")]
     // async fn call_connector<'a, RouterDataReq>(
     //     &'a self,
diff --git a/crates/router/src/core/payments/operations/payment_confirm_intent.rs b/crates/router/src/core/payments/operations/payment_confirm_intent.rs
index 7084fc14bb8..8805710c077 100644
--- a/crates/router/src/core/payments/operations/payment_confirm_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm_intent.rs
@@ -1,9 +1,9 @@
 use api_models::{enums::FrmSuggestion, payments::PaymentsConfirmIntentRequest};
 use async_trait::async_trait;
-use common_utils::{ext_traits::Encode, types::keymanager::ToEncryptable};
+use common_utils::{ext_traits::Encode, fp_utils::when, types::keymanager::ToEncryptable};
 use error_stack::ResultExt;
 use hyperswitch_domain_models::payments::PaymentConfirmData;
-use masking::PeekInterface;
+use masking::{ExposeOptionInterface, PeekInterface};
 use router_env::{instrument, tracing};
 
 use super::{Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
@@ -11,6 +11,7 @@ use crate::{
     core::{
         admin,
         errors::{self, CustomResult, RouterResult, StorageErrorExt},
+        payment_methods,
         payments::{
             self, call_decision_manager, helpers,
             operations::{self, ValidateStatusForOperation},
@@ -225,6 +226,23 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentConfirmData<F>, PaymentsConfir
             .clone()
             .map(hyperswitch_domain_models::payment_method_data::PaymentMethodData::from);
 
+        if request.payment_token.is_some() {
+            when(
+                !matches!(
+                    payment_method_data,
+                    Some(domain::payment_method_data::PaymentMethodData::CardToken(_))
+                ),
+                || {
+                    Err(errors::ApiErrorResponse::InvalidDataValue {
+                        field_name: "payment_method_data",
+                    })
+                    .attach_printable(
+                        "payment_method_data should be card_token when a token is passed",
+                    )
+                },
+            )?;
+        };
+
         let payment_address = hyperswitch_domain_models::payment_address::PaymentAddress::new(
             payment_intent
                 .shipping_address
@@ -248,6 +266,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentConfirmData<F>, PaymentsConfir
             payment_method_data,
             payment_address,
             mandate_data: None,
+            payment_method: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse { payment_data };
@@ -347,6 +366,125 @@ impl<F: Clone + Send + Sync> Domain<F, PaymentsConfirmIntentRequest, PaymentConf
         )
         .await
     }
+
+    #[cfg(feature = "v2")]
+    async fn create_or_fetch_payment_method<'a>(
+        &'a self,
+        state: &SessionState,
+        merchant_context: &domain::MerchantContext,
+        business_profile: &domain::Profile,
+        payment_data: &mut PaymentConfirmData<F>,
+    ) -> CustomResult<(), errors::ApiErrorResponse> {
+        let (payment_method, payment_method_data) = match (
+            &payment_data.payment_attempt.payment_token,
+            &payment_data.payment_method_data,
+            &payment_data.payment_attempt.customer_acceptance,
+        ) {
+            (
+                Some(payment_token),
+                Some(domain::payment_method_data::PaymentMethodData::CardToken(card_token)),
+                None,
+            ) => {
+                let (card_cvc, card_holder_name) = {
+                    (
+                        card_token
+                            .card_cvc
+                            .clone()
+                            .ok_or(errors::ApiErrorResponse::InvalidDataValue {
+                                field_name: "card_cvc",
+                            })
+                            .attach_printable("card_cvc not provided")?,
+                        card_token.card_holder_name.clone(),
+                    )
+                };
+
+                let (payment_method, vault_data) =
+                    payment_methods::vault::retrieve_payment_method_from_vault_using_payment_token(
+                        state,
+                        merchant_context,
+                        business_profile,
+                        payment_token,
+                        &payment_data.payment_attempt.payment_method_type,
+                    )
+                    .await
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed to retrieve payment method from vault")?;
+
+                match vault_data {
+                    domain::vault::PaymentMethodVaultingData::Card(card_detail) => {
+                        let pm_data_from_vault =
+                            domain::payment_method_data::PaymentMethodData::Card(
+                                domain::payment_method_data::Card::from((
+                                    card_detail,
+                                    card_cvc,
+                                    card_holder_name,
+                                )),
+                            );
+
+                        (Some(payment_method), Some(pm_data_from_vault))
+                    }
+                    _ => Err(errors::ApiErrorResponse::NotImplemented {
+                        message: errors::NotImplementedMessage::Reason(
+                            "Non-card Tokenization not implemented".to_string(),
+                        ),
+                    })?,
+                }
+            }
+
+            (Some(_payment_token), _, _) => Err(errors::ApiErrorResponse::InvalidDataValue {
+                field_name: "payment_method_data",
+            })
+            .attach_printable("payment_method_data should be card_token when a token is passed")?,
+
+            (None, Some(domain::PaymentMethodData::Card(card)), Some(_customer_acceptance)) => {
+                let customer_id = match &payment_data.payment_intent.customer_id {
+                    Some(customer_id) => customer_id.clone(),
+                    None => {
+                        return Err(errors::ApiErrorResponse::InvalidDataValue {
+                            field_name: "customer_id",
+                        })
+                        .attach_printable("customer_id not provided");
+                    }
+                };
+
+                let pm_create_data =
+                    api::PaymentMethodCreateData::Card(api::CardDetail::from(card.clone()));
+
+                let req = api::PaymentMethodCreate {
+                    payment_method_type: payment_data.payment_attempt.payment_method_type,
+                    payment_method_subtype: payment_data.payment_attempt.payment_method_subtype,
+                    metadata: None,
+                    customer_id,
+                    payment_method_data: pm_create_data,
+                    billing: None,
+                    psp_tokenization: None,
+                    network_tokenization: None,
+                };
+
+                let (_pm_response, payment_method) = payment_methods::create_payment_method_core(
+                    state,
+                    &state.get_req_state(),
+                    req,
+                    merchant_context,
+                    business_profile,
+                )
+                .await?;
+
+                // Don't modify payment_method_data in this case, only the payment_method and payment_method_id
+                (Some(payment_method), None)
+            }
+            _ => (None, None), // Pass payment_data unmodified for any other case
+        };
+
+        if let Some(pm_data) = payment_method_data {
+            payment_data.update_payment_method_data(pm_data);
+        }
+        if let Some(pm) = payment_method {
+            payment_data.update_payment_method_and_pm_id(pm.get_id().clone(), pm);
+        }
+
+        Ok(())
+    }
 }
 
 #[async_trait]
@@ -400,12 +538,26 @@ impl<F: Clone + Sync> UpdateTracker<F, PaymentConfirmData<F>, PaymentsConfirmInt
 
         let authentication_type = payment_data.payment_attempt.authentication_type;
 
-        let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntent {
-            status: attempt_status,
-            updated_by: storage_scheme.to_string(),
-            connector,
-            merchant_connector_id,
-            authentication_type,
+        let payment_attempt_update = match &payment_data.payment_method {
+            Some(payment_method) => {
+                hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentTokenized {
+                    status: attempt_status,
+                    updated_by: storage_scheme.to_string(),
+                    connector,
+                    merchant_connector_id,
+                    authentication_type,
+                    payment_method_id : payment_method.get_id().clone()
+                }
+            }
+            None => {
+                hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntent {
+                    status: attempt_status,
+                    updated_by: storage_scheme.to_string(),
+                    connector,
+                    merchant_connector_id,
+                    authentication_type,
+                }
+            }
         };
 
         let updated_payment_intent = db
diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs
index 40285ee5ce4..41d494989b9 100644
--- a/crates/router/src/core/payments/operations/payment_response.rs
+++ b/crates/router/src/core/payments/operations/payment_response.rs
@@ -2541,9 +2541,55 @@ impl<F: Clone> PostUpdateTracker<F, PaymentConfirmData<F>, types::PaymentsAuthor
             .change_context(errors::ApiErrorResponse::InternalServerError)
             .attach_printable("Unable to update payment attempt")?;
 
+        let attempt_status = updated_payment_attempt.status;
+
         payment_data.payment_intent = updated_payment_intent;
         payment_data.payment_attempt = updated_payment_attempt;
 
+        if let Some(payment_method) = &payment_data.payment_method {
+            match attempt_status {
+                common_enums::AttemptStatus::AuthenticationFailed
+                | common_enums::AttemptStatus::RouterDeclined
+                | common_enums::AttemptStatus::AuthorizationFailed
+                | common_enums::AttemptStatus::Voided
+                | common_enums::AttemptStatus::VoidInitiated
+                | common_enums::AttemptStatus::CaptureFailed
+                | common_enums::AttemptStatus::VoidFailed
+                | common_enums::AttemptStatus::AutoRefunded
+                | common_enums::AttemptStatus::Unresolved
+                | common_enums::AttemptStatus::Pending
+                | common_enums::AttemptStatus::Failure => (),
+
+                common_enums::AttemptStatus::Started
+                | common_enums::AttemptStatus::AuthenticationPending
+                | common_enums::AttemptStatus::AuthenticationSuccessful
+                | common_enums::AttemptStatus::Authorized
+                | common_enums::AttemptStatus::Charged
+                | common_enums::AttemptStatus::Authorizing
+                | common_enums::AttemptStatus::CodInitiated
+                | common_enums::AttemptStatus::PartialCharged
+                | common_enums::AttemptStatus::PartialChargedAndChargeable
+                | common_enums::AttemptStatus::CaptureInitiated
+                | common_enums::AttemptStatus::PaymentMethodAwaited
+                | common_enums::AttemptStatus::ConfirmationAwaited
+                | common_enums::AttemptStatus::DeviceDataCollectionPending => {
+                    let pm_update_status = enums::PaymentMethodStatus::Active;
+
+                    // payment_methods microservice call
+                    payment_methods::update_payment_method_status_internal(
+                        state,
+                        key_store,
+                        storage_scheme,
+                        pm_update_status,
+                        payment_method.get_id(),
+                    )
+                    .await
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed to update payment method status")?;
+                }
+            }
+        }
+
         Ok(payment_data)
     }
 }
diff --git a/crates/router/src/core/payments/operations/proxy_payments_intent.rs b/crates/router/src/core/payments/operations/proxy_payments_intent.rs
index 1d7fb108b30..9829c109440 100644
--- a/crates/router/src/core/payments/operations/proxy_payments_intent.rs
+++ b/crates/router/src/core/payments/operations/proxy_payments_intent.rs
@@ -260,6 +260,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentConfirmData<F>, ProxyPaymentsR
             payment_method_data: Some(PaymentMethodData::MandatePayment),
             payment_address,
             mandate_data: Some(mandate_data_input),
+            payment_method: None,
         };
 
         let get_trackers_response = operations::GetTrackerResponse { payment_data };
diff --git a/crates/router/src/core/payments/payment_methods.rs b/crates/router/src/core/payments/payment_methods.rs
index 887bd078914..46c88e76a06 100644
--- a/crates/router/src/core/payments/payment_methods.rs
+++ b/crates/router/src/core/payments/payment_methods.rs
@@ -5,7 +5,7 @@ use common_utils::{ext_traits::OptionExt, id_type};
 use error_stack::ResultExt;
 
 use super::errors;
-use crate::{db::errors::StorageErrorExt, routes, types::domain};
+use crate::{core::payment_methods, db::errors::StorageErrorExt, routes, types::domain};
 
 #[cfg(all(
     feature = "v2",
@@ -46,12 +46,24 @@ pub async fn list_payment_methods(
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("error when fetching merchant connector accounts")?;
 
+    let customer_payment_methods = match &payment_intent.customer_id {
+        Some(customer_id) => Some(
+            payment_methods::list_customer_payment_methods_core(
+                &state,
+                &merchant_context,
+                customer_id,
+            )
+            .await?,
+        ),
+        None => None,
+    };
+
     let response =
         hyperswitch_domain_models::merchant_connector_account::FlattenedPaymentMethodsEnabled::from_payment_connectors_list(payment_connector_accounts)
             .perform_filtering()
             .get_required_fields(RequiredFieldsInput::new())
             .perform_surcharge_calculation()
-            .generate_response();
+            .generate_response(customer_payment_methods);
 
     Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
         response,
@@ -119,7 +131,12 @@ struct RequiredFieldsAndSurchargeForEnabledPaymentMethodTypes(
 );
 
 impl RequiredFieldsAndSurchargeForEnabledPaymentMethodTypes {
-    fn generate_response(self) -> api_models::payments::PaymentMethodListResponseForPayments {
+    fn generate_response(
+        self,
+        customer_payment_methods: Option<
+            Vec<api_models::payment_methods::CustomerPaymentMethodResponseItem>,
+        >,
+    ) -> api_models::payments::PaymentMethodListResponseForPayments {
         let response_payment_methods = self
             .0
             .into_iter()
@@ -136,7 +153,7 @@ impl RequiredFieldsAndSurchargeForEnabledPaymentMethodTypes {
 
         api_models::payments::PaymentMethodListResponseForPayments {
             payment_methods_enabled: response_payment_methods,
-            customer_payment_methods: None,
+            customer_payment_methods,
         }
     }
 }
diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs
index 0efbd655772..1e8969d3727 100644
--- a/crates/router/src/routes/payment_methods.rs
+++ b/crates/router/src/routes/payment_methods.rs
@@ -1044,6 +1044,17 @@ impl ParentPaymentMethodToken {
             ),
         }
     }
+
+    #[cfg(feature = "v2")]
+    pub fn return_key_for_token(
+        (parent_pm_token, payment_method): (&String, api_models::enums::PaymentMethod),
+    ) -> String {
+        format!(
+            "pm_token_{}_{}_hyperswitch",
+            parent_pm_token, payment_method
+        )
+    }
+
     pub async fn insert(
         &self,
         fulfillment_time: i64,
diff --git a/crates/router/src/types/api/payment_methods.rs b/crates/router/src/types/api/payment_methods.rs
index 09dd783e483..ecc3ec35edf 100644
--- a/crates/router/src/types/api/payment_methods.rs
+++ b/crates/router/src/types/api/payment_methods.rs
@@ -1,19 +1,18 @@
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 pub use api_models::payment_methods::{
     CardDetail, CardDetailFromLocker, CardDetailsPaymentMethod, CardNetworkTokenizeRequest,
-    CardNetworkTokenizeResponse, CardType, CustomerPaymentMethod,
-    CustomerPaymentMethodsListResponse, DeleteTokenizeByTokenRequest, GetTokenizePayloadRequest,
-    GetTokenizePayloadResponse, ListCountriesCurrenciesRequest, MigrateCardDetail,
-    NetworkTokenDetailsPaymentMethod, NetworkTokenDetailsResponse, NetworkTokenResponse,
-    PaymentMethodCollectLinkRenderRequest, PaymentMethodCollectLinkRequest, PaymentMethodCreate,
-    PaymentMethodCreateData, PaymentMethodDeleteResponse, PaymentMethodId,
-    PaymentMethodIntentConfirm, PaymentMethodIntentCreate, PaymentMethodListData,
-    PaymentMethodListRequest, PaymentMethodListResponse, PaymentMethodMigrate,
-    PaymentMethodMigrateResponse, PaymentMethodResponse, PaymentMethodResponseData,
-    PaymentMethodUpdate, PaymentMethodUpdateData, PaymentMethodsData, TokenDataResponse,
-    TokenDetailsResponse, TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1,
-    TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2,
-    TotalPaymentMethodCountResponse,
+    CardNetworkTokenizeResponse, CardType, CustomerPaymentMethodResponseItem,
+    DeleteTokenizeByTokenRequest, GetTokenizePayloadRequest, GetTokenizePayloadResponse,
+    ListCountriesCurrenciesRequest, MigrateCardDetail, NetworkTokenDetailsPaymentMethod,
+    NetworkTokenDetailsResponse, NetworkTokenResponse, PaymentMethodCollectLinkRenderRequest,
+    PaymentMethodCollectLinkRequest, PaymentMethodCreate, PaymentMethodCreateData,
+    PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodIntentConfirm,
+    PaymentMethodIntentCreate, PaymentMethodListData, PaymentMethodListRequest,
+    PaymentMethodListResponseForSession, PaymentMethodMigrate, PaymentMethodMigrateResponse,
+    PaymentMethodResponse, PaymentMethodResponseData, PaymentMethodUpdate, PaymentMethodUpdateData,
+    PaymentMethodsData, TokenDataResponse, TokenDetailsResponse, TokenizePayloadEncrypted,
+    TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1,
+    TokenizedWalletValue2, TotalPaymentMethodCountResponse,
 };
 #[cfg(all(
     any(feature = "v2", feature = "v1"),
diff --git a/crates/router/src/types/storage/payment_method.rs b/crates/router/src/types/storage/payment_method.rs
index 21c15c23b3c..ff12d890df4 100644
--- a/crates/router/src/types/storage/payment_method.rs
+++ b/crates/router/src/types/storage/payment_method.rs
@@ -29,7 +29,7 @@ pub struct CardTokenData {
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 pub struct CardTokenData {
-    pub payment_method_id: Option<common_utils::id_type::GlobalPaymentMethodId>,
+    pub payment_method_id: common_utils::id_type::GlobalPaymentMethodId,
     pub locker_id: Option<String>,
     pub token: String,
 }
@@ -53,6 +53,7 @@ pub struct WalletTokenData {
 
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 #[serde(tag = "kind", rename_all = "snake_case")]
+#[cfg(feature = "v1")]
 pub enum PaymentTokenData {
     // The variants 'Temporary' and 'Permanent' are added for backwards compatibility
     // with any tokenized data present in Redis at the time of deployment of this change
@@ -64,6 +65,15 @@ pub enum PaymentTokenData {
     WalletToken(WalletTokenData),
 }
 
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[serde(tag = "kind", rename_all = "snake_case")]
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub enum PaymentTokenData {
+    TemporaryGeneric(GenericTokenData),
+    PermanentCard(CardTokenData),
+    AuthBankDebit(payment_methods::BankAccountTokenData),
+}
+
 impl PaymentTokenData {
     #[cfg(all(
         any(feature = "v1", feature = "v2"),
@@ -85,7 +95,7 @@ impl PaymentTokenData {
 
     #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
     pub fn permanent_card(
-        payment_method_id: Option<common_utils::id_type::GlobalPaymentMethodId>,
+        payment_method_id: common_utils::id_type::GlobalPaymentMethodId,
         locker_id: Option<String>,
         token: String,
     ) -> Self {
@@ -100,13 +110,20 @@ impl PaymentTokenData {
         Self::TemporaryGeneric(GenericTokenData { token })
     }
 
+    #[cfg(feature = "v1")]
     pub fn wallet_token(payment_method_id: String) -> Self {
         Self::WalletToken(WalletTokenData { payment_method_id })
     }
 
+    #[cfg(feature = "v1")]
     pub fn is_permanent_card(&self) -> bool {
         matches!(self, Self::PermanentCard(_) | Self::Permanent(_))
     }
+
+    #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+    pub fn is_permanent_card(&self) -> bool {
+        matches!(self, Self::PermanentCard(_))
+    }
 }
 
 #[cfg(all(
@@ -126,6 +143,7 @@ pub struct PaymentMethodListContext {
 pub enum PaymentMethodListContext {
     Card {
         card_details: api::CardDetailFromLocker,
+        // TODO: Why can't these fields be mandatory?
         token_data: Option<PaymentTokenData>,
     },
     Bank {
diff --git a/crates/router/src/workflows/revenue_recovery.rs b/crates/router/src/workflows/revenue_recovery.rs
index af27d6f45d1..792251de496 100644
--- a/crates/router/src/workflows/revenue_recovery.rs
+++ b/crates/router/src/workflows/revenue_recovery.rs
@@ -85,13 +85,13 @@ impl ProcessTrackerWorkflow<SessionState> for ExecutePcrWorkflow {
 
         match process.name.as_deref() {
             Some("EXECUTE_WORKFLOW") => {
-                pcr::perform_execute_payment(
+                Box::pin(pcr::perform_execute_payment(
                     state,
                     &process,
                     &tracking_data,
                     &revenue_recovery_payment_data,
                     &payment_data.payment_intent,
-                )
+                ))
                 .await
             }
             Some("PSYNC_WORKFLOW") => {

## 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 -->
- Added a field `payment_token` to customer PML response
- During `/confirm-intent`, in case of card, an inactive payment method method is created before `call_conector_service`
- After the payment has completed, depending on its status the payment method is marked active
- Added support for confirming a payment using `payment_token` and `card_cvc`

### Additional Changes

- [x] 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).
-->
Closes #8089 

## 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)?
-->
1. Confirm Intent Request:

```
curl --location 'http://localhost:8080/v2/payments/12345_pay_01971c02c9f176a3b60be16df712bfc3/confirm-intent' \
--header 'x-client-secret: cs_01971c02ca147f11baea8a2521618052' \
--header 'x-profile-id: pro_W5FEDaNZ8OqqVDgFXgfg' \
--header 'Authorization: publishable-key=pk_dev_08e48a189e584123be3657ad34e1fb74,client-secret=cs_01971c02ca147f11baea8a2521618052' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_08e48a189e584123be3657ad34e1fb74' \
--data '{
    "payment_method_data": {
        "card": {
            "card_number": "4242424242424242",
            "card_exp_month": "10",
            "card_exp_year": "25",
            "card_holder_name": "John Doe",
            "card_cvc": "100"
        }
    },
    "customer_acceptance": {
        "acceptance_type": "online",
        "accepted_at": "2025-05-10T10:11:12Z",
        "online": null
    },
    "payment_method_type": "card",
    "payment_method_subtype": "card"
}'
```

2. Confirm Intent Response:

```json
{
    "id": "12345_pay_01971677d7ea7c80a137ddcb47221e17",
    "status": "succeeded",
    "amount": {
        "order_amount": 100,
        "currency": "USD",
        "shipping_cost": null,
        "order_tax_amount": null,
        "external_tax_calculation": "skip",
        "surcharge_calculation": "skip",
        "surcharge_amount": null,
        "tax_on_surcharge": null,
        "net_amount": 100,
        "amount_to_capture": null,
        "amount_capturable": 0,
        "amount_captured": 100
    },
    "customer_id": "12345_cus_01971677c68c79d1be4297b6565164fb",
    "connector": "stripe",
    "created": "2025-05-28T10:37:22.297Z",
    "payment_method_data": {
        "billing": null
    },
    "payment_method_type": "card",
    "payment_method_subtype": "card",
    "connector_transaction_id": "pi_3RThMRD5R7gDAGff03fgp3sK",
    "connector_reference_id": null,
    "merchant_connector_id": "mca_zi4k2xVeD6hTCWqHxDeX",
    "browser_info": null,
    "error": null,
    "shipping": null,
    "billing": null,
    "attempts": null,
    "connector_token_details": {
        "token": "pm_1RThMRD5R7gDAGffyr5YF1e5",
        "connector_token_request_reference_id": "rmuFSW2YVDX2PHEnpU"
    },
    "payment_method_id": "12345_pm_01971677e50c7aa29a4ec01584df07dc",
    "next_action": null,
    "return_url": "https://google.com/success",
    "authentication_type": "no_three_ds",
    "authentication_type_applied": "no_three_ds",
    "is_iframe_redirection_enabled": null
}
```

3. Customer PML Request:

```
curl --location 'http://localhost:8080/v2/customers/12345_cus_01971677c68c79d1be4297b6565164fb/saved-payment-methods' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: pro_hvfcgBE4PqzQ25QRg2Y1' \
--header 'Authorization: api-key=dev_huT4fMR6cwCZL7j8pGpORZqKUGfTmWOD6ahQ6IOkmOMgJdJkVbJfYCHxpuapjpuM' \
--header 'api-key: dev_huT4fMR6cwCZL7j8pGpORZqKUGfTmWOD6ahQ6IOkmOMgJdJkVbJfYCHxpuapjpuM'
```

4. Customer PML Response:

```json
{
    "customer_payment_methods": [
        {
            "id": "12345_pm_01971677e50c7aa29a4ec01584df07dc",
            "payment_token": "token_mb4HgBeUiiDtw4p9fmsh",
            "customer_id": "12345_cus_01971677c68c79d1be4297b6565164fb",
            "payment_method_type": "card",
            "payment_method_subtype": "card",
            "recurring_enabled": true,
            "payment_method_data": {
                "card": {
                    "issuer_country": null,
                    "last4_digits": "4242",
                    "expiry_month": "10",
                    "expiry_year": "25",
                    "card_holder_name": "John Doe",
                    "card_fingerprint": null,
                    "nick_name": null,
                    "card_network": null,
                    "card_isin": null,
                    "card_issuer": null,
                    "card_type": null,
                    "saved_to_locker": true
                }
            },
            "bank": null,
            "created": "2025-05-28T10:37:25.645Z",
            "requires_cvv": true,
            "last_used_at": "2025-05-28T10:37:25.645Z",
            "is_default": false,
            "billing": null,
            "network_tokenization": null,
            "psp_tokenization_enabled": false
        }
    ]
}
```

5. Payments Confirm using token request:

```
curl --location 'http://localhost:8080/v2/payments/12345_pay_01971ae0cd847b20984cf9b465bd84ba/confirm-intent' \
--header 'x-profile-id: pro_pE7MrT231b4IhEVnTycu' \
--header 'x-client-secret: cs_01971ae0cd9170b1a05d40f837a86c8f' \
--header 'Authorization: publishable-key=pk_dev_841e89133d1246d3b53a3468ea92dd6a,client-secret=cs_01971ae0cd9170b1a05d40f837a86c8f' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_841e89133d1246d3b53a3468ea92dd6a' \
--data '{
    "payment_method_data": {
        "card_token": {
            "card_holder_name": "John Doe",
            "card_cvc": "123"
        }
    },
    "payment_method_type": "card",
    "payment_method_subtype": "card",
    "payment_token": "token_14edM60EPMfyyPvp80Ex"
    
}'
```

6. Payments Confirm using token response:

```json
{
    "id": "12345_pay_01971ae0cd847b20984cf9b465bd84ba",
    "status": "succeeded",
    "amount": {
        "order_amount": 100,
        "currency": "GBP",
        "shipping_cost": null,
        "order_tax_amount": null,
        "external_tax_calculation": "skip",
        "surcharge_calculation": "skip",
        "surcharge_amount": null,
        "tax_on_surcharge": null,
        "net_amount": 100,
        "amount_to_capture": null,
        "amount_capturable": 0,
        "amount_captured": 100
    },
    "customer_id": "12345_cus_01971adcfc007813b7bc2367e2a399b5",
    "connector": "stripe",
    "created": "2025-05-29T07:10:29.774Z",
    "payment_method_data": {
        "billing": null
    },
    "payment_method_type": "card",
    "payment_method_subtype": "card",
    "connector_transaction_id": "pi_3RU0cUD5R7gDAGff0yM3CMmF",
    "connector_reference_id": null,
    "merchant_connector_id": "mca_ZXKvjtgq3DVPfbpHW902",
    "browser_info": null,
    "error": null,
    "shipping": null,
    "billing": null,
    "attempts": null,
    "connector_token_details": {
        "token": "pm_1RU0cUD5R7gDAGff6idzjsOT",
        "connector_token_request_reference_id": "vjY55lNJYsW5G6nbPZ"
    },
    "payment_method_id": "12345_pm_01971ade17337c939cc0c2e3df36cf0e",
    "next_action": null,
    "return_url": "https://google.com/success",
    "authentication_type": "no_three_ds",
    "authentication_type_applied": "no_three_ds",
    "is_iframe_redirection_enabled": null
}
```
## Checklist
<!-- Put an `x` in the boxes that apply -->

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