Bug: [FEATURE] Supporting processors token in Payments API



### Feature Description

During the transition phase of Hyperswitch, Merchant should be able to send the processor's token to Hyperswitch to process MIT transaction. This is because, Merchant will not have the card data to migrate from Processor to Hyperswitch. 

### Possible Implementation

**#Solution 1**
In payments create+confirm API, we will add new enum processor_token in type under recurring_details  to support connector data. We will start supporting Bambora’s and we will slowly adopt every connectors.

- This field will be a replaceable field for payment method id. Merchant can either pass payment_method_id or {recurring_details.data:{processor_payment_token: "value", connector:"BAMBORA"}}. Connector can be enum. 

- Based on this field, we will fork the main flow, which will skip the payment_method part and use this data given in the request. 

**Expected Flow:** 
- Merchant needs to create customer before calling this API. 
- Call Payments API

**Technical changes information:**
- Routing is not involved - (No changes)
- Customer related process can also be ignored. (No changes, as merchant creates customer before calling this API)
- Populate connector_mandate_id in `router_data` from the request, instead of fetching from database. 

**In V1 we can add if else to handle the flow, in v2, we will follow separate handler with the same route.** 

**Flow shall be in the following order,** 
- Get tracker (create+confirm)
- Get customer (create + confirm)
- Skip to call connector (create + confirm). 
- response handling (create + confirm )


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

