Bug: [FEATURE] Allow creation of mandates using payment_token



### Feature Description

Allow creation of mandates using payment_token, with setup_future_usage and customer_acceptance

### Possible Implementation

Decide based on mandate_type if the intention is to Make a recurring mandate with payment_token or to make a new mandate with payment_token

### Have you spent some time checking if this feature request has been raised before?

- [X] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/crates/router/src/core/mandate/helpers.rs b/crates/router/src/core/mandate/helpers.rs
index 704b7ae99f5..c15969fd1c8 100644
--- a/crates/router/src/core/mandate/helpers.rs
+++ b/crates/router/src/core/mandate/helpers.rs
@@ -1,3 +1,4 @@
+use api_models::payments as api_payments;
 use common_enums::enums;
 use common_utils::errors::CustomResult;
 use data_models::mandates::MandateData;
@@ -7,7 +8,7 @@ use error_stack::ResultExt;
 use crate::{
     core::{errors, payments},
     routes::AppState,
-    types::domain,
+    types::{api, domain},
 };
 
 pub async fn get_profile_id_for_mandate(
@@ -40,6 +41,40 @@ pub async fn get_profile_id_for_mandate(
     Ok(profile_id)
 }
 
+pub fn get_mandate_type(
+    mandate_data: Option<api_payments::MandateData>,
+    off_session: Option<bool>,
+    setup_future_usage: Option<enums::FutureUsage>,
+    customer_acceptance: Option<api_payments::CustomerAcceptance>,
+    token: Option<String>,
+) -> CustomResult<Option<api::MandateTransactionType>, errors::ValidationError> {
+    match (
+        mandate_data.clone(),
+        off_session,
+        setup_future_usage,
+        customer_acceptance.or(mandate_data.and_then(|m_data| m_data.customer_acceptance)),
+        token,
+    ) {
+        (Some(_), Some(_), Some(enums::FutureUsage::OffSession), Some(_), Some(_)) => {
+            Err(errors::ValidationError::InvalidValue {
+                message: "Expected one out of recurring_details and mandate_data but got both"
+                    .to_string(),
+            }
+            .into())
+        }
+        (_, _, Some(enums::FutureUsage::OffSession), Some(_), Some(_))
+        | (_, _, Some(enums::FutureUsage::OffSession), Some(_), _)
+        | (Some(_), _, Some(enums::FutureUsage::OffSession), _, _) => {
+            Ok(Some(api::MandateTransactionType::NewMandateTransaction))
+        }
+
+        (_, _, Some(enums::FutureUsage::OffSession), _, Some(_)) | (_, Some(_), _, _, _) => Ok(
+            Some(api::MandateTransactionType::RecurringMandateTransaction),
+        ),
+
+        _ => Ok(None),
+    }
+}
 #[derive(Clone)]
 pub struct MandateGenericData {
     pub token: Option<String>,
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index e74a8c1d1ec..d56c4cfea5d 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -129,13 +129,13 @@ where
         customer_details,
         mut payment_data,
         business_profile,
+        mandate_type,
     } = operation
         .to_get_tracker()?
         .get_trackers(
             state,
             &validate_result.payment_id,
             &req,
-            validate_result.mandate_type.to_owned(),
             &merchant_account,
             &key_store,
             auth_flow,
@@ -166,6 +166,7 @@ where
         &key_store,
         &mut payment_data,
         eligible_connectors,
+        mandate_type,
     )
     .await?;
 
@@ -2655,6 +2656,7 @@ pub async fn get_connector_choice<F, Req, Ctx>(
     key_store: &domain::MerchantKeyStore,
     payment_data: &mut PaymentData<F>,
     eligible_connectors: Option<Vec<api_models::enums::RoutableConnectors>>,
+    mandate_type: Option<api::MandateTransactionType>,
 ) -> RouterResult<Option<ConnectorCallType>>
 where
     F: Send + Clone,
@@ -2694,6 +2696,7 @@ where
                     payment_data,
                     Some(straight_through),
                     eligible_connectors,
+                    mandate_type,
                 )
                 .await?
             }
@@ -2707,6 +2710,7 @@ where
                     payment_data,
                     None,
                     eligible_connectors,
+                    mandate_type,
                 )
                 .await?
             }
@@ -2723,6 +2727,7 @@ where
     Ok(connector)
 }
 
+#[allow(clippy::too_many_arguments)]
 pub async fn connector_selection<F>(
     state: &AppState,
     merchant_account: &domain::MerchantAccount,
@@ -2731,6 +2736,7 @@ pub async fn connector_selection<F>(
     payment_data: &mut PaymentData<F>,
     request_straight_through: Option<serde_json::Value>,
     eligible_connectors: Option<Vec<api_models::enums::RoutableConnectors>>,
+    mandate_type: Option<api::MandateTransactionType>,
 ) -> RouterResult<ConnectorCallType>
 where
     F: Send + Clone,
@@ -2772,6 +2778,7 @@ where
         request_straight_through,
         &mut routing_data,
         eligible_connectors,
+        mandate_type,
     )
     .await?;
 
@@ -2805,6 +2812,7 @@ pub async fn decide_connector<F>(
     request_straight_through: Option<api::routing::StraightThroughAlgorithm>,
     routing_data: &mut storage::RoutingData,
     eligible_connectors: Option<Vec<api_models::enums::RoutableConnectors>>,
+    mandate_type: Option<api::MandateTransactionType>,
 ) -> RouterResult<ConnectorCallType>
 where
     F: Send + Clone,
@@ -2936,6 +2944,7 @@ where
             payment_data,
             routing_data,
             connector_data,
+            mandate_type,
         )
         .await;
     }
@@ -2992,6 +3001,7 @@ where
             payment_data,
             routing_data,
             connector_data,
+            mandate_type,
         )
         .await;
     }
@@ -3004,6 +3014,7 @@ where
         TransactionData::Payment(payment_data),
         routing_data,
         eligible_connectors,
+        mandate_type,
     )
     .await
 }
@@ -3013,16 +3024,30 @@ pub async fn decide_multiplex_connector_for_normal_or_recurring_payment<F: Clone
     payment_data: &mut PaymentData<F>,
     routing_data: &mut storage::RoutingData,
     connectors: Vec<api::ConnectorData>,
+    mandate_type: Option<api::MandateTransactionType>,
 ) -> RouterResult<ConnectorCallType> {
     match (
         payment_data.payment_intent.setup_future_usage,
         payment_data.token_data.as_ref(),
         payment_data.recurring_details.as_ref(),
         payment_data.payment_intent.off_session,
+        mandate_type,
     ) {
-        (Some(storage_enums::FutureUsage::OffSession), Some(_), None, None)
-        | (None, None, Some(RecurringDetails::PaymentMethodId(_)), Some(true))
-        | (None, Some(_), None, Some(true)) => {
+        (
+            Some(storage_enums::FutureUsage::OffSession),
+            Some(_),
+            None,
+            None,
+            Some(api::MandateTransactionType::RecurringMandateTransaction),
+        )
+        | (
+            None,
+            None,
+            Some(RecurringDetails::PaymentMethodId(_)),
+            Some(true),
+            Some(api::MandateTransactionType::RecurringMandateTransaction),
+        )
+        | (None, Some(_), None, Some(true), _) => {
             logger::debug!("performing routing for token-based MIT flow");
 
             let payment_method_info = payment_data
@@ -3326,6 +3351,7 @@ where
     Ok(final_list)
 }
 
+#[allow(clippy::too_many_arguments)]
 pub async fn route_connector_v1<F>(
     state: &AppState,
     merchant_account: &domain::MerchantAccount,
@@ -3334,6 +3360,7 @@ pub async fn route_connector_v1<F>(
     transaction_data: TransactionData<'_, F>,
     routing_data: &mut storage::RoutingData,
     eligible_connectors: Option<Vec<api_models::enums::RoutableConnectors>>,
+    mandate_type: Option<api::MandateTransactionType>,
 ) -> RouterResult<ConnectorCallType>
 where
     F: Send + Clone,
@@ -3424,6 +3451,7 @@ where
                 payment_data,
                 routing_data,
                 connector_data,
+                mandate_type,
             )
             .await
         }
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index f8aa463a44b..de74abe8603 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -430,7 +430,7 @@ pub async fn get_token_pm_type_mandate_details(
             request.payment_token.to_owned(),
             request.payment_method,
             request.payment_method_type,
-            Some(mandate_data.clone().get_required_value("mandate_data")?),
+            mandate_data.clone(),
             None,
             None,
             None,
@@ -493,29 +493,37 @@ pub async fn get_token_pm_type_mandate_details(
                     }
                 },
                 None => {
-                    let mandate_id = request
-                        .mandate_id
-                        .clone()
-                        .get_required_value("mandate_id")?;
-                    let mandate_generic_data = get_token_for_recurring_mandate(
-                        state,
-                        request,
-                        merchant_account,
-                        merchant_key_store,
-                        mandate_id,
-                    )
-                    .await?;
-                    (
-                        mandate_generic_data.token,
-                        mandate_generic_data.payment_method,
-                        mandate_generic_data
-                            .payment_method_type
-                            .or(request.payment_method_type),
-                        None,
-                        mandate_generic_data.recurring_mandate_payment_data,
-                        mandate_generic_data.mandate_connector,
-                        None,
-                    )
+                    if let Some(mandate_id) = request.mandate_id.clone() {
+                        let mandate_generic_data = get_token_for_recurring_mandate(
+                            state,
+                            request,
+                            merchant_account,
+                            merchant_key_store,
+                            mandate_id,
+                        )
+                        .await?;
+                        (
+                            mandate_generic_data.token,
+                            mandate_generic_data.payment_method,
+                            mandate_generic_data
+                                .payment_method_type
+                                .or(request.payment_method_type),
+                            None,
+                            mandate_generic_data.recurring_mandate_payment_data,
+                            mandate_generic_data.mandate_connector,
+                            None,
+                        )
+                    } else {
+                        (
+                            request.payment_token.to_owned(),
+                            request.payment_method,
+                            request.payment_method_type,
+                            None,
+                            None,
+                            None,
+                            None,
+                        )
+                    }
                 }
             }
         }
diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs
index cad02fc7210..44256b6a718 100644
--- a/crates/router/src/core/payments/operations.rs
+++ b/crates/router/src/core/payments/operations.rs
@@ -79,7 +79,6 @@ pub trait Operation<F: Clone, T, Ctx: PaymentMethodRetrieve>: Send + std::fmt::D
 pub struct ValidateResult<'a> {
     pub merchant_id: &'a str,
     pub payment_id: api::PaymentIdType,
-    pub mandate_type: Option<api::MandateTransactionType>,
     pub storage_scheme: enums::MerchantStorageScheme,
     pub requeue: bool,
 }
@@ -98,6 +97,7 @@ pub struct GetTrackerResponse<'a, F: Clone, R, Ctx> {
     pub customer_details: Option<CustomerDetails>,
     pub payment_data: PaymentData<F>,
     pub business_profile: storage::business_profile::BusinessProfile,
+    pub mandate_type: Option<api::MandateTransactionType>,
 }
 
 #[async_trait]
@@ -108,7 +108,6 @@ pub trait GetTracker<F: Clone, D, R, Ctx: PaymentMethodRetrieve>: Send {
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &R,
-        mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         mechant_key_store: &domain::MerchantKeyStore,
         auth_flow: services::AuthFlow,
diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs
index e25ef7ed4a4..b47608eba98 100644
--- a/crates/router/src/core/payments/operations/payment_approve.rs
+++ b/crates/router/src/core/payments/operations/payment_approve.rs
@@ -38,7 +38,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         _request: &api::PaymentsCaptureRequest,
-        _mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -186,6 +185,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: None,
             payment_data,
             business_profile,
+            mandate_type: None,
         };
 
         Ok(get_trackers_response)
@@ -259,7 +259,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
                     request.payment_id.clone(),
                     "payment_id",
                 )?),
-                mandate_type: None,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: false,
             },
diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs
index ab5feb5d9b5..9cd9ba9f6d4 100644
--- a/crates/router/src/core/payments/operations/payment_cancel.rs
+++ b/crates/router/src/core/payments/operations/payment_cancel.rs
@@ -39,7 +39,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &api::PaymentsCancelRequest,
-        _mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -195,6 +194,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: None,
             payment_data,
             business_profile,
+            mandate_type: None,
         };
 
         Ok(get_trackers_response)
@@ -281,7 +281,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: api::PaymentIdType::PaymentIntentId(request.payment_id.to_owned()),
-                mandate_type: None,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: false,
             },
diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs
index 4445589f42f..c6dfe6bd3cb 100644
--- a/crates/router/src/core/payments/operations/payment_capture.rs
+++ b/crates/router/src/core/payments/operations/payment_capture.rs
@@ -38,7 +38,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &api::PaymentsCaptureRequest,
-        _mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -239,6 +238,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: None,
             payment_data,
             business_profile,
+            mandate_type: None,
         };
 
         Ok(get_trackers_response)
@@ -313,7 +313,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: api::PaymentIdType::PaymentIntentId(request.payment_id.to_owned()),
-                mandate_type: None,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: false,
             },
diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
index e1a16b6f4a2..413a4b03895 100644
--- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs
+++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
@@ -10,7 +10,7 @@ use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, Valida
 use crate::{
     core::{
         errors::{self, CustomResult, RouterResult, StorageErrorExt},
-        mandate::helpers::MandateGenericData,
+        mandate::helpers as m_helpers,
         payment_methods::PaymentMethodRetrieve,
         payments::{self, helpers, operations, CustomerDetails, PaymentAddress, PaymentData},
         utils as core_utils,
@@ -40,7 +40,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &api::PaymentsRequest,
-        mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -72,23 +71,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             "confirm",
         )?;
 
-        let MandateGenericData {
-            token,
-            payment_method,
-            payment_method_type,
-            mandate_data,
-            recurring_mandate_payment_data,
-            mandate_connector,
-            payment_method_info,
-        } = helpers::get_token_pm_type_mandate_details(
-            state,
-            request,
-            mandate_type.to_owned(),
-            merchant_account,
-            key_store,
-        )
-        .await?;
-
         let browser_info = request
             .browser_info
             .clone()
@@ -99,6 +81,9 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
                 field_name: "browser_info",
             })?;
 
+        let recurring_details = request.recurring_details.clone();
+        let customer_acceptance = request.customer_acceptance.clone().map(From::from);
+
         payment_attempt = db
             .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
                 &payment_intent.payment_id,
@@ -109,6 +94,33 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        let mandate_type = m_helpers::get_mandate_type(
+            request.mandate_data.clone(),
+            request.off_session,
+            payment_intent.setup_future_usage,
+            request.customer_acceptance.clone(),
+            request.payment_token.clone(),
+        )
+        .change_context(errors::ApiErrorResponse::MandateValidationFailed {
+            reason: "Expected one out of recurring_details and mandate_data but got both".into(),
+        })?;
+
+        let m_helpers::MandateGenericData {
+            token,
+            payment_method,
+            payment_method_type,
+            mandate_data,
+            recurring_mandate_payment_data,
+            mandate_connector,
+            payment_method_info,
+        } = helpers::get_token_pm_type_mandate_details(
+            state,
+            request,
+            mandate_type.to_owned(),
+            merchant_account,
+            key_store,
+        )
+        .await?;
         let token = token.or_else(|| payment_attempt.payment_token.clone());
 
         if let Some(payment_method) = payment_method {
@@ -259,7 +271,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             mandate_id: None,
             mandate_connector,
             setup_mandate,
-            customer_acceptance: None,
+            customer_acceptance,
             token,
             token_data,
             address: PaymentAddress::new(
@@ -293,7 +305,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             authorizations: vec![],
             authentication: None,
             frm_metadata: None,
-            recurring_details: request.recurring_details.clone(),
+            recurring_details,
         };
 
         let customer_details = Some(CustomerDetails {
@@ -309,6 +321,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details,
             payment_data,
             business_profile,
+            mandate_type,
         };
 
         Ok(get_trackers_response)
@@ -456,7 +469,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
 
         helpers::validate_payment_method_fields_present(request)?;
 
-        let mandate_type =
+        let _mandate_type =
             helpers::validate_mandate(request, payments::is_operation_confirm(self))?;
 
         helpers::validate_recurring_details_and_token(
@@ -470,7 +483,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: payment_id.and_then(|id| core_utils::validate_id(id, "payment_id"))?,
-                mandate_type,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: matches!(
                     request.retry_action,
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 8e66f436817..458e05fd2e9 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -15,7 +15,7 @@ use crate::{
         authentication,
         blocklist::utils as blocklist_utils,
         errors::{self, CustomResult, RouterResult, StorageErrorExt},
-        mandate::helpers::MandateGenericData,
+        mandate::helpers as m_helpers,
         payment_methods::PaymentMethodRetrieve,
         payments::{
             self, helpers, operations, populate_surcharge_details, CustomerDetails, PaymentAddress,
@@ -47,7 +47,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &api::PaymentsRequest,
-        mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         auth_flow: services::AuthFlow,
@@ -62,47 +61,18 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             .change_context(errors::ApiErrorResponse::PaymentNotFound)?;
 
         // Stage 1
-        let store = state.clone().store;
+        let store = &*state.store;
         let m_merchant_id = merchant_id.clone();
-        let payment_intent_fut = tokio::spawn(
-            async move {
-                store
-                    .find_payment_intent_by_payment_id_merchant_id(
-                        &payment_id,
-                        m_merchant_id.as_str(),
-                        storage_scheme,
-                    )
-                    .map(|x| x.change_context(errors::ApiErrorResponse::PaymentNotFound))
-                    .await
-            }
-            .in_current_span(),
-        );
-
-        let m_state = state.clone();
-        let m_mandate_type = mandate_type.clone();
-        let m_merchant_account = merchant_account.clone();
-        let m_request = request.clone();
-        let m_key_store = key_store.clone();
-
-        let mandate_details_fut = tokio::spawn(
-            async move {
-                helpers::get_token_pm_type_mandate_details(
-                    &m_state,
-                    &m_request,
-                    m_mandate_type,
-                    &m_merchant_account,
-                    &m_key_store,
-                )
-                .await
-            }
-            .in_current_span(),
-        );
 
         // Parallel calls - level 0
-        let (mut payment_intent, mandate_details) = tokio::try_join!(
-            utils::flatten_join_error(payment_intent_fut),
-            utils::flatten_join_error(mandate_details_fut)
-        )?;
+        let mut payment_intent = store
+            .find_payment_intent_by_payment_id_merchant_id(
+                &payment_id,
+                m_merchant_id.as_str(),
+                storage_scheme,
+            )
+            .await
+            .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
         if let Some(order_details) = &request.order_details {
             helpers::validate_order_details_amount(
@@ -352,16 +322,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             .setup_future_usage
             .or(payment_intent.setup_future_usage);
 
-        let MandateGenericData {
-            token,
-            payment_method,
-            payment_method_type,
-            mandate_data,
-            recurring_mandate_payment_data,
-            mandate_connector,
-            payment_method_info,
-        } = mandate_details;
-
         let browser_info = request
             .browser_info
             .clone()
@@ -374,6 +334,8 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             })?;
         let customer_acceptance = request.customer_acceptance.clone().map(From::from);
 
+        let recurring_details = request.recurring_details.clone();
+
         helpers::validate_card_data(
             request
                 .payment_method_data
@@ -381,46 +343,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
                 .map(|pmd| pmd.payment_method_data.clone()),
         )?;
 
-        let token = token.or_else(|| payment_attempt.payment_token.clone());
-
-        helpers::validate_pm_or_token_given(
-            &request.payment_method,
-            &request
-                .payment_method_data
-                .as_ref()
-                .map(|pmd| pmd.payment_method_data.clone()),
-            &request.payment_method_type,
-            &mandate_type,
-            &token,
-        )?;
-
-        let (token_data, payment_method_info) = if let Some(token) = token.clone() {
-            let token_data = helpers::retrieve_payment_token_data(
-                state,
-                token,
-                payment_method.or(payment_attempt.payment_method),
-            )
-            .await?;
-
-            let payment_method_info = helpers::retrieve_payment_method_from_db_with_token_data(
-                state,
-                &token_data,
-                storage_scheme,
-            )
-            .await?;
-
-            (Some(token_data), payment_method_info)
-        } else {
-            (None, payment_method_info)
-        };
-
-        payment_attempt.payment_method = payment_method.or(payment_attempt.payment_method);
         payment_attempt.browser_info = browser_info;
-        payment_attempt.payment_method_type = payment_method_type
-            .or(payment_attempt.payment_method_type)
-            .or(payment_method_info
-                .as_ref()
-                .and_then(|pm_info| pm_info.payment_method_type));
 
         payment_attempt.payment_experience = request
             .payment_experience
@@ -485,23 +408,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             .clone()
             .or(payment_attempt.business_sub_label);
 
-        // The operation merges mandate data from both request and payment_attempt
-        let setup_mandate = mandate_data.map(|mut sm| {
-            sm.mandate_type = payment_attempt.mandate_details.clone().or(sm.mandate_type);
-            sm.update_mandate_id = payment_attempt
-                .mandate_data
-                .clone()
-                .and_then(|mandate| mandate.update_mandate_id)
-                .or(sm.update_mandate_id);
-            sm
-        });
-
-        let mandate_details_present =
-            payment_attempt.mandate_details.is_some() || request.mandate_data.is_some();
-        helpers::validate_mandate_data_and_future_usage(
-            payment_intent.setup_future_usage,
-            mandate_details_present,
-        )?;
         let n_request_payment_method_data = request
             .payment_method_data
             .as_ref()
@@ -553,13 +459,112 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             }
             .in_current_span(),
         );
+        let mandate_type = m_helpers::get_mandate_type(
+            request.mandate_data.clone(),
+            request.off_session,
+            payment_intent.setup_future_usage,
+            request.customer_acceptance.clone(),
+            request.payment_token.clone(),
+        )
+        .change_context(errors::ApiErrorResponse::MandateValidationFailed {
+            reason: "Expected one out of recurring_details and mandate_data but got both".into(),
+        })?;
+
+        let m_state = state.clone();
+        let m_mandate_type = mandate_type.clone();
+        let m_merchant_account = merchant_account.clone();
+        let m_request = request.clone();
+        let m_key_store = key_store.clone();
+
+        let mandate_details_fut = tokio::spawn(
+            async move {
+                helpers::get_token_pm_type_mandate_details(
+                    &m_state,
+                    &m_request,
+                    m_mandate_type,
+                    &m_merchant_account,
+                    &m_key_store,
+                )
+                .await
+            }
+            .in_current_span(),
+        );
 
         // Parallel calls - level 2
-        let (additional_pm_data, payment_method_billing) = tokio::try_join!(
+        let (mandate_details, additional_pm_data, payment_method_billing) = tokio::try_join!(
+            utils::flatten_join_error(mandate_details_fut),
             utils::flatten_join_error(additional_pm_data_fut),
             utils::flatten_join_error(payment_method_billing_future),
         )?;
 
+        let m_helpers::MandateGenericData {
+            token,
+            payment_method,
+            payment_method_type,
+            mandate_data,
+            recurring_mandate_payment_data,
+            mandate_connector,
+            payment_method_info,
+        } = mandate_details;
+
+        payment_attempt.payment_method = payment_method.or(payment_attempt.payment_method);
+
+        payment_attempt.payment_method_type = payment_method_type
+            .or(payment_attempt.payment_method_type)
+            .or(payment_method_info
+                .as_ref()
+                .and_then(|pm_info| pm_info.payment_method_type));
+
+        let token = token.or_else(|| payment_attempt.payment_token.clone());
+
+        helpers::validate_pm_or_token_given(
+            &request.payment_method,
+            &request
+                .payment_method_data
+                .as_ref()
+                .map(|pmd| pmd.payment_method_data.clone()),
+            &request.payment_method_type,
+            &mandate_type,
+            &token,
+        )?;
+
+        let (token_data, payment_method_info) = if let Some(token) = token.clone() {
+            let token_data = helpers::retrieve_payment_token_data(
+                state,
+                token,
+                payment_method.or(payment_attempt.payment_method),
+            )
+            .await?;
+
+            let payment_method_info = helpers::retrieve_payment_method_from_db_with_token_data(
+                state,
+                &token_data,
+                storage_scheme,
+            )
+            .await?;
+
+            (Some(token_data), payment_method_info)
+        } else {
+            (None, payment_method_info)
+        };
+        // The operation merges mandate data from both request and payment_attempt
+        let setup_mandate = mandate_data.map(|mut sm| {
+            sm.mandate_type = payment_attempt.mandate_details.clone().or(sm.mandate_type);
+            sm.update_mandate_id = payment_attempt
+                .mandate_data
+                .clone()
+                .and_then(|mandate| mandate.update_mandate_id)
+                .or(sm.update_mandate_id);
+            sm
+        });
+
+        let mandate_details_present =
+            payment_attempt.mandate_details.is_some() || request.mandate_data.is_some();
+        helpers::validate_mandate_data_and_future_usage(
+            payment_intent.setup_future_usage,
+            mandate_details_present,
+        )?;
+
         let payment_method_data_after_card_bin_call = request
             .payment_method_data
             .as_ref()
@@ -627,7 +632,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             authorizations: vec![],
             frm_metadata: request.frm_metadata.clone(),
             authentication,
-            recurring_details: request.recurring_details.clone(),
+            recurring_details,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -635,6 +640,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: Some(customer_details),
             payment_data,
             business_profile,
+            mandate_type,
         };
 
         Ok(get_trackers_response)
@@ -1212,7 +1218,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
 
         helpers::validate_payment_method_fields_present(request)?;
 
-        let mandate_type =
+        let _mandate_type =
             helpers::validate_mandate(request, payments::is_operation_confirm(self))?;
 
         helpers::validate_recurring_details_and_token(
@@ -1231,7 +1237,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: payment_id.and_then(|id| core_utils::validate_id(id, "payment_id"))?,
-                mandate_type,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: matches!(
                     request.retry_action,
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index c6e95b176c1..944580c4f08 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -21,7 +21,7 @@ use crate::{
     consts,
     core::{
         errors::{self, CustomResult, RouterResult, StorageErrorExt},
-        mandate::helpers::MandateGenericData,
+        mandate::helpers as m_helpers,
         payment_link,
         payment_methods::PaymentMethodRetrieve,
         payments::{self, helpers, operations, CustomerDetails, PaymentAddress, PaymentData},
@@ -58,7 +58,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &api::PaymentsRequest,
-        mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         merchant_key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -106,8 +105,22 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
                     id: profile_id.to_string(),
                 })?
         };
+        let customer_acceptance = request.customer_acceptance.clone().map(From::from);
+
+        let recurring_details = request.recurring_details.clone();
+
+        let mandate_type = m_helpers::get_mandate_type(
+            request.mandate_data.clone(),
+            request.off_session,
+            request.setup_future_usage,
+            request.customer_acceptance.clone(),
+            request.payment_token.clone(),
+        )
+        .change_context(errors::ApiErrorResponse::MandateValidationFailed {
+            reason: "Expected one out of recurring_details and mandate_data but got both".into(),
+        })?;
 
-        let MandateGenericData {
+        let m_helpers::MandateGenericData {
             token,
             payment_method,
             payment_method_type,
@@ -118,7 +131,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         } = helpers::get_token_pm_type_mandate_details(
             state,
             request,
-            mandate_type,
+            mandate_type.clone(),
             merchant_account,
             merchant_key_store,
         )
@@ -375,8 +388,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         // The operation merges mandate data from both request and payment_attempt
         let setup_mandate = mandate_data.map(MandateData::from);
 
-        let customer_acceptance = request.customer_acceptance.clone().map(From::from);
-
         let surcharge_details = request.surcharge_details.map(|request_surcharge_details| {
             payments::types::SurchargeDetails::from((&request_surcharge_details, &payment_attempt))
         });
@@ -434,7 +445,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             authorizations: vec![],
             authentication: None,
             frm_metadata: request.frm_metadata.clone(),
-            recurring_details: request.recurring_details.clone(),
+            recurring_details,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -442,6 +453,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: Some(customer_details),
             payment_data,
             business_profile,
+            mandate_type,
         };
 
         Ok(get_trackers_response)
@@ -726,7 +738,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id,
-                mandate_type,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: matches!(
                     request.retry_action,
diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs
index e1d58b032aa..506f372e947 100644
--- a/crates/router/src/core/payments/operations/payment_reject.rs
+++ b/crates/router/src/core/payments/operations/payment_reject.rs
@@ -37,7 +37,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         _request: &PaymentsCancelRequest,
-        _mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -182,6 +181,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: None,
             payment_data,
             business_profile,
+            mandate_type: None,
         };
 
         Ok(get_trackers_response)
@@ -273,7 +273,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, PaymentsCan
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: api::PaymentIdType::PaymentIntentId(request.payment_id.to_owned()),
-                mandate_type: None,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: false,
             },
diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs
index 25b419e3222..19075759ef1 100644
--- a/crates/router/src/core/payments/operations/payment_session.rs
+++ b/crates/router/src/core/payments/operations/payment_session.rs
@@ -39,7 +39,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &api::PaymentsSessionRequest,
-        _mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -207,6 +206,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: Some(customer_details),
             payment_data,
             business_profile,
+            mandate_type: None,
         };
 
         Ok(get_trackers_response)
@@ -276,7 +276,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: api::PaymentIdType::PaymentIntentId(given_payment_id),
-                mandate_type: None,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: false,
             },
diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs
index 560d2014bae..9a952f0a526 100644
--- a/crates/router/src/core/payments/operations/payment_start.rs
+++ b/crates/router/src/core/payments/operations/payment_start.rs
@@ -38,7 +38,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         _request: &api::PaymentsStartRequest,
-        _mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -194,6 +193,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: Some(customer_details),
             payment_data,
             business_profile,
+            mandate_type: None,
         };
 
         Ok(get_trackers_response)
@@ -252,7 +252,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: api::PaymentIdType::PaymentIntentId(payment_id),
-                mandate_type: None,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: false,
             },
diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs
index 6739c2c3ba7..5335c273b6e 100644
--- a/crates/router/src/core/payments/operations/payment_status.rs
+++ b/crates/router/src/core/payments/operations/payment_status.rs
@@ -206,7 +206,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &api::PaymentsRetrieveRequest,
-        _mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -494,6 +493,7 @@ async fn get_tracker_for_sync<
         customer_details: None,
         payment_data,
         business_profile,
+        mandate_type: None,
     };
 
     Ok(get_trackers_response)
@@ -522,7 +522,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: request.resource_id.clone(),
-                mandate_type: None,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: false,
             },
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index 934c0edfddd..fce8bd0f0be 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -13,7 +13,7 @@ use super::{BoxedOperation, Domain, GetTracker, Operation, UpdateTracker, Valida
 use crate::{
     core::{
         errors::{self, CustomResult, RouterResult, StorageErrorExt},
-        mandate::helpers::MandateGenericData,
+        mandate::helpers as m_helpers,
         payment_methods::PaymentMethodRetrieve,
         payments::{self, helpers, operations, CustomerDetails, PaymentAddress, PaymentData},
         utils as core_utils,
@@ -43,7 +43,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &api::PaymentsRequest,
-        mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         key_store: &domain::MerchantKeyStore,
         auth_flow: services::AuthFlow,
@@ -98,23 +97,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
 
         helpers::authenticate_client_secret(request.client_secret.as_ref(), &payment_intent)?;
 
-        let MandateGenericData {
-            token,
-            payment_method,
-            payment_method_type,
-            mandate_data,
-            recurring_mandate_payment_data,
-            mandate_connector,
-            payment_method_info,
-        } = helpers::get_token_pm_type_mandate_details(
-            state,
-            request,
-            mandate_type.to_owned(),
-            merchant_account,
-            key_store,
-        )
-        .await?;
-
         payment_intent = db
             .find_payment_intent_by_payment_id_merchant_id(&payment_id, merchant_id, storage_scheme)
             .await
@@ -136,6 +118,36 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        let customer_acceptance = request.customer_acceptance.clone().map(From::from);
+        let recurring_details = request.recurring_details.clone();
+
+        let mandate_type = m_helpers::get_mandate_type(
+            request.mandate_data.clone(),
+            request.off_session,
+            payment_intent.setup_future_usage,
+            request.customer_acceptance.clone(),
+            request.payment_token.clone(),
+        )
+        .change_context(errors::ApiErrorResponse::MandateValidationFailed {
+            reason: "Expected one out of recurring_details and mandate_data but got both".into(),
+        })?;
+
+        let m_helpers::MandateGenericData {
+            token,
+            payment_method,
+            payment_method_type,
+            mandate_data,
+            recurring_mandate_payment_data,
+            mandate_connector,
+            payment_method_info,
+        } = helpers::get_token_pm_type_mandate_details(
+            state,
+            request,
+            mandate_type.to_owned(),
+            merchant_account,
+            key_store,
+        )
+        .await?;
         helpers::validate_amount_to_capture_and_capture_method(Some(&payment_attempt), request)?;
 
         helpers::validate_request_amount_and_amount_to_capture(
@@ -390,7 +402,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             .to_not_found_response(errors::ApiErrorResponse::BusinessProfileNotFound {
                 id: profile_id.to_string(),
             })?;
-        let customer_acceptance = request.customer_acceptance.clone().map(From::from);
+
         let surcharge_details = request.surcharge_details.map(|request_surcharge_details| {
             payments::types::SurchargeDetails::from((&request_surcharge_details, &payment_attempt))
         });
@@ -439,7 +451,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             authorizations: vec![],
             authentication: None,
             frm_metadata: request.frm_metadata.clone(),
-            recurring_details: request.recurring_details.clone(),
+            recurring_details,
         };
 
         let get_trackers_response = operations::GetTrackerResponse {
@@ -447,6 +459,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: Some(customer_details),
             payment_data,
             business_profile,
+            mandate_type,
         };
 
         Ok(get_trackers_response)
@@ -750,7 +763,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
 
         helpers::validate_payment_method_fields_present(request)?;
 
-        let mandate_type = helpers::validate_mandate(request, false)?;
+        let _mandate_type = helpers::validate_mandate(request, false)?;
 
         helpers::validate_recurring_details_and_token(
             &request.recurring_details,
@@ -763,7 +776,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve> ValidateRequest<F, api::Paymen
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: payment_id.and_then(|id| core_utils::validate_id(id, "payment_id"))?,
-                mandate_type,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: matches!(
                     request.retry_action,
diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
index be2b127ff67..e453ec0106d 100644
--- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
+++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
@@ -42,7 +42,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
         state: &'a AppState,
         payment_id: &api::PaymentIdType,
         request: &PaymentsIncrementalAuthorizationRequest,
-        _mandate_type: Option<api::MandateTransactionType>,
         merchant_account: &domain::MerchantAccount,
         _key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
@@ -160,6 +159,7 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             customer_details: None,
             payment_data,
             business_profile,
+            mandate_type: None,
         };
 
         Ok(get_trackers_response)
@@ -275,7 +275,6 @@ impl<F: Send + Clone, Ctx: PaymentMethodRetrieve>
             operations::ValidateResult {
                 merchant_id: &merchant_account.merchant_id,
                 payment_id: api::PaymentIdType::PaymentIntentId(request.payment_id.to_owned()),
-                mandate_type: None,
                 storage_scheme: merchant_account.storage_scheme,
                 requeue: false,
             },
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index ef54cedcb8d..34e121bd337 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -778,6 +778,7 @@ pub async fn decide_payout_connector(
         TransactionData::<()>::Payout(payout_data),
         routing_data,
         eligible_connectors,
+        None,
     )
     .await
 }

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

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

## Description
This PR supports creating a mandate by passing `payment_token` with , `setup_future_usage:off_session` and `customer_acceptance`


### Additional Changes

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

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

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


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

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


## How did you test it?
- Create an MA and MCA
- `Step 1:`Make a  save card payment
- `Step 2:` List Customer Payment Method, get the `payment_token`
- `Step 3:` Use the `payment token` to create the mandate 
> Create
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_1ORGV1egb2qN8z8UoZE7pCkv7cUMiXbdMwZYZJNX8qjm2aTW9uAcX2d3ezX4g3KY' \
--data-raw '{
    "amount": 6777,
    "currency": "USD",
    "confirm": false,
    
    "customer_id": "new-c77",
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
     "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
 
"setup_future_usage":"off_session",
    "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"
        }
    },

    "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"
        }
    },
    "connector_metadata": {
        "noon": {
            "order_category": "pay"
        }
    }
}'
```
>Confirm
```
curl --location 'http://localhost:8080/payments/pay_up5SZAykikpNXZqLivDP/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_1ORGV1egb2qN8z8UoZE7pCkv7cUMiXbdMwZYZJNX8qjm2aTW9uAcX2d3ezX4g3KY' \
--data '{
    "confirm": true,
          "payment_method": "card",
    "payment_method_type": "credit",
   "payment_token": "{{payment_token}}",
      "customer_acceptance": {
            "acceptance_type": "offline",
            "accepted_at": "1963-05-03T04:07:52.723Z",
            "online": {
                "ip_address": "in sit",
                "user_agent": "amet irure esse"
            }}
}'
```

- `Step4:`  Do a recurring payment, with `off_session:true`
>Create 
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_1ORGV1egb2qN8z8UoZE7pCkv7cUMiXbdMwZYZJNX8qjm2aTW9uAcX2d3ezX4g3KY' \
--data-raw '{
    "amount": 1000,
    "currency": "USD",
    "confirm": true,
    
    "customer_id": "new-c77",
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
       "off_session": true,
    "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"
        }
    },

    
      "recurring_details":{
        "type":"payment_method_id",
        "data":"{{payment_method_id}}"
    },

    "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"
        }
    },
    "connector_metadata": {
        "noon": {
            "order_category": "pay"
        }
    }
}'
```

-> UseCase 2 (for doing a recurring payment with `setup_future_usage:off_session`):
- Create an MA and MCA with cybersource
- Follow the above steps From 1 - 3
- Do a List Customer PaymentMethods to get the token
- Do a recurring_payment with `payment_token + setup_future_usage:off_session` and no `customer_acceptance`
>Create 
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_EDXOKcN5iMxjonvVaA0bjl2Qn37J15SxoQ6QX3QFHEgA8P1HGj9CLj4sClVM9dB4' \
--data-raw '{
    "amount": 6777,
    "currency": "USD",
    "confirm": false,
    "customer_id": "new-c77",
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
     "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
 "setup_future_usage":"off_session",
    "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"
        }
    },

    "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"
        }
    },
    "connector_metadata": {
        "noon": {
            "order_category": "pay"
        }
    }
}'
```
>Confirm
```
curl --location 'http://localhost:8080/payments/pay_DpS8eVBQRvmlHIvWPrJK/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_EDXOKcN5iMxjonvVaA0bjl2Qn37J15SxoQ6QX3QFHEgA8P1HGj9CLj4sClVM9dB4' \
--data '{
    "confirm": true,
    "payment_token": "{{payment_token}}"

}'
```

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