Bug: Support Default Payment Method for customer



Add support for having a default payment method option for a customer. This can be used to increase conversion rates by using the preferred saved payment method for payments, reducing the friction.

Solution:
- Customers table to have a column for 'default_payment_method'
- API to set and retrieve the default PM for a customer
- If default has not been set, use the `last_used` PM as the default 
-  Customer Payment Method List to indicate the default PM
diff --git a/config/development.toml b/config/development.toml
index d69719bd419..59d73a4b8b2 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -71,7 +71,6 @@ mock_locker = true
 basilisk_host = ""
 locker_enabled = true
 
-
 [forex_api]
 call_delay = 21600
 local_fetch_retry_count = 5
diff --git a/crates/api_models/src/customers.rs b/crates/api_models/src/customers.rs
index d8c864746a8..eeb10e62286 100644
--- a/crates/api_models/src/customers.rs
+++ b/crates/api_models/src/customers.rs
@@ -73,6 +73,9 @@ pub struct CustomerResponse {
     /// object.
     #[schema(value_type = Option<Object>,example = json!({ "city": "NY", "unit": "245" }))]
     pub metadata: Option<pii::SecretSerdeValue>,
+    /// The identifier for the default payment method.
+    #[schema(max_length = 64, example = "pm_djh2837dwduh890123")]
+    pub default_payment_method_id: Option<String>,
 }
 
 #[derive(Default, Clone, Debug, Deserialize, Serialize)]
diff --git a/crates/api_models/src/events/payment.rs b/crates/api_models/src/events/payment.rs
index 32d3dc30bd8..92f69933900 100644
--- a/crates/api_models/src/events/payment.rs
+++ b/crates/api_models/src/events/payment.rs
@@ -2,7 +2,8 @@ use common_utils::events::{ApiEventMetric, ApiEventsType};
 
 use crate::{
     payment_methods::{
-        CustomerPaymentMethodsListResponse, PaymentMethodDeleteResponse, PaymentMethodListRequest,
+        CustomerDefaultPaymentMethodResponse, CustomerPaymentMethodsListResponse,
+        DefaultPaymentMethod, PaymentMethodDeleteResponse, PaymentMethodListRequest,
         PaymentMethodListResponse, PaymentMethodResponse, PaymentMethodUpdate,
     },
     payments::{
@@ -95,6 +96,16 @@ impl ApiEventMetric for PaymentMethodResponse {
 
 impl ApiEventMetric for PaymentMethodUpdate {}
 
+impl ApiEventMetric for DefaultPaymentMethod {
+    fn get_api_event_type(&self) -> Option<ApiEventsType> {
+        Some(ApiEventsType::PaymentMethod {
+            payment_method_id: self.payment_method_id.clone(),
+            payment_method: None,
+            payment_method_type: None,
+        })
+    }
+}
+
 impl ApiEventMetric for PaymentMethodDeleteResponse {
     fn get_api_event_type(&self) -> Option<ApiEventsType> {
         Some(ApiEventsType::PaymentMethod {
@@ -121,6 +132,16 @@ impl ApiEventMetric for PaymentMethodListRequest {
 
 impl ApiEventMetric for PaymentMethodListResponse {}
 
+impl ApiEventMetric for CustomerDefaultPaymentMethodResponse {
+    fn get_api_event_type(&self) -> Option<ApiEventsType> {
+        Some(ApiEventsType::PaymentMethod {
+            payment_method_id: self.default_payment_method_id.clone().unwrap_or_default(),
+            payment_method: Some(self.payment_method),
+            payment_method_type: self.payment_method_type,
+        })
+    }
+}
+
 impl ApiEventMetric for PaymentListFilterConstraints {
     fn get_api_event_type(&self) -> Option<ApiEventsType> {
         Some(ApiEventsType::ResourceListAPI)
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 83e1a2c4887..35193b958f2 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -185,6 +185,10 @@ pub struct PaymentMethodResponse {
     #[cfg(feature = "payouts")]
     #[schema(value_type = Option<Bank>)]
     pub bank_transfer: Option<payouts::Bank>,
+
+    #[schema(value_type = Option<PrimitiveDateTime>, example = "2024-02-24T11:04:09.922Z")]
+    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
+    pub last_used_at: Option<time::PrimitiveDateTime>,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
@@ -550,6 +554,10 @@ pub struct PaymentMethodListRequest {
     /// Indicates whether the payment method is eligible for card netwotks
     #[schema(value_type = Option<Vec<CardNetwork>>, example = json!(["visa", "mastercard"]))]
     pub card_networks: Option<Vec<api_enums::CardNetwork>>,
+
+    /// Indicates the limit of last used payment methods
+    #[schema(example = 1)]
+    pub limit: Option<i64>,
 }
 
 impl<'de> serde::Deserialize<'de> for PaymentMethodListRequest {
@@ -618,6 +626,9 @@ impl<'de> serde::Deserialize<'de> for PaymentMethodListRequest {
                             Some(inner) => inner.push(map.next_value()?),
                             None => output.card_networks = Some(vec![map.next_value()?]),
                         },
+                        "limit" => {
+                            set_or_reject_duplicate(&mut output.limit, "limit", map.next_value()?)?;
+                        }
                         _ => {}
                     }
                 }
@@ -731,12 +742,30 @@ pub struct PaymentMethodDeleteResponse {
     #[schema(example = true)]
     pub deleted: bool,
 }
+#[derive(Debug, serde::Serialize, ToSchema)]
+pub struct CustomerDefaultPaymentMethodResponse {
+    /// The unique identifier of the Payment method
+    #[schema(example = "card_rGK4Vi5iSW70MY7J2mIy")]
+    pub default_payment_method_id: Option<String>,
+    /// The unique identifier of the customer.
+    #[schema(example = "cus_meowerunwiuwiwqw")]
+    pub customer_id: String,
+    /// The type of payment method use for the payment.
+    #[schema(value_type = PaymentMethod,example = "card")]
+    pub payment_method: api_enums::PaymentMethod,
+    /// This is a sub-category of payment method.
+    #[schema(value_type = Option<PaymentMethodType>,example = "credit")]
+    pub payment_method_type: Option<api_enums::PaymentMethodType>,
+}
 
 #[derive(Debug, Clone, serde::Serialize, ToSchema)]
 pub struct CustomerPaymentMethod {
     /// Token for payment method in temporary card locker which gets refreshed often
     #[schema(example = "7ebf443f-a050-4067-84e5-e6f6d4800aef")]
     pub payment_token: String,
+    /// The unique identifier of the customer.
+    #[schema(example = "pm_iouuy468iyuowqs")]
+    pub payment_method_id: String,
 
     /// The unique identifier of the customer.
     #[schema(example = "cus_meowerunwiuwiwqw")]
@@ -798,6 +827,14 @@ pub struct CustomerPaymentMethod {
     /// 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 = Option<PrimitiveDateTime>,example = "2024-02-24T11:04:09.922Z")]
+    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
+    pub last_used_at: Option<time::PrimitiveDateTime>,
+    /// Indicates if the payment method has been set to default or not
+    #[schema(example = true)]
+    pub default_payment_method_set: bool,
 }
 
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
@@ -810,6 +847,11 @@ pub struct PaymentMethodId {
     pub payment_method_id: String,
 }
 
+#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)]
+pub struct DefaultPaymentMethod {
+    pub customer_id: String,
+    pub payment_method_id: String,
+}
 //------------------------------------------------TokenizeService------------------------------------------------
 #[derive(Debug, serde::Serialize, serde::Deserialize)]
 pub struct TokenizePayloadEncrypted {
diff --git a/crates/diesel_models/src/customers.rs b/crates/diesel_models/src/customers.rs
index c0cebba7755..cefb0c240ec 100644
--- a/crates/diesel_models/src/customers.rs
+++ b/crates/diesel_models/src/customers.rs
@@ -37,6 +37,7 @@ pub struct Customer {
     pub connector_customer: Option<serde_json::Value>,
     pub modified_at: PrimitiveDateTime,
     pub address_id: Option<String>,
+    pub default_payment_method_id: Option<String>,
 }
 
 #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)]
@@ -51,4 +52,5 @@ pub struct CustomerUpdateInternal {
     pub modified_at: Option<PrimitiveDateTime>,
     pub connector_customer: Option<serde_json::Value>,
     pub address_id: Option<String>,
+    pub default_payment_method_id: Option<String>,
 }
diff --git a/crates/diesel_models/src/payment_method.rs b/crates/diesel_models/src/payment_method.rs
index 09be739581e..6191a768efe 100644
--- a/crates/diesel_models/src/payment_method.rs
+++ b/crates/diesel_models/src/payment_method.rs
@@ -34,12 +34,13 @@ pub struct PaymentMethod {
     pub metadata: Option<pii::SecretSerdeValue>,
     pub payment_method_data: Option<Encryption>,
     pub locker_id: Option<String>,
+    pub last_used_at: PrimitiveDateTime,
     pub connector_mandate_details: Option<serde_json::Value>,
     pub customer_acceptance: Option<pii::SecretSerdeValue>,
     pub status: storage_enums::PaymentMethodStatus,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, Insertable, Queryable, router_derive::DebugAsDisplay)]
+#[derive(Clone, Debug, Eq, PartialEq, Insertable, router_derive::DebugAsDisplay)]
 #[diesel(table_name = payment_methods)]
 pub struct PaymentMethodNew {
     pub customer_id: String,
@@ -64,6 +65,7 @@ pub struct PaymentMethodNew {
     pub metadata: Option<pii::SecretSerdeValue>,
     pub payment_method_data: Option<Encryption>,
     pub locker_id: Option<String>,
+    pub last_used_at: PrimitiveDateTime,
     pub connector_mandate_details: Option<serde_json::Value>,
     pub customer_acceptance: Option<pii::SecretSerdeValue>,
     pub status: storage_enums::PaymentMethodStatus,
@@ -96,6 +98,7 @@ impl Default for PaymentMethodNew {
             last_modified: now,
             metadata: Option::default(),
             payment_method_data: Option::default(),
+            last_used_at: now,
             connector_mandate_details: Option::default(),
             customer_acceptance: Option::default(),
             status: storage_enums::PaymentMethodStatus::Active,
@@ -117,6 +120,9 @@ pub enum PaymentMethodUpdate {
     PaymentMethodDataUpdate {
         payment_method_data: Option<Encryption>,
     },
+    LastUsedUpdate {
+        last_used_at: PrimitiveDateTime,
+    },
 }
 
 #[derive(Clone, Debug, Default, AsChangeset, router_derive::DebugAsDisplay)]
@@ -124,6 +130,7 @@ pub enum PaymentMethodUpdate {
 pub struct PaymentMethodUpdateInternal {
     metadata: Option<serde_json::Value>,
     payment_method_data: Option<Encryption>,
+    last_used_at: Option<PrimitiveDateTime>,
 }
 
 impl PaymentMethodUpdateInternal {
@@ -140,12 +147,19 @@ impl From<PaymentMethodUpdate> for PaymentMethodUpdateInternal {
             PaymentMethodUpdate::MetadataUpdate { metadata } => Self {
                 metadata,
                 payment_method_data: None,
+                last_used_at: None,
             },
             PaymentMethodUpdate::PaymentMethodDataUpdate {
                 payment_method_data,
             } => Self {
                 metadata: None,
                 payment_method_data,
+                last_used_at: None,
+            },
+            PaymentMethodUpdate::LastUsedUpdate { last_used_at } => Self {
+                metadata: None,
+                payment_method_data: None,
+                last_used_at: Some(last_used_at),
             },
         }
     }
diff --git a/crates/diesel_models/src/query/payment_method.rs b/crates/diesel_models/src/query/payment_method.rs
index aa227962760..e3f2e511378 100644
--- a/crates/diesel_models/src/query/payment_method.rs
+++ b/crates/diesel_models/src/query/payment_method.rs
@@ -90,20 +90,16 @@ impl PaymentMethod {
         conn: &PgPooledConn,
         customer_id: &str,
         merchant_id: &str,
+        limit: Option<i64>,
     ) -> StorageResult<Vec<Self>> {
-        generics::generic_filter::<
-            <Self as HasTable>::Table,
-            _,
-            <<Self as HasTable>::Table as Table>::PrimaryKey,
-            _,
-        >(
+        generics::generic_filter::<<Self as HasTable>::Table, _, _, _>(
             conn,
             dsl::customer_id
                 .eq(customer_id.to_owned())
                 .and(dsl::merchant_id.eq(merchant_id.to_owned())),
+            limit,
             None,
-            None,
-            None,
+            Some(dsl::last_used_at.desc()),
         )
         .await
     }
@@ -114,21 +110,17 @@ impl PaymentMethod {
         customer_id: &str,
         merchant_id: &str,
         status: storage_enums::PaymentMethodStatus,
+        limit: Option<i64>,
     ) -> StorageResult<Vec<Self>> {
-        generics::generic_filter::<
-            <Self as HasTable>::Table,
-            _,
-            <<Self as HasTable>::Table as Table>::PrimaryKey,
-            _,
-        >(
+        generics::generic_filter::<<Self as HasTable>::Table, _, _, _>(
             conn,
             dsl::customer_id
                 .eq(customer_id.to_owned())
                 .and(dsl::merchant_id.eq(merchant_id.to_owned()))
                 .and(dsl::status.eq(status)),
+            limit,
             None,
-            None,
-            None,
+            Some(dsl::last_used_at.desc()),
         )
         .await
     }
diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs
index f3c6f23e086..97ef8b974dc 100644
--- a/crates/diesel_models/src/schema.rs
+++ b/crates/diesel_models/src/schema.rs
@@ -227,6 +227,8 @@ diesel::table! {
         modified_at -> Timestamp,
         #[max_length = 64]
         address_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        default_payment_method_id -> Nullable<Varchar>,
     }
 }
 
@@ -831,6 +833,7 @@ diesel::table! {
         payment_method_data -> Nullable<Bytea>,
         #[max_length = 64]
         locker_id -> Nullable<Varchar>,
+        last_used_at -> Timestamp,
         connector_mandate_details -> Nullable<Jsonb>,
         customer_acceptance -> Nullable<Jsonb>,
         #[max_length = 64]
diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs
index ef573093be5..e21797d2eef 100644
--- a/crates/openapi/src/openapi.rs
+++ b/crates/openapi/src/openapi.rs
@@ -115,6 +115,7 @@ Never share your secret api keys. Keep them guarded and secure.
         routes::customers::customers_update,
         routes::customers::customers_delete,
         routes::customers::customers_mandates_list,
+        routes::customers::default_payment_method_set_api,
 
         //Routes for payment methods
         routes::payment_method::create_payment_method_api,
@@ -188,6 +189,7 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payment_methods::CustomerPaymentMethodsListResponse,
         api_models::payment_methods::PaymentMethodDeleteResponse,
         api_models::payment_methods::PaymentMethodUpdate,
+        api_models::payment_methods::CustomerDefaultPaymentMethodResponse,
         api_models::payment_methods::CardDetailFromLocker,
         api_models::payment_methods::CardDetail,
         api_models::payment_methods::RequestPaymentMethodTypes,
@@ -374,6 +376,7 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::BrowserInformation,
         api_models::payments::PaymentCreatePaymentLinkConfig,
         api_models::payment_methods::RequiredFieldInfo,
+        api_models::payment_methods::DefaultPaymentMethod,
         api_models::payment_methods::MaskedBankDetails,
         api_models::payment_methods::SurchargeDetailsResponse,
         api_models::payment_methods::SurchargeResponse,
diff --git a/crates/openapi/src/routes/customers.rs b/crates/openapi/src/routes/customers.rs
index 19901cbbeb9..6011621fc13 100644
--- a/crates/openapi/src/routes/customers.rs
+++ b/crates/openapi/src/routes/customers.rs
@@ -116,3 +116,23 @@ pub async fn customers_list() {}
     security(("api_key" = []))
 )]
 pub async fn customers_mandates_list() {}
+
+/// Customers - Set Default Payment Method
+///
+/// Set the Payment Method as Default for the Customer.
+#[utoipa::path(
+    get,
+    path = "/{customer_id}/payment_methods/{payment_method_id}/default",
+    params (
+        ("method_id" = String, Path, description = "Set the Payment Method as Default for the Customer"),
+    ),
+    responses(
+        (status = 200, description = "Payment Method has been set as default", body =CustomerDefaultPaymentMethodResponse ),
+        (status = 400, description = "Payment Method has already been set as default for that customer"),
+        (status = 404, description = "Payment Method not found for the customer")
+    ),
+    tag = "Customer Set Default Payment Method",
+    operation_id = "Set the Payment Method as Default",
+    security(("ephemeral_key" = []))
+)]
+pub async fn default_payment_method_set_api() {}
diff --git a/crates/router/src/core/customers.rs b/crates/router/src/core/customers.rs
index 521e3a22166..02127efe6de 100644
--- a/crates/router/src/core/customers.rs
+++ b/crates/router/src/core/customers.rs
@@ -108,6 +108,7 @@ pub async fn create_customer(
             address_id: address.clone().map(|addr| addr.address_id),
             created_at: common_utils::date_time::now(),
             modified_at: common_utils::date_time::now(),
+            default_payment_method_id: None,
         })
     }
     .await
@@ -208,6 +209,7 @@ pub async fn delete_customer(
         .find_payment_method_by_customer_id_merchant_id_list(
             &req.customer_id,
             &merchant_account.merchant_id,
+            None,
         )
         .await
     {
diff --git a/crates/router/src/core/locker_migration.rs b/crates/router/src/core/locker_migration.rs
index 1347bb8ffd0..c5ddb1ed6bb 100644
--- a/crates/router/src/core/locker_migration.rs
+++ b/crates/router/src/core/locker_migration.rs
@@ -43,7 +43,11 @@ pub async fn rust_locker_migration(
 
     for customer in domain_customers {
         let result = db
-            .find_payment_method_by_customer_id_merchant_id_list(&customer.customer_id, merchant_id)
+            .find_payment_method_by_customer_id_merchant_id_list(
+                &customer.customer_id,
+                merchant_id,
+                None,
+            )
             .change_context(errors::ApiErrorResponse::InternalServerError)
             .and_then(|pm| {
                 call_to_locker(
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index bdbd9b02d9e..df1fb1e358d 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -156,6 +156,10 @@ impl PaymentMethodRetrieve for Oss {
                 helpers::retrieve_card_with_permanent_token(
                     state,
                     card_token.locker_id.as_ref().unwrap_or(&card_token.token),
+                    card_token
+                        .payment_method_id
+                        .as_ref()
+                        .unwrap_or(&card_token.token),
                     payment_intent,
                     card_token_data,
                 )
@@ -167,6 +171,10 @@ impl PaymentMethodRetrieve for Oss {
                 helpers::retrieve_card_with_permanent_token(
                     state,
                     card_token.locker_id.as_ref().unwrap_or(&card_token.token),
+                    card_token
+                        .payment_method_id
+                        .as_ref()
+                        .unwrap_or(&card_token.token),
                     payment_intent,
                     card_token_data,
                 )
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index a92215936a0..8c00938cadc 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -7,8 +7,9 @@ use api_models::{
     admin::{self, PaymentMethodsEnabled},
     enums::{self as api_enums},
     payment_methods::{
-        BankAccountConnectorDetails, CardDetailsPaymentMethod, CardNetworkTypes, MaskedBankDetails,
-        PaymentExperienceTypes, PaymentMethodsData, RequestPaymentMethodTypes, RequiredFieldInfo,
+        BankAccountConnectorDetails, CardDetailsPaymentMethod, CardNetworkTypes,
+        CustomerDefaultPaymentMethodResponse, MaskedBankDetails, PaymentExperienceTypes,
+        PaymentMethodsData, RequestPaymentMethodTypes, RequiredFieldInfo,
         ResponsePaymentMethodIntermediate, ResponsePaymentMethodTypes,
         ResponsePaymentMethodsEnabled,
     },
@@ -25,6 +26,7 @@ use diesel_models::{
     business_profile::BusinessProfile, encryption::Encryption, enums as storage_enums,
     payment_method,
 };
+use domain::CustomerUpdate;
 use error_stack::{report, IntoReport, ResultExt};
 use masking::Secret;
 use router_env::{instrument, tracing};
@@ -128,11 +130,12 @@ pub fn store_default_payment_method(
         created: Some(common_utils::date_time::now()),
         recurring_enabled: false,           //[#219]
         installment_payment_enabled: false, //[#219]
-        payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219]
+        payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
+        last_used_at: Some(common_utils::date_time::now()),
     };
+
     (payment_method_response, None)
 }
-
 #[instrument(skip_all)]
 pub async fn get_or_insert_payment_method(
     db: &dyn db::StorageInterface,
@@ -2584,6 +2587,8 @@ pub async fn do_list_customer_pm_fetch_customer_if_not_passed(
     customer_id: Option<&str>,
 ) -> errors::RouterResponse<api::CustomerPaymentMethodsListResponse> {
     let db = state.store.as_ref();
+    let limit = req.clone().and_then(|pml_req| pml_req.limit);
+
     if let Some(customer_id) = customer_id {
         Box::pin(list_customer_payment_method(
             &state,
@@ -2591,6 +2596,7 @@ pub async fn do_list_customer_pm_fetch_customer_if_not_passed(
             key_store,
             None,
             customer_id,
+            limit,
         ))
         .await
     } else {
@@ -2614,6 +2620,7 @@ pub async fn do_list_customer_pm_fetch_customer_if_not_passed(
                     key_store,
                     payment_intent,
                     &customer_id,
+                    limit,
                 ))
                 .await
             }
@@ -2634,6 +2641,7 @@ pub async fn list_customer_payment_method(
     key_store: domain::MerchantKeyStore,
     payment_intent: Option<storage::PaymentIntent>,
     customer_id: &str,
+    limit: Option<i64>,
 ) -> errors::RouterResponse<api::CustomerPaymentMethodsListResponse> {
     let db = &*state.store;
 
@@ -2645,13 +2653,14 @@ pub async fn list_customer_payment_method(
         }
     };
 
-    db.find_customer_by_customer_id_merchant_id(
-        customer_id,
-        &merchant_account.merchant_id,
-        &key_store,
-    )
-    .await
-    .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;
+    let customer = db
+        .find_customer_by_customer_id_merchant_id(
+            customer_id,
+            &merchant_account.merchant_id,
+            &key_store,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;
 
     let key = key_store.key.get_inner().peek();
 
@@ -2671,6 +2680,7 @@ pub async fn list_customer_payment_method(
             customer_id,
             &merchant_account.merchant_id,
             common_enums::PaymentMethodStatus::Active,
+            limit,
         )
         .await
         .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
@@ -2758,6 +2768,7 @@ pub async fn list_customer_payment_method(
 
         let pma = api::CustomerPaymentMethod {
             payment_token: parent_payment_method_token.to_owned(),
+            payment_method_id: pm.payment_method_id.clone(),
             customer_id: pm.customer_id,
             payment_method: pm.payment_method,
             payment_method_type: pm.payment_method_type,
@@ -2773,6 +2784,9 @@ pub async fn list_customer_payment_method(
             bank: bank_details,
             surcharge_details: None,
             requires_cvv,
+            last_used_at: Some(pm.last_used_at),
+            default_payment_method_set: customer.default_payment_method_id.is_some()
+                && customer.default_payment_method_id == Some(pm.payment_method_id),
         };
         customer_pms.push(pma.to_owned());
 
@@ -3059,7 +3073,96 @@ async fn get_bank_account_connector_details(
         None => Ok(None),
     }
 }
+pub async fn set_default_payment_method(
+    state: routes::AppState,
+    merchant_account: domain::MerchantAccount,
+    key_store: domain::MerchantKeyStore,
+    customer_id: &str,
+    payment_method_id: String,
+) -> errors::RouterResponse<CustomerDefaultPaymentMethodResponse> {
+    let db = &*state.store;
+    //check for the customer
+    let customer = db
+        .find_customer_by_customer_id_merchant_id(
+            customer_id,
+            &merchant_account.merchant_id,
+            &key_store,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;
+    // check for the presence of payment_method
+    let payment_method = db
+        .find_payment_method(&payment_method_id)
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
 
+    utils::when(
+        payment_method.customer_id != customer_id
+            && payment_method.merchant_id != merchant_account.merchant_id,
+        || {
+            Err(errors::ApiErrorResponse::PreconditionFailed {
+                message: "The payment_method_id is not valid".to_string(),
+            })
+            .into_report()
+        },
+    )?;
+
+    utils::when(
+        Some(payment_method_id.clone()) == customer.default_payment_method_id,
+        || {
+            Err(errors::ApiErrorResponse::PreconditionFailed {
+                message: "Payment Method is already set as default".to_string(),
+            })
+            .into_report()
+        },
+    )?;
+
+    let customer_update = CustomerUpdate::UpdateDefaultPaymentMethod {
+        default_payment_method_id: Some(payment_method_id.clone()),
+    };
+
+    // update the db with the default payment method id
+    let updated_customer_details = db
+        .update_customer_by_customer_id_merchant_id(
+            customer_id.to_owned(),
+            merchant_account.merchant_id,
+            customer_update,
+            &key_store,
+        )
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to update the default payment method id for the customer")?;
+    let resp = CustomerDefaultPaymentMethodResponse {
+        default_payment_method_id: updated_customer_details.default_payment_method_id,
+        customer_id: customer.customer_id,
+        payment_method_type: payment_method.payment_method_type,
+        payment_method: payment_method.payment_method,
+    };
+
+    Ok(services::ApplicationResponse::Json(resp))
+}
+
+pub async fn update_last_used_at(
+    pm_id: &str,
+    state: &routes::AppState,
+) -> errors::RouterResult<()> {
+    let update_last_used = storage::PaymentMethodUpdate::LastUsedUpdate {
+        last_used_at: common_utils::date_time::now(),
+    };
+    let payment_method = state
+        .store
+        .find_payment_method(pm_id)
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
+    state
+        .store
+        .update_payment_method(payment_method, update_last_used)
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to update the last_used_at in db")?;
+
+    Ok(())
+}
 #[cfg(feature = "payouts")]
 pub async fn get_bank_from_hs_locker(
     state: &routes::AppState,
@@ -3243,9 +3346,10 @@ pub async fn retrieve_payment_method(
             card,
             metadata: pm.metadata,
             created: Some(pm.created_at),
-            recurring_enabled: false,           //[#219]
-            installment_payment_enabled: false, //[#219]
-            payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219],
+            recurring_enabled: false,
+            installment_payment_enabled: false,
+            payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
+            last_used_at: Some(pm.last_used_at),
         },
     ))
 }
diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs
index 19ecf733dfb..35491d747ef 100644
--- a/crates/router/src/core/payment_methods/transformers.rs
+++ b/crates/router/src/core/payment_methods/transformers.rs
@@ -327,7 +327,8 @@ pub fn mk_add_bank_response_hs(
         created: Some(common_utils::date_time::now()),
         recurring_enabled: false,           // [#256]
         installment_payment_enabled: false, // #[#256]
-        payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), // [#256]
+        payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
+        last_used_at: Some(common_utils::date_time::now()),
     }
 }
 
@@ -370,7 +371,8 @@ pub fn mk_add_card_response_hs(
         created: Some(common_utils::date_time::now()),
         recurring_enabled: false,           // [#256]
         installment_payment_enabled: false, // #[#256]
-        payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), // [#256]
+        payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
+        last_used_at: Some(common_utils::date_time::now()), // [#256]
     }
 }
 
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index b94b8627ef9..782d1814cc6 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -1070,7 +1070,6 @@ where
         customer,
     )
     .await?;
-
     *payment_data = pd;
 
     // Validating the blocklist guard and generate the fingerprint
@@ -1141,7 +1140,6 @@ where
     let pm_token = router_data
         .add_payment_method_token(state, &connector, &tokenization_action)
         .await?;
-
     if let Some(payment_method_token) = pm_token.clone() {
         router_data.payment_method_token = Some(router_types::PaymentMethodToken::Token(
             payment_method_token,
@@ -1846,7 +1844,7 @@ async fn decide_payment_method_tokenize_action(
     }
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub enum TokenizationAction {
     TokenizeInRouter,
     TokenizeInConnector,
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 0baba7035ce..e0b8a5f6232 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -1131,6 +1131,7 @@ pub(crate) async fn get_payment_method_create_request(
                         customer_id: Some(customer.customer_id.to_owned()),
                         card_network: None,
                     };
+
                     Ok(payment_method_request)
                 }
             },
@@ -1402,6 +1403,7 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, Ctx>(
                             modified_at: common_utils::date_time::now(),
                             connector_customer: None,
                             address_id: None,
+                            default_payment_method_id: None,
                         })
                     }
                     .await
@@ -1545,7 +1547,8 @@ pub async fn retrieve_payment_method_with_temporary_token(
 
 pub async fn retrieve_card_with_permanent_token(
     state: &AppState,
-    token: &str,
+    locker_id: &str,
+    payment_method_id: &str,
     payment_intent: &PaymentIntent,
     card_token_data: Option<&CardToken>,
 ) -> RouterResult<api::PaymentMethodData> {
@@ -1556,11 +1559,11 @@ pub async fn retrieve_card_with_permanent_token(
         .change_context(errors::ApiErrorResponse::UnprocessableEntity {
             message: "no customer id provided for the payment".to_string(),
         })?;
-
-    let card = cards::get_card_from_locker(state, customer_id, &payment_intent.merchant_id, token)
-        .await
-        .change_context(errors::ApiErrorResponse::InternalServerError)
-        .attach_printable("failed to fetch card information from the permanent locker")?;
+    let card =
+        cards::get_card_from_locker(state, customer_id, &payment_intent.merchant_id, locker_id)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("failed to fetch card information from the permanent locker")?;
 
     // The card_holder_name from locker retrieved card is considered if it is a non-empty string or else card_holder_name is picked
     // from payment_method_data.card_token object
@@ -1593,7 +1596,7 @@ pub async fn retrieve_card_with_permanent_token(
         card_issuing_country: None,
         bank_code: None,
     };
-
+    cards::update_last_used_at(payment_method_id, state).await?;
     Ok(api::PaymentMethodData::Card(api_card))
 }
 
diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs
index d08f0208500..21fd4cf85e8 100644
--- a/crates/router/src/core/payments/tokenization.rs
+++ b/crates/router/src/core/payments/tokenization.rs
@@ -426,6 +426,7 @@ async fn skip_saving_card_in_locker(
                 metadata: None,
                 created: Some(common_utils::date_time::now()),
                 bank_transfer: None,
+                last_used_at: Some(common_utils::date_time::now()),
             };
 
             Ok((pm_resp, None))
@@ -445,6 +446,7 @@ async fn skip_saving_card_in_locker(
                 installment_payment_enabled: false,
                 payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
                 bank_transfer: None,
+                last_used_at: Some(common_utils::date_time::now()),
             };
             Ok((payment_method_response, None))
         }
@@ -491,6 +493,7 @@ pub async fn save_in_locker(
                 recurring_enabled: false,           //[#219]
                 installment_payment_enabled: false, //[#219]
                 payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]), //[#219]
+                last_used_at: Some(common_utils::date_time::now()),
             };
             Ok((payment_method_response, None))
         }
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index 7b5ec096248..75a8483e06c 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -432,6 +432,7 @@ pub async fn get_or_create_customer_details(
                 created_at: common_utils::date_time::now(),
                 modified_at: common_utils::date_time::now(),
                 address_id: None,
+                default_payment_method_id: None,
             };
 
             Ok(Some(
diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs
index 982ed9cae94..2987370f280 100644
--- a/crates/router/src/core/pm_auth.rs
+++ b/crates/router/src/core/pm_auth.rs
@@ -297,6 +297,7 @@ async fn store_bank_details_in_payment_methods(
         .find_payment_method_by_customer_id_merchant_id_list(
             &customer_id,
             &merchant_account.merchant_id,
+            None,
         )
         .await
         .change_context(ApiErrorResponse::InternalServerError)?;
diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs
index 1c1ec00ce79..0c4cf01aa0e 100644
--- a/crates/router/src/db/kafka_store.rs
+++ b/crates/router/src/db/kafka_store.rs
@@ -1267,9 +1267,10 @@ impl PaymentMethodInterface for KafkaStore {
         &self,
         customer_id: &str,
         merchant_id: &str,
+        limit: Option<i64>,
     ) -> CustomResult<Vec<storage::PaymentMethod>, errors::StorageError> {
         self.diesel_store
-            .find_payment_method_by_customer_id_merchant_id_list(customer_id, merchant_id)
+            .find_payment_method_by_customer_id_merchant_id_list(customer_id, merchant_id, limit)
             .await
     }
 
@@ -1278,9 +1279,15 @@ impl PaymentMethodInterface for KafkaStore {
         customer_id: &str,
         merchant_id: &str,
         status: common_enums::PaymentMethodStatus,
+        limit: Option<i64>,
     ) -> CustomResult<Vec<storage::PaymentMethod>, errors::StorageError> {
         self.diesel_store
-            .find_payment_method_by_customer_id_merchant_id_status(customer_id, merchant_id, status)
+            .find_payment_method_by_customer_id_merchant_id_status(
+                customer_id,
+                merchant_id,
+                status,
+                limit,
+            )
             .await
     }
 
diff --git a/crates/router/src/db/payment_method.rs b/crates/router/src/db/payment_method.rs
index f15ceecd1c4..ddd2857cc22 100644
--- a/crates/router/src/db/payment_method.rs
+++ b/crates/router/src/db/payment_method.rs
@@ -24,6 +24,7 @@ pub trait PaymentMethodInterface {
         &self,
         customer_id: &str,
         merchant_id: &str,
+        limit: Option<i64>,
     ) -> CustomResult<Vec<storage::PaymentMethod>, errors::StorageError>;
 
     async fn find_payment_method_by_customer_id_merchant_id_status(
@@ -31,6 +32,7 @@ pub trait PaymentMethodInterface {
         customer_id: &str,
         merchant_id: &str,
         status: common_enums::PaymentMethodStatus,
+        limit: Option<i64>,
     ) -> CustomResult<Vec<storage::PaymentMethod>, errors::StorageError>;
 
     async fn insert_payment_method(
@@ -104,12 +106,18 @@ impl PaymentMethodInterface for Store {
         &self,
         customer_id: &str,
         merchant_id: &str,
+        limit: Option<i64>,
     ) -> CustomResult<Vec<storage::PaymentMethod>, errors::StorageError> {
         let conn = connection::pg_connection_read(self).await?;
-        storage::PaymentMethod::find_by_customer_id_merchant_id(&conn, customer_id, merchant_id)
-            .await
-            .map_err(Into::into)
-            .into_report()
+        storage::PaymentMethod::find_by_customer_id_merchant_id(
+            &conn,
+            customer_id,
+            merchant_id,
+            limit,
+        )
+        .await
+        .map_err(Into::into)
+        .into_report()
     }
 
     async fn find_payment_method_by_customer_id_merchant_id_status(
@@ -117,6 +125,7 @@ impl PaymentMethodInterface for Store {
         customer_id: &str,
         merchant_id: &str,
         status: common_enums::PaymentMethodStatus,
+        limit: Option<i64>,
     ) -> CustomResult<Vec<storage::PaymentMethod>, errors::StorageError> {
         let conn = connection::pg_connection_read(self).await?;
         storage::PaymentMethod::find_by_customer_id_merchant_id_status(
@@ -124,6 +133,7 @@ impl PaymentMethodInterface for Store {
             customer_id,
             merchant_id,
             status,
+            limit,
         )
         .await
         .map_err(Into::into)
@@ -221,6 +231,7 @@ impl PaymentMethodInterface for MockDb {
             payment_method_issuer_code: payment_method_new.payment_method_issuer_code,
             metadata: payment_method_new.metadata,
             payment_method_data: payment_method_new.payment_method_data,
+            last_used_at: payment_method_new.last_used_at,
             connector_mandate_details: payment_method_new.connector_mandate_details,
             customer_acceptance: payment_method_new.customer_acceptance,
             status: payment_method_new.status,
@@ -233,6 +244,7 @@ impl PaymentMethodInterface for MockDb {
         &self,
         customer_id: &str,
         merchant_id: &str,
+        _limit: Option<i64>,
     ) -> CustomResult<Vec<storage::PaymentMethod>, errors::StorageError> {
         let payment_methods = self.payment_methods.lock().await;
         let payment_methods_found: Vec<storage::PaymentMethod> = payment_methods
@@ -256,6 +268,7 @@ impl PaymentMethodInterface for MockDb {
         customer_id: &str,
         merchant_id: &str,
         status: common_enums::PaymentMethodStatus,
+        _limit: Option<i64>,
     ) -> CustomResult<Vec<storage::PaymentMethod>, errors::StorageError> {
         let payment_methods = self.payment_methods.lock().await;
         let payment_methods_found: Vec<storage::PaymentMethod> = payment_methods
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 73558c78d7b..1d82bc7539f 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -632,6 +632,10 @@ impl Customers {
                     web::resource("/{customer_id}/payment_methods")
                         .route(web::get().to(list_customer_payment_method_api)),
                 )
+                .service(
+                    web::resource("/{customer_id}/payment_methods/{payment_method_id}/default")
+                        .route(web::post().to(default_payment_method_set_api)),
+                )
                 .service(
                     web::resource("/{customer_id}")
                         .route(web::get().to(customers_retrieve))
diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs
index 9471289a0c8..edbdee7bf6f 100644
--- a/crates/router/src/routes/lock_utils.rs
+++ b/crates/router/src/routes/lock_utils.rs
@@ -96,7 +96,8 @@ impl From<Flow> for ApiIdentifier {
             | Flow::PaymentMethodsRetrieve
             | Flow::PaymentMethodsUpdate
             | Flow::PaymentMethodsDelete
-            | Flow::ValidatePaymentMethod => Self::PaymentMethods,
+            | Flow::ValidatePaymentMethod
+            | Flow::DefaultPaymentMethodsSet => Self::PaymentMethods,
 
             Flow::PmAuthLinkTokenCreate | Flow::PmAuthExchangeToken => Self::PaymentMethodAuth,
 
diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs
index 89ca36c8c15..5469f981659 100644
--- a/crates/router/src/routes/payment_methods.rs
+++ b/crates/router/src/routes/payment_methods.rs
@@ -102,6 +102,12 @@ pub async fn list_customer_payment_method_api(
     let flow = Flow::CustomerPaymentMethodsList;
     let payload = query_payload.into_inner();
     let customer_id = customer_id.into_inner().0;
+
+    let ephemeral_auth =
+        match auth::is_ephemeral_auth(req.headers(), &*state.store, &customer_id).await {
+            Ok(auth) => auth,
+            Err(err) => return api::log_and_return_error_response(err),
+        };
     Box::pin(api::server_wrap(
         flow,
         state,
@@ -116,7 +122,7 @@ pub async fn list_customer_payment_method_api(
                 Some(&customer_id),
             )
         },
-        &auth::ApiKeyAuth,
+        &*ephemeral_auth,
         api_locking::LockAction::NotApplicable,
     ))
     .await
@@ -157,6 +163,7 @@ pub async fn list_customer_payment_method_api_client(
         Ok((auth, _auth_flow)) => (auth, _auth_flow),
         Err(e) => return api::log_and_return_error_response(e),
     };
+
     Box::pin(api::server_wrap(
         flow,
         state,
@@ -252,6 +259,42 @@ pub async fn payment_method_delete_api(
     ))
     .await
 }
+
+#[instrument(skip_all, fields(flow = ?Flow::DefaultPaymentMethodsSet))]
+pub async fn default_payment_method_set_api(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    path: web::Path<payment_methods::DefaultPaymentMethod>,
+) -> HttpResponse {
+    let flow = Flow::DefaultPaymentMethodsSet;
+    let payload = path.into_inner();
+    let customer_id = payload.clone().customer_id;
+
+    let ephemeral_auth =
+        match auth::is_ephemeral_auth(req.headers(), &*state.store, &customer_id).await {
+            Ok(auth) => auth,
+            Err(err) => return api::log_and_return_error_response(err),
+        };
+    Box::pin(api::server_wrap(
+        flow,
+        state,
+        &req,
+        payload,
+        |state, auth: auth::AuthenticationData, default_payment_method| {
+            cards::set_default_payment_method(
+                state,
+                auth.merchant_account,
+                auth.key_store,
+                &customer_id,
+                default_payment_method.payment_method_id,
+            )
+        },
+        &*ephemeral_auth,
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
+
 #[cfg(test)]
 mod tests {
     #![allow(clippy::unwrap_used)]
diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs
index 894b3d830dd..009033d5341 100644
--- a/crates/router/src/types/api.rs
+++ b/crates/router/src/types/api.rs
@@ -204,7 +204,7 @@ type BoxedConnector = Box<&'static (dyn Connector + Sync)>;
 
 // Normal flow will call the connector and follow the flow specific operations (capture, authorize)
 // SessionTokenFromMetadata will avoid calling the connector instead create the session token ( for sdk )
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Clone, Eq, PartialEq, Debug)]
 pub enum GetToken {
     GpayMetadata,
     ApplePayMetadata,
@@ -214,7 +214,7 @@ pub enum GetToken {
 /// Routing algorithm will output merchant connector identifier instead of connector name
 /// In order to support backwards compatibility for older routing algorithms and merchant accounts
 /// the support for connector name is retained
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct ConnectorData {
     pub connector: BoxedConnector,
     pub connector_name: types::Connector,
diff --git a/crates/router/src/types/api/customers.rs b/crates/router/src/types/api/customers.rs
index 32430c0918a..6f08a7fd7e4 100644
--- a/crates/router/src/types/api/customers.rs
+++ b/crates/router/src/types/api/customers.rs
@@ -32,6 +32,7 @@ impl From<(domain::Customer, Option<payments::AddressDetails>)> for CustomerResp
             created_at: cust.created_at,
             metadata: cust.metadata,
             address,
+            default_payment_method_id: cust.default_payment_method_id,
         }
         .into()
     }
diff --git a/crates/router/src/types/api/payment_methods.rs b/crates/router/src/types/api/payment_methods.rs
index ca852f832ee..642e94ad69e 100644
--- a/crates/router/src/types/api/payment_methods.rs
+++ b/crates/router/src/types/api/payment_methods.rs
@@ -1,10 +1,11 @@
 pub use api_models::payment_methods::{
     CardDetail, CardDetailFromLocker, CardDetailsPaymentMethod, CustomerPaymentMethod,
-    CustomerPaymentMethodsListResponse, DeleteTokenizeByTokenRequest, GetTokenizePayloadRequest,
-    GetTokenizePayloadResponse, PaymentMethodCreate, PaymentMethodDeleteResponse, PaymentMethodId,
-    PaymentMethodList, PaymentMethodListRequest, PaymentMethodListResponse, PaymentMethodResponse,
-    PaymentMethodUpdate, PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest,
-    TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2,
+    CustomerPaymentMethodsListResponse, DefaultPaymentMethod, DeleteTokenizeByTokenRequest,
+    GetTokenizePayloadRequest, GetTokenizePayloadResponse, PaymentMethodCreate,
+    PaymentMethodDeleteResponse, PaymentMethodId, PaymentMethodList, PaymentMethodListRequest,
+    PaymentMethodListResponse, PaymentMethodResponse, PaymentMethodUpdate, PaymentMethodsData,
+    TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1, TokenizedCardValue2,
+    TokenizedWalletValue1, TokenizedWalletValue2,
 };
 use error_stack::report;
 
diff --git a/crates/router/src/types/domain/customer.rs b/crates/router/src/types/domain/customer.rs
index fe575851dc4..5437d06a2e6 100644
--- a/crates/router/src/types/domain/customer.rs
+++ b/crates/router/src/types/domain/customer.rs
@@ -22,6 +22,7 @@ pub struct Customer {
     pub modified_at: PrimitiveDateTime,
     pub connector_customer: Option<serde_json::Value>,
     pub address_id: Option<String>,
+    pub default_payment_method_id: Option<String>,
 }
 
 #[async_trait::async_trait]
@@ -45,6 +46,7 @@ impl super::behaviour::Conversion for Customer {
             modified_at: self.modified_at,
             connector_customer: self.connector_customer,
             address_id: self.address_id,
+            default_payment_method_id: self.default_payment_method_id,
         })
     }
 
@@ -72,6 +74,7 @@ impl super::behaviour::Conversion for Customer {
                 modified_at: item.modified_at,
                 connector_customer: item.connector_customer,
                 address_id: item.address_id,
+                default_payment_method_id: item.default_payment_method_id,
             })
         }
         .await
@@ -114,6 +117,9 @@ pub enum CustomerUpdate {
     ConnectorCustomer {
         connector_customer: Option<serde_json::Value>,
     },
+    UpdateDefaultPaymentMethod {
+        default_payment_method_id: Option<String>,
+    },
 }
 
 impl From<CustomerUpdate> for CustomerUpdateInternal {
@@ -138,12 +144,20 @@ impl From<CustomerUpdate> for CustomerUpdateInternal {
                 connector_customer,
                 modified_at: Some(date_time::now()),
                 address_id,
+                ..Default::default()
             },
             CustomerUpdate::ConnectorCustomer { connector_customer } => Self {
                 connector_customer,
                 modified_at: Some(common_utils::date_time::now()),
                 ..Default::default()
             },
+            CustomerUpdate::UpdateDefaultPaymentMethod {
+                default_payment_method_id,
+            } => Self {
+                default_payment_method_id,
+                modified_at: Some(common_utils::date_time::now()),
+                ..Default::default()
+            },
         }
     }
 }
diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs
index 62c09c42455..4790e60acb1 100644
--- a/crates/router_env/src/logger/types.rs
+++ b/crates/router_env/src/logger/types.rs
@@ -123,6 +123,8 @@ pub enum Flow {
     PaymentMethodsUpdate,
     /// Payment methods delete flow.
     PaymentMethodsDelete,
+    /// Default Payment method flow.
+    DefaultPaymentMethodsSet,
     /// Payments create flow.
     PaymentsCreate,
     /// Payments Retrieve flow.
diff --git a/migrations/2024-02-21-120100_add_last_used_at_in_payment_methods/down.sql b/migrations/2024-02-21-120100_add_last_used_at_in_payment_methods/down.sql
new file mode 100644
index 00000000000..fc9fc6350ed
--- /dev/null
+++ b/migrations/2024-02-21-120100_add_last_used_at_in_payment_methods/down.sql
@@ -0,0 +1,2 @@
+-- This file should undo anything in `up.sql`
+ALTER TABLE payment_methods DROP COLUMN IF EXISTS last_used_at;
\ No newline at end of file
diff --git a/migrations/2024-02-21-120100_add_last_used_at_in_payment_methods/up.sql b/migrations/2024-02-21-120100_add_last_used_at_in_payment_methods/up.sql
new file mode 100644
index 00000000000..f1c0aab4def
--- /dev/null
+++ b/migrations/2024-02-21-120100_add_last_used_at_in_payment_methods/up.sql
@@ -0,0 +1,2 @@
+-- Your SQL goes here
+ALTER TABLE payment_methods ADD COLUMN IF NOT EXISTS last_used_at TIMESTAMP NOT NULL DEFAULT now()::TIMESTAMP;
\ No newline at end of file
diff --git a/migrations/2024-02-21-143530_add_default_payment_method_in_customers/down.sql b/migrations/2024-02-21-143530_add_default_payment_method_in_customers/down.sql
new file mode 100644
index 00000000000..948123ce7e2
--- /dev/null
+++ b/migrations/2024-02-21-143530_add_default_payment_method_in_customers/down.sql
@@ -0,0 +1,2 @@
+-- This file should undo anything in `up.sql`
+ALTER TABLE customers DROP COLUMN IF EXISTS default_payment_method;
diff --git a/migrations/2024-02-21-143530_add_default_payment_method_in_customers/up.sql b/migrations/2024-02-21-143530_add_default_payment_method_in_customers/up.sql
new file mode 100644
index 00000000000..abaeb1df718
--- /dev/null
+++ b/migrations/2024-02-21-143530_add_default_payment_method_in_customers/up.sql
@@ -0,0 +1,3 @@
+-- Your SQL goes here
+ALTER TABLE customers
+ADD COLUMN IF NOT EXISTS default_payment_method_id VARCHAR(64);
\ No newline at end of file
diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json
index 30e75c028d5..3fcf6bca79f 100644
--- a/openapi/openapi_spec.json
+++ b/openapi/openapi_spec.json
@@ -4080,6 +4080,50 @@
           }
         ]
       }
+    },
+    "/{customer_id}/payment_methods/{payment_method_id}/default": {
+      "get": {
+        "tags": [
+          "Customer Set Default Payment Method"
+        ],
+        "summary": "Customers - Set Default Payment Method",
+        "description": "Customers - Set Default Payment Method\n\nSet the Payment Method as Default for the Customer.",
+        "operationId": "Set the Payment Method as Default",
+        "parameters": [
+          {
+            "name": "method_id",
+            "in": "path",
+            "description": "Set the Payment Method as Default for the Customer",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Payment Method has been set as default",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/CustomerDefaultPaymentMethodResponse"
+                }
+              }
+            }
+          },
+          "400": {
+            "description": "Payment Method has already been set as default for that customer"
+          },
+          "404": {
+            "description": "Payment Method not found for the customer"
+          }
+        },
+        "security": [
+          {
+            "ephemeral_key": []
+          }
+        ]
+      }
     }
   },
   "components": {
@@ -7308,6 +7352,37 @@
           }
         }
       },
+      "CustomerDefaultPaymentMethodResponse": {
+        "type": "object",
+        "required": [
+          "customer_id",
+          "payment_method"
+        ],
+        "properties": {
+          "default_payment_method_id": {
+            "type": "string",
+            "description": "The unique identifier of the Payment method",
+            "example": "card_rGK4Vi5iSW70MY7J2mIy",
+            "nullable": true
+          },
+          "customer_id": {
+            "type": "string",
+            "description": "The unique identifier of the customer.",
+            "example": "cus_meowerunwiuwiwqw"
+          },
+          "payment_method": {
+            "$ref": "#/components/schemas/PaymentMethod"
+          },
+          "payment_method_type": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/PaymentMethodType"
+              }
+            ],
+            "nullable": true
+          }
+        }
+      },
       "CustomerDeleteResponse": {
         "type": "object",
         "required": [
@@ -7384,11 +7459,13 @@
         "type": "object",
         "required": [
           "payment_token",
+          "payment_method_id",
           "customer_id",
           "payment_method",
           "recurring_enabled",
           "installment_payment_enabled",
-          "requires_cvv"
+          "requires_cvv",
+          "default_payment_method_set"
         ],
         "properties": {
           "payment_token": {
@@ -7396,6 +7473,11 @@
             "description": "Token for payment method in temporary card locker which gets refreshed often",
             "example": "7ebf443f-a050-4067-84e5-e6f6d4800aef"
           },
+          "payment_method_id": {
+            "type": "string",
+            "description": "The unique identifier of the customer.",
+            "example": "pm_iouuy468iyuowqs"
+          },
           "customer_id": {
             "type": "string",
             "description": "The unique identifier of the customer.",
@@ -7495,6 +7577,18 @@
             "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",
+            "nullable": true
+          },
+          "default_payment_method_set": {
+            "type": "boolean",
+            "description": "Indicates if the payment method has been set to default or not",
+            "example": true
           }
         }
       },
@@ -7644,6 +7738,28 @@
             "type": "object",
             "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500\ncharacters long. Metadata is useful for storing additional, structured information on an\nobject.",
             "nullable": true
+          },
+          "default_payment_method_id": {
+            "type": "string",
+            "description": "The identifier for the default payment method.",
+            "example": "pm_djh2837dwduh890123",
+            "nullable": true,
+            "maxLength": 64
+          }
+        }
+      },
+      "DefaultPaymentMethod": {
+        "type": "object",
+        "required": [
+          "customer_id",
+          "payment_method_id"
+        ],
+        "properties": {
+          "customer_id": {
+            "type": "string"
+          },
+          "payment_method_id": {
+            "type": "string"
           }
         }
       },
@@ -11888,6 +12004,12 @@
               }
             ],
             "nullable": true
+          },
+          "last_used_at": {
+            "type": "string",
+            "format": "date-time",
+            "example": "2024-02-24T11:04:09.922Z",
+            "nullable": true
           }
         }
       },

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

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

## Description
- Add default payment method column in customers table and last used column in payment_methods table. 
- Last used would be updated depending on every payment_method usages.
-  And the CustomerPaymentMethodList would be sorted on the basis of last_used at.
- A query param was added , to show the list on the basis of limit, i.e., if limit is 1 we will show only the 1st payment_method while doing a CustomerPaymentMethodList
- CustomerPaymentMethodList Authentication from ApiKey to EphemeralKey
- Made a new Api Route, `/payment_methods/{customer_id}/{payment_method_id}/default` for explicitly setting up the default payment method for a particular customer, which would require , customer_id and payment_method_id to be passed in the path
- In CustomerPaymentMethodList we would show the Default Payment Method was either set or not , based on its entry in the Customer Table 
- Also in CustomerPaymentMethodList we would show payment_method_id now 


### Additional Changes

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

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

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


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

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


## How did you test it?
 

To test `set_default_payment_method`

- Create an MA and and MCA 
- Create an ApiKey and EphemeralKey for that particular customer
- Make a payment , using one card and then do a ListCustomerPaymentMethods
- > Create
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_RHgvB0yPOTVA4xK4zTjXzxrnSVmnXlJz80hnEHIocTKplSc6sYqwRu2yHD8iJyuA' \
--data-raw ' {"amount": 6540,
    "currency": "USD",
    "confirm": false,
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "customer_id": "7cc",
    "email": "something@gmail.com",
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "metadata": {
        "order_details": {
            "product_name": "Apple iphone 15",
            "quantity": 1
        }
    },
    "business_country": "US",
    "business_label": "default",
    "setup_future_usage": "on_session"
    
    
}'
```
-> Confirm
```
curl --location 'http://localhost:8080/payments/pay_nIQnyrfS15jQja2OocCX/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_RHgvB0yPOTVA4xK4zTjXzxrnSVmnXlJz80hnEHIocTKplSc6sYqwRu2yHD8iJyuA' \
--data '{
    "confirm": true,
     "payment_type": "normal",
       "setup_future_usage":"on_session",









    "payment_method": "card",

    "payment_method_type": "debit",
    "payment_method_data": {
        "card": {
              "card_number": "4111111111111111",
      
            

            
    
            "card_exp_month": "11",
            "card_exp_year": "2040",
            "card_holder_name": "AKA",
            "card_cvc": "123",
            "nick_name": "HELO"
        }
    }
}'
```
- The `default_payment_method` would be false , there also will be `payment_method_id` field (refer the screenshots below)
-  The following curl can be used to set the particular payment_method as default, the

```
curl --location --request POST 'http://localhost:8080/customers/{customer_id}/payment_methods/{payment_method_id}/set' \
--header 'Accept: application/json' \
--header 'api-key: epk_bf2209db8af14c04b811bce74e0d1202'
```

- do a ListCustomerPaymentMethods, The `default_payment_method` would be true

To test `last_used_at`
- Create an MA and and MCA 
- Create an ApiKey and EphemeralKey for that particular customer
- Make a payment , using one card and then do a ListCustomerPaymentMethods
- > Create
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_RHgvB0yPOTVA4xK4zTjXzxrnSVmnXlJz80hnEHIocTKplSc6sYqwRu2yHD8iJyuA' \
--data-raw ' {"amount": 6540,
    "currency": "USD",
    "confirm": false,
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "customer_id": "7cc",
    "email": "something@gmail.com",
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "metadata": {
        "order_details": {
            "product_name": "Apple iphone 15",
            "quantity": 1
        }
    },
    "business_country": "US",
    "business_label": "default",
    "setup_future_usage": "on_session"
    
    
}'
```
-> Confirm
```
curl --location 'http://localhost:8080/payments/pay_nIQnyrfS15jQja2OocCX/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_RHgvB0yPOTVA4xK4zTjXzxrnSVmnXlJz80hnEHIocTKplSc6sYqwRu2yHD8iJyuA' \
--data '{
    "confirm": true,
     "payment_type": "normal",
       "setup_future_usage":"on_session",









    "payment_method": "card",

    "payment_method_type": "debit",
    "payment_method_data": {
        "card": {
              "card_number": "4111111111111111",
      
            

            
    
            "card_exp_month": "11",
            "card_exp_year": "2040",
            "card_holder_name": "AKA",
            "card_cvc": "123",
            "nick_name": "HELO"
        }
    }
}'
```
- The last_used_at field would show the current timestamp
- Make a payment , using another card and then do a ListCustomerPaymentMethods
- > Create
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_RHgvB0yPOTVA4xK4zTjXzxrnSVmnXlJz80hnEHIocTKplSc6sYqwRu2yHD8iJyuA' \
--data-raw ' {"amount": 6540,
    "currency": "USD",
    "confirm": false,
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "customer_id": "7cc",
    "email": "something@gmail.com",
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "metadata": {
        "order_details": {
            "product_name": "Apple iphone 15",
            "quantity": 1
        }
    },
    "business_country": "US",
    "business_label": "default",
    "setup_future_usage": "on_session"
    
    
}'
```
-> Confirm
```
curl --location 'http://localhost:8080/payments/pay_nIQnyrfS15jQja2OocCX/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_RHgvB0yPOTVA4xK4zTjXzxrnSVmnXlJz80hnEHIocTKplSc6sYqwRu2yHD8iJyuA' \
--data '{
    "confirm": true,
     "payment_type": "normal",
       "setup_future_usage":"on_session",









    "payment_method": "card",

    "payment_method_type": "debit",
    "payment_method_data": {
        "card": {
              "card_number": "4242424242424242",
      
            

            
    
            "card_exp_month": "11",
            "card_exp_year": "2040",
            "card_holder_name": "AKA",
            "card_cvc": "123",
            "nick_name": "HELO"
        }
    }
}'
```
- The last_used_at field would show the current timestamp
- Do The list customer and then select a payment_token of the last card
- Make a payment using the `payment_token`
- The last_used_at field would show the current timestamp, and would be sorted in the order that PaymentMethod was used at
- The following curl can be used to list the customer payment methods with a limit , the limit if set as 1 would show the last used payment method
```
curl --location 'http://localhost:8080/customers/{customer_id}/payment_methods?limit=1' \
--header 'Accept: application/json' \
--header 'api-key: dev_OS3aZUsCeqV3eTW2Nlaba7yThKEUAZGXlEysuL15ZIoPP0McJ4YB9zRr9mWc9NFW'
```
![image](https://github.com/juspay/hyperswitch/assets/55580080/9597cd08-bf23-4fea-978c-fecae7e5c848)

<img width="1728" alt="Screenshot 2024-02-26 at 4 42 43 PM" src="https://github.com/juspay/hyperswitch/assets/55580080/64231527-bce6-4483-9997-b0cfb0669733">
![Screenshot 2024-02-26 at 4 11 50 PM](https://github.com/juspay/hyperswitch/assets/55580080/0618a89e-e6ae-43d1-911c-f46e365f38c3)


![image](https://github.com/juspay/hyperswitch/assets/55580080/c07d3f76-863e-4beb-a897-06de49390c63)


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

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