None
diff --git a/crates/api_models/src/mandates.rs b/crates/api_models/src/mandates.rs
index f4089a16c22..dc61aa08b0c 100644
--- a/crates/api_models/src/mandates.rs
+++ b/crates/api_models/src/mandates.rs
@@ -120,4 +120,14 @@ pub struct MandateListConstraints {
 pub enum RecurringDetails {
     MandateId(String),
     PaymentMethodId(String),
+    ProcessorPaymentToken(ProcessorPaymentToken),
+}
+
+/// Processor payment token for MIT payments where payment_method_data is not available
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
+pub struct ProcessorPaymentToken {
+    pub processor_payment_token: String,
+    #[schema(value_type = Connector, example = "stripe")]
+    pub connector: api_enums::Connector,
+    pub merchant_connector_id: String,
 }
diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs
index 2d390b0b34c..bdea1fe52a7 100644
--- a/crates/diesel_models/src/payment_intent.rs
+++ b/crates/diesel_models/src/payment_intent.rs
@@ -68,6 +68,7 @@ pub struct PaymentIntent {
     pub billing_details: Option<Encryption>,
     pub merchant_order_reference_id: Option<String>,
     pub shipping_details: Option<Encryption>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
 
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "payment_v2")))]
@@ -128,6 +129,7 @@ pub struct PaymentIntent {
     pub billing_details: Option<Encryption>,
     pub merchant_order_reference_id: Option<String>,
     pub shipping_details: Option<Encryption>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
 
 #[derive(
@@ -187,6 +189,7 @@ pub struct PaymentIntentNew {
     pub billing_details: Option<Encryption>,
     pub merchant_order_reference_id: Option<String>,
     pub shipping_details: Option<Encryption>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -291,6 +294,7 @@ pub struct PaymentIntentUpdateFields {
     pub billing_details: Option<Encryption>,
     pub merchant_order_reference_id: Option<String>,
     pub shipping_details: Option<Encryption>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
 
 #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)]
@@ -331,6 +335,7 @@ pub struct PaymentIntentUpdateInternal {
     pub billing_details: Option<Encryption>,
     pub merchant_order_reference_id: Option<String>,
     pub shipping_details: Option<Encryption>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
 
 impl PaymentIntentUpdate {
@@ -370,6 +375,7 @@ impl PaymentIntentUpdate {
             billing_details,
             merchant_order_reference_id,
             shipping_details,
+            is_payment_processor_token_flow,
         } = self.into();
         PaymentIntent {
             amount: amount.unwrap_or(source.amount),
@@ -412,6 +418,8 @@ impl PaymentIntentUpdate {
             merchant_order_reference_id: merchant_order_reference_id
                 .or(source.merchant_order_reference_id),
             shipping_details: shipping_details.or(source.shipping_details),
+            is_payment_processor_token_flow: is_payment_processor_token_flow
+                .or(source.is_payment_processor_token_flow),
             ..source
         }
     }
@@ -458,6 +466,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::Update(value) => Self {
                 amount: Some(value.amount),
@@ -495,6 +504,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 surcharge_applicable: None,
                 incremental_authorization_allowed: None,
                 authorization_count: None,
+                is_payment_processor_token_flow: value.is_payment_processor_token_flow,
             },
             PaymentIntentUpdate::PaymentCreateUpdate {
                 return_url,
@@ -539,6 +549,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::PGStatusUpdate {
                 status,
@@ -579,6 +590,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::MerchantStatusUpdate {
                 status,
@@ -620,6 +632,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::ResponseUpdate {
                 // amount,
@@ -669,6 +682,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate {
                 active_attempt_id,
@@ -709,6 +723,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::StatusAndAttemptUpdate {
                 status,
@@ -750,6 +765,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::ApproveUpdate {
                 status,
@@ -790,6 +806,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::RejectUpdate {
                 status,
@@ -830,6 +847,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::SurchargeApplicableUpdate {
                 surcharge_applicable,
@@ -869,6 +887,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } => Self {
                 amount: Some(amount),
@@ -905,6 +924,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::AuthorizationCountUpdate {
                 authorization_count,
@@ -943,6 +963,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::CompleteAuthorizeUpdate {
                 shipping_address_id,
@@ -981,6 +1002,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
             PaymentIntentUpdate::ManualUpdate { status, updated_by } => Self {
                 status,
@@ -1017,6 +1039,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: None,
                 merchant_order_reference_id: None,
                 shipping_details: None,
+                is_payment_processor_token_flow: None,
             },
         }
     }
diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs
index d2c66fc37fe..e272c71ba24 100644
--- a/crates/diesel_models/src/schema.rs
+++ b/crates/diesel_models/src/schema.rs
@@ -897,6 +897,7 @@ diesel::table! {
         #[max_length = 255]
         merchant_order_reference_id -> Nullable<Varchar>,
         shipping_details -> Nullable<Bytea>,
+        is_payment_processor_token_flow -> Nullable<Bool>,
     }
 }
 
diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs
index 23f9dff31ea..246f37a4e49 100644
--- a/crates/diesel_models/src/schema_v2.rs
+++ b/crates/diesel_models/src/schema_v2.rs
@@ -897,6 +897,7 @@ diesel::table! {
         #[max_length = 255]
         merchant_order_reference_id -> Nullable<Varchar>,
         shipping_details -> Nullable<Bytea>,
+        is_payment_processor_token_flow -> Nullable<Bool>,
     }
 }
 
diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs
index ac79bc1a942..3f7cfde2f78 100644
--- a/crates/hyperswitch_domain_models/src/payments.rs
+++ b/crates/hyperswitch_domain_models/src/payments.rs
@@ -66,4 +66,5 @@ pub struct PaymentIntent {
     pub billing_details: Option<Encryptable<Secret<serde_json::Value>>>,
     pub merchant_order_reference_id: Option<String>,
     pub shipping_details: Option<Encryptable<Secret<serde_json::Value>>>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
index 15c5aded500..8fe01d380e8 100644
--- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
+++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
@@ -541,6 +541,7 @@ impl behaviour::Conversion for PaymentIntent {
             billing_details: self.billing_details.map(Encryption::from),
             merchant_order_reference_id: self.merchant_order_reference_id,
             shipping_details: self.shipping_details.map(Encryption::from),
+            is_payment_processor_token_flow: self.is_payment_processor_token_flow,
         })
     }
     async fn convert_back(
@@ -613,6 +614,7 @@ impl behaviour::Conversion for PaymentIntent {
                     .shipping_details
                     .async_lift(inner_decrypt)
                     .await?,
+                is_payment_processor_token_flow: storage_model.is_payment_processor_token_flow,
             })
         }
         .await
@@ -670,6 +672,7 @@ impl behaviour::Conversion for PaymentIntent {
             billing_details: self.billing_details.map(Encryption::from),
             merchant_order_reference_id: self.merchant_order_reference_id,
             shipping_details: self.shipping_details.map(Encryption::from),
+            is_payment_processor_token_flow: self.is_payment_processor_token_flow,
         })
     }
 }
@@ -729,6 +732,7 @@ impl behaviour::Conversion for PaymentIntent {
             billing_details: self.billing_details.map(Encryption::from),
             merchant_order_reference_id: self.merchant_order_reference_id,
             shipping_details: self.shipping_details.map(Encryption::from),
+            is_payment_processor_token_flow: self.is_payment_processor_token_flow,
         })
     }
 
@@ -802,6 +806,7 @@ impl behaviour::Conversion for PaymentIntent {
                     .shipping_details
                     .async_lift(inner_decrypt)
                     .await?,
+                is_payment_processor_token_flow: storage_model.is_payment_processor_token_flow,
             })
         }
         .await
@@ -859,6 +864,7 @@ impl behaviour::Conversion for PaymentIntent {
             billing_details: self.billing_details.map(Encryption::from),
             merchant_order_reference_id: self.merchant_order_reference_id,
             shipping_details: self.shipping_details.map(Encryption::from),
+            is_payment_processor_token_flow: self.is_payment_processor_token_flow,
         })
     }
 }
diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs
index 8033ec7706c..90e3619f02e 100644
--- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs
+++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs
@@ -143,6 +143,7 @@ pub struct PaymentIntentNew {
     pub customer_details: Option<Encryptable<Secret<serde_json::Value>>>,
     pub billing_details: Option<Encryptable<Secret<serde_json::Value>>>,
     pub shipping_details: Option<Encryptable<Secret<serde_json::Value>>>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
 
 #[derive(Debug, Clone, Serialize)]
@@ -172,6 +173,7 @@ pub struct PaymentIntentUpdateFields {
     pub billing_details: Option<Encryptable<Secret<serde_json::Value>>>,
     pub merchant_order_reference_id: Option<String>,
     pub shipping_details: Option<Encryptable<Secret<serde_json::Value>>>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
 
 #[derive(Debug, Clone, Serialize)]
@@ -288,6 +290,7 @@ pub struct PaymentIntentUpdateInternal {
     pub billing_details: Option<Encryptable<Secret<serde_json::Value>>>,
     pub merchant_order_reference_id: Option<String>,
     pub shipping_details: Option<Encryptable<Secret<serde_json::Value>>>,
+    pub is_payment_processor_token_flow: Option<bool>,
 }
 
 impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
@@ -329,6 +332,7 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 billing_details: value.billing_details,
                 merchant_order_reference_id: value.merchant_order_reference_id,
                 shipping_details: value.shipping_details,
+                is_payment_processor_token_flow: value.is_payment_processor_token_flow,
                 ..Default::default()
             },
             PaymentIntentUpdate::PaymentCreateUpdate {
@@ -531,6 +535,7 @@ impl From<PaymentIntentUpdate> for DieselPaymentIntentUpdate {
                     billing_details: value.billing_details.map(Encryption::from),
                     merchant_order_reference_id: value.merchant_order_reference_id,
                     shipping_details: value.shipping_details.map(Encryption::from),
+                    is_payment_processor_token_flow: value.is_payment_processor_token_flow,
                 }))
             }
             PaymentIntentUpdate::PaymentCreateUpdate {
@@ -674,6 +679,7 @@ impl From<PaymentIntentUpdateInternal> for diesel_models::PaymentIntentUpdateInt
             billing_details,
             merchant_order_reference_id,
             shipping_details,
+            is_payment_processor_token_flow,
         } = value;
 
         Self {
@@ -711,6 +717,7 @@ impl From<PaymentIntentUpdateInternal> for diesel_models::PaymentIntentUpdateInt
             billing_details: billing_details.map(Encryption::from),
             merchant_order_reference_id,
             shipping_details: shipping_details.map(Encryption::from),
+            is_payment_processor_token_flow,
         }
     }
 }
diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs
index b525c3aa930..4bbbfb8a7f1 100644
--- a/crates/openapi/src/openapi.rs
+++ b/crates/openapi/src/openapi.rs
@@ -465,6 +465,7 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::mandates::MandateResponse,
         api_models::mandates::MandateCardDetails,
         api_models::mandates::RecurringDetails,
+        api_models::mandates::ProcessorPaymentToken,
         api_models::ephemeral_key::EphemeralKeyCreateResponse,
         api_models::payments::CustomerDetails,
         api_models::payments::GiftCardData,
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 78d0d8fd79d..cbc912bd0c2 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -1510,15 +1510,20 @@ where
     )
     .await?;
 
-    let merchant_recipient_data = payment_data
-        .get_merchant_recipient_data(
-            state,
-            merchant_account,
-            key_store,
-            &merchant_connector_account,
-            &connector,
-        )
-        .await?;
+    let merchant_recipient_data =
+        if let Some(true) = payment_data.payment_intent.is_payment_processor_token_flow {
+            None
+        } else {
+            payment_data
+                .get_merchant_recipient_data(
+                    state,
+                    merchant_account,
+                    key_store,
+                    &merchant_connector_account,
+                    &connector,
+                )
+                .await?
+        };
 
     let mut router_data = payment_data
         .construct_router_data(
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 53fc1e1938c..80ab9ebaf90 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -446,6 +446,20 @@ pub async fn get_token_pm_type_mandate_details(
         Some(api::MandateTransactionType::RecurringMandateTransaction) => {
             match &request.recurring_details {
                 Some(recurring_details) => match recurring_details {
+                    RecurringDetails::ProcessorPaymentToken(processor_payment_token) => (
+                        None,
+                        request.payment_method,
+                        None,
+                        None,
+                        None,
+                        Some(payments::MandateConnectorDetails {
+                            connector: processor_payment_token.connector.to_string(),
+                            merchant_connector_id: Some(
+                                processor_payment_token.merchant_connector_id.clone(),
+                            ),
+                        }),
+                        None,
+                    ),
                     RecurringDetails::MandateId(mandate_id) => {
                         let mandate_generic_data = get_token_for_recurring_mandate(
                             state,
@@ -1168,26 +1182,31 @@ pub fn create_complete_authorize_url(
 }
 
 fn validate_recurring_mandate(req: api::MandateValidationFields) -> RouterResult<()> {
-    req.recurring_details
-        .check_value_present("recurring_details")?;
+    let recurring_details = req
+        .recurring_details
+        .get_required_value("recurring_details")?;
 
-    req.customer_id.check_value_present("customer_id")?;
+    match recurring_details {
+        RecurringDetails::ProcessorPaymentToken(_) => Ok(()),
+        _ => {
+            req.customer_id.check_value_present("customer_id")?;
 
-    let confirm = req.confirm.get_required_value("confirm")?;
-    if !confirm {
-        Err(report!(errors::ApiErrorResponse::PreconditionFailed {
-            message: "`confirm` must be `true` for mandates".into()
-        }))?
-    }
+            let confirm = req.confirm.get_required_value("confirm")?;
+            if !confirm {
+                Err(report!(errors::ApiErrorResponse::PreconditionFailed {
+                    message: "`confirm` must be `true` for mandates".into()
+                }))?
+            }
 
-    let off_session = req.off_session.get_required_value("off_session")?;
-    if !off_session {
-        Err(report!(errors::ApiErrorResponse::PreconditionFailed {
-            message: "`off_session` should be `true` for mandates".into()
-        }))?
+            let off_session = req.off_session.get_required_value("off_session")?;
+            if !off_session {
+                Err(report!(errors::ApiErrorResponse::PreconditionFailed {
+                    message: "`off_session` should be `true` for mandates".into()
+                }))?
+            }
+            Ok(())
+        }
     }
-
-    Ok(())
 }
 
 pub fn verify_mandate_details(
@@ -3079,6 +3098,7 @@ mod tests {
             billing_details: None,
             merchant_order_reference_id: None,
             shipping_details: None,
+            is_payment_processor_token_flow: None,
         };
         let req_cs = Some("1".to_string());
         assert!(authenticate_client_secret(req_cs.as_ref(), &payment_intent).is_ok());
@@ -3143,6 +3163,7 @@ mod tests {
             billing_details: None,
             merchant_order_reference_id: None,
             shipping_details: None,
+            is_payment_processor_token_flow: None,
         };
         let req_cs = Some("1".to_string());
         assert!(authenticate_client_secret(req_cs.as_ref(), &payment_intent,).is_err())
@@ -3205,6 +3226,7 @@ mod tests {
             billing_details: None,
             merchant_order_reference_id: None,
             shipping_details: None,
+            is_payment_processor_token_flow: None,
         };
         let req_cs = Some("1".to_string());
         assert!(authenticate_client_secret(req_cs.as_ref(), &payment_intent).is_err())
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 52d76289d88..b62b97bdb20 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -628,6 +628,31 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             .as_ref()
             .map(|payment_method_billing| payment_method_billing.address_id.clone());
 
+        // If processor_payment_token is passed in request then populating the same in PaymentData
+        let mandate_id = request
+            .recurring_details
+            .as_ref()
+            .and_then(|recurring_details| match recurring_details {
+                api_models::mandates::RecurringDetails::ProcessorPaymentToken(token) => {
+                    payment_intent.is_payment_processor_token_flow = Some(true);
+                    Some(api_models::payments::MandateIds {
+                        mandate_id: None,
+                        mandate_reference_id: Some(
+                            api_models::payments::MandateReferenceId::ConnectorMandateId(
+                                api_models::payments::ConnectorMandateReferenceId {
+                                    connector_mandate_id: Some(
+                                        token.processor_payment_token.clone(),
+                                    ),
+                                    payment_method_id: None,
+                                    update_history: None,
+                                },
+                            ),
+                        ),
+                    })
+                }
+                _ => None,
+            });
+
         let payment_data = PaymentData {
             flow: PhantomData,
             payment_intent,
@@ -635,7 +660,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             currency,
             amount,
             email: request.email.clone(),
-            mandate_id: None,
+            mandate_id: mandate_id.clone(),
             mandate_connector,
             setup_mandate,
             customer_acceptance: customer_acceptance.map(From::from),
@@ -1279,6 +1304,8 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
         let session_expiry = m_payment_data_payment_intent.session_expiry;
         let m_key_store = key_store.clone();
         let key_manager_state = state.into();
+        let is_payment_processor_token_flow =
+            payment_data.payment_intent.is_payment_processor_token_flow;
 
         let payment_intent_fut = tokio::spawn(
             async move {
@@ -1311,6 +1338,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
                         merchant_order_reference_id: None,
                         billing_details,
                         shipping_details,
+                        is_payment_processor_token_flow,
                     })),
                     &m_key_store,
                     storage_scheme,
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index 1723084d0f1..983a31c50e5 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -376,6 +376,32 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             .await
             .transpose()?;
 
+        let mandate_id = if mandate_id.is_none() {
+            request
+                .recurring_details
+                .as_ref()
+                .and_then(|recurring_details| match recurring_details {
+                    RecurringDetails::ProcessorPaymentToken(token) => {
+                        Some(api_models::payments::MandateIds {
+                            mandate_id: None,
+                            mandate_reference_id: Some(
+                                api_models::payments::MandateReferenceId::ConnectorMandateId(
+                                    api_models::payments::ConnectorMandateReferenceId {
+                                        connector_mandate_id: Some(
+                                            token.processor_payment_token.clone(),
+                                        ),
+                                        payment_method_id: None,
+                                        update_history: None,
+                                    },
+                                ),
+                            ),
+                        })
+                    }
+                    _ => None,
+                })
+        } else {
+            mandate_id
+        };
         let operation = payments::if_not_create_change_operation::<_, F>(
             payment_intent.status,
             request.confirm,
@@ -429,7 +455,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             currency,
             amount,
             email: request.email.clone(),
-            mandate_id,
+            mandate_id: mandate_id.clone(),
             mandate_connector,
             setup_mandate,
             customer_acceptance,
@@ -1105,6 +1131,12 @@ impl PaymentCreate {
         } else {
             None
         };
+        let is_payment_processor_token_flow = request.recurring_details.as_ref().and_then(
+            |recurring_details| match recurring_details {
+                RecurringDetails::ProcessorPaymentToken(_) => Some(true),
+                _ => None,
+            },
+        );
 
         // Encrypting our Customer Details to be stored in Payment Intent
         let customer_details = raw_customer_details
@@ -1165,6 +1197,7 @@ impl PaymentCreate {
             customer_details,
             merchant_order_reference_id: request.merchant_order_reference_id.clone(),
             shipping_details,
+            is_payment_processor_token_flow,
         })
     }
 
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index 3a5cd00b9c3..58753586106 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -772,6 +772,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
                     merchant_order_reference_id,
                     billing_details,
                     shipping_details,
+                    is_payment_processor_token_flow: None,
                 })),
                 key_store,
                 storage_scheme,
diff --git a/crates/router/src/utils/user/sample_data.rs b/crates/router/src/utils/user/sample_data.rs
index 86607234d4e..bbd709de66a 100644
--- a/crates/router/src/utils/user/sample_data.rs
+++ b/crates/router/src/utils/user/sample_data.rs
@@ -230,6 +230,7 @@ pub async fn generate_sample_data(
             billing_details: None,
             merchant_order_reference_id: Default::default(),
             shipping_details: None,
+            is_payment_processor_token_flow: None,
         };
         let payment_attempt = PaymentAttemptBatchNew {
             attempt_id: attempt_id.clone(),
diff --git a/migrations/2024-08-01-172628_add_is_payment_processor_token_flow_in_payment_intent_table/down.sql b/migrations/2024-08-01-172628_add_is_payment_processor_token_flow_in_payment_intent_table/down.sql
new file mode 100644
index 00000000000..02ff48e6b68
--- /dev/null
+++ b/migrations/2024-08-01-172628_add_is_payment_processor_token_flow_in_payment_intent_table/down.sql
@@ -0,0 +1,2 @@
+-- This file should undo anything in `up.sql`
+ALTER TABLE payment_intent DROP COLUMN IF EXISTS is_payment_processor_token_flow;
diff --git a/migrations/2024-08-01-172628_add_is_payment_processor_token_flow_in_payment_intent_table/up.sql b/migrations/2024-08-01-172628_add_is_payment_processor_token_flow_in_payment_intent_table/up.sql
new file mode 100644
index 00000000000..785806d09ef
--- /dev/null
+++ b/migrations/2024-08-01-172628_add_is_payment_processor_token_flow_in_payment_intent_table/up.sql
@@ -0,0 +1,3 @@
+-- Your SQL goes here
+ALTER TABLE payment_intent
+ADD COLUMN IF NOT EXISTS is_payment_processor_token_flow BOOLEAN;

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

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

## Description
<!-- Describe your changes in detail -->
During the transition phase of Hyperswitch, Merchant should be able to send the processor's token to Hyperswitch to process MIT transaction. This is because, Merchant will not have the card data to migrate from Processor to Hyperswitch.
The migration is here:
'''
-- Your SQL goes here
ALTER TABLE payment_intent
ADD COLUMN IF NOT EXISTS is_payment_processor_token_flow BOOLEAN;
### Additional Changes
'''

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

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

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


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

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


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
### The testing flows are as follows:
1. Create a Setup Mandate Payment.
2. Get the payment_method_id.
3. Get the connector_mandate_id from payment_method table in db (using pm_method_id) -> this is our payment_processor_token (PPT).
4. Now create a recurring_payment using the above ppt.

The curls for the same are as follows:
1. Create a Setup Mandate Payment.
```
curl --location 'http://127.0.0.1:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: ••••••' \
--data-raw '
{
    "amount": 10000,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "customer_id": "cus_35RDuRN4P6XdVMgt2Px7",
    "email": "abcdef123@gmail.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
    "setup_future_usage": "off_session",
    "off_session": true,
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "127.0.0.1"
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "John",
            "last_name": "Doe"
        }
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "payment_type": "setup_mandate",
    "payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4242424242424242",
            "card_exp_month": "02",
            "card_exp_year": "26",
            "card_holder_name": "Joseph Doe",
            "card_cvc": "999"
        }
    },
    "billing": {
        "address": {
            "line1": "8th block",
            "line2": "8th block",
            "line3": "8th block",
            "city": "Bengaluru",
            "state": "Karnataka",
            "zip": "560095",
            "country": "IN",
            "first_name": "Sakil",
            "last_name": "Mostak"
        }
    },
    "customer_acceptance": {
        "acceptance_type": "online"
    }
}'
```
2. Get the payment_method_id.
```
"payment_method_id": "pm_A1YI0BNBELMQVw76ipT3",
```

3. Get the connector_mandate_id from payment_method table in db (using pm_method_id) -> this is our payment_processor_token (PPT).
```
connector_mandate_details      | {"mca_A3fAZBZEG6X8cBb19z9w": {"payment_method_type": "credit", "connector_mandate_id": "**pm_1Pkk1YD5R7gDAGff2yPGAPgr**", "original_payment_authorized_amount": 10000, "original_payment_authorized_currency": "USD"}}
```

4. Now create a recurring_payment using the above ppt (confirm true).
```
curl --location 'http://127.0.0.1:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_QP5rWb7dq1xSRpxdQoroFUxUiD3kLx6MgfsBBEe9FlvkAjXnqTYINyylTR8o5zkG' \
--data '{
    "amount": 499,
    "currency": "USD",
    "capture_method": "automatic",
    "customer_id": "cus_35RDuRN4P6XdVMgt2Px7",
    "off_session": true,
    "confirm": true,
    "recurring_details": {
        "type": "processor_payment_token",
        "data": {
            "processor_payment_token": "pm_1Pkk1YD5R7gDAGff2yPGAPgr",
            "connector": "stripe",
            "merchant_connector_id": "mca_A3fAZBZEG6X8cBb19z9w"
        }
    },
    "payment_method": "card",
    "authentication_type": "no_three_ds"
}'
```

4. Now create a recurring_payment using the above ppt (confirm false).
```
curl --location 'http://127.0.0.1:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_QP5rWb7dq1xSRpxdQoroFUxUiD3kLx6MgfsBBEe9FlvkAjXnqTYINyylTR8o5zkG' \
--data '{
    "amount": 499,
    "currency": "USD",
    "capture_method": "automatic",
    "customer_id": "cus_35RDuRN4P6XdVMgt2Px7",
    "off_session": true,
    "confirm": false,
    "authentication_type": "no_three_ds"
}'
```

5. Confirm the payment
```
curl --location 'http://localhost:8080/payments/pay_LG5wWKTQ5sLATRBchdc3/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: ••••••' \
--data '{
    "off_session": true,
    "payment_method": "card",
    "recurring_details": {
        "type": "processor_payment_token",
        "data": {
            "processor_payment_token": "pm_1Pkk1YD5R7gDAGff2yPGAPgr",
            "connector": "stripe",
            "merchant_connector_id": "mca_A3fAZBZEG6X8cBb19z9w"
        }
    }
}'
```


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

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