Bug: feat(vsaas): Add platform merchant validations for payment intent



Currently `payment_intent` stores `platform_merchant_id`. This can be used to identify if the payment was created by platform merchant.

If the payment was initialized by platform merchant, the merchant who is the owner of the payment should not be able to do any operations on the payment and vice versa.

So, we need those validations on payment intents to check if the current merchant can be allowed to perform those operations even if the authentication module allows it.
diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs
index c830b7618d0..bdb0548d6a4 100644
--- a/crates/router/src/core/payments/operations/payment_approve.rs
+++ b/crates/router/src/core/payments/operations/payment_approve.rs
@@ -11,6 +11,7 @@ use crate::{
     core::{
         errors::{self, RouterResult, StorageErrorExt},
         payments::{helpers, operations, PaymentData},
+        utils::ValidatePlatformMerchant,
     },
     events::audit_events::{AuditEvent, AuditEventType},
     routes::{app::ReqState, SessionState},
@@ -45,7 +46,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsCaptureR
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<
         operations::GetTrackerResponse<'a, F, api::PaymentsCaptureRequest, PaymentData<F>>,
     > {
@@ -70,6 +71,9 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsCaptureR
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         helpers::validate_payment_status_against_not_allowed_statuses(
             payment_intent.status,
             &[IntentStatus::Failed, IntentStatus::Succeeded],
diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs
index c6679e481f1..b41247003bd 100644
--- a/crates/router/src/core/payments/operations/payment_cancel.rs
+++ b/crates/router/src/core/payments/operations/payment_cancel.rs
@@ -12,6 +12,7 @@ use crate::{
     core::{
         errors::{self, RouterResult, StorageErrorExt},
         payments::{helpers, operations, PaymentData},
+        utils::ValidatePlatformMerchant,
     },
     events::audit_events::{AuditEvent, AuditEventType},
     routes::{app::ReqState, SessionState},
@@ -46,7 +47,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsCancelRe
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<
         operations::GetTrackerResponse<'a, F, api::PaymentsCancelRequest, PaymentData<F>>,
     > {
@@ -70,6 +71,9 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsCancelRe
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         helpers::validate_payment_status_against_not_allowed_statuses(
             payment_intent.status,
             &[
diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs
index ebe49f59f64..2bb8dd279e5 100644
--- a/crates/router/src/core/payments/operations/payment_capture.rs
+++ b/crates/router/src/core/payments/operations/payment_capture.rs
@@ -11,6 +11,7 @@ use crate::{
     core::{
         errors::{self, RouterResult, StorageErrorExt},
         payments::{self, helpers, operations, types::MultipleCaptureData},
+        utils::ValidatePlatformMerchant,
     },
     events::audit_events::{AuditEvent, AuditEventType},
     routes::{app::ReqState, SessionState},
@@ -45,7 +46,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, payments::PaymentData<F>, api::Paymen
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<
         operations::GetTrackerResponse<
             'a,
@@ -76,6 +77,9 @@ impl<F: Send + Clone + Sync> GetTracker<F, payments::PaymentData<F>, api::Paymen
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         payment_attempt = db
             .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
                 &payment_intent.payment_id,
diff --git a/crates/router/src/core/payments/operations/payment_capture_v2.rs b/crates/router/src/core/payments/operations/payment_capture_v2.rs
index 81ffa8e992f..93b7ffa6c19 100644
--- a/crates/router/src/core/payments/operations/payment_capture_v2.rs
+++ b/crates/router/src/core/payments/operations/payment_capture_v2.rs
@@ -8,7 +8,11 @@ use super::{Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
 use crate::{
     core::{
         errors::{self, CustomResult, RouterResult, StorageErrorExt},
-        payments::operations::{self, ValidateStatusForOperation},
+        payments::{
+            helpers,
+            operations::{self, ValidateStatusForOperation},
+        },
+        utils::ValidatePlatformMerchant,
     },
     routes::{app::ReqState, SessionState},
     types::{
@@ -142,7 +146,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentCaptureData<F>, PaymentsCaptureReques
         _profile: &domain::Profile,
         key_store: &domain::MerchantKeyStore,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<operations::GetTrackerResponse<PaymentCaptureData<F>>> {
         let db = &*state.store;
         let key_manager_state = &state.into();
@@ -154,6 +158,9 @@ impl<F: Send + Clone> GetTracker<F, PaymentCaptureData<F>, PaymentsCaptureReques
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         self.validate_status_for_operation(payment_intent.status)?;
 
         let active_attempt_id = payment_intent
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 72c04c6a549..f1279f394b2 100644
--- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs
+++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
@@ -72,6 +72,9 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             )
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
+
+        // TODO (#7195): Add platform merchant account validation once client_secret auth is solved
+
         payment_intent.setup_future_usage = request
             .setup_future_usage
             .or(payment_intent.setup_future_usage);
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 64191f77c6d..84ff9933875 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -106,6 +106,8 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        // TODO (#7195): Add platform merchant account validation once client_secret auth is solved
+
         if let Some(order_details) = &request.order_details {
             helpers::validate_order_details_amount(
                 order_details.to_owned(),
diff --git a/crates/router/src/core/payments/operations/payment_confirm_intent.rs b/crates/router/src/core/payments/operations/payment_confirm_intent.rs
index 71d99d03e41..7245188059e 100644
--- a/crates/router/src/core/payments/operations/payment_confirm_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm_intent.rs
@@ -170,6 +170,8 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentConfirmData<F>, PaymentsConfir
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        // TODO (#7195): Add platform merchant account validation once publishable key auth is solved
+
         self.validate_status_for_operation(payment_intent.status)?;
         let client_secret = header_payload
             .client_secret
diff --git a/crates/router/src/core/payments/operations/payment_get.rs b/crates/router/src/core/payments/operations/payment_get.rs
index 6419376f090..9f3a9e5248e 100644
--- a/crates/router/src/core/payments/operations/payment_get.rs
+++ b/crates/router/src/core/payments/operations/payment_get.rs
@@ -9,7 +9,11 @@ use super::{Domain, GetTracker, Operation, UpdateTracker, ValidateRequest};
 use crate::{
     core::{
         errors::{self, CustomResult, RouterResult, StorageErrorExt},
-        payments::operations::{self, ValidateStatusForOperation},
+        payments::{
+            helpers,
+            operations::{self, ValidateStatusForOperation},
+        },
+        utils::ValidatePlatformMerchant,
     },
     routes::{app::ReqState, SessionState},
     types::{
@@ -119,7 +123,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentStatusData<F>, PaymentsRetriev
         _profile: &domain::Profile,
         key_store: &domain::MerchantKeyStore,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<operations::GetTrackerResponse<PaymentStatusData<F>>> {
         let db = &*state.store;
         let key_manager_state = &state.into();
@@ -131,6 +135,9 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentStatusData<F>, PaymentsRetriev
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         let payment_attempt = payment_intent
             .active_attempt_id
             .as_ref()
diff --git a/crates/router/src/core/payments/operations/payment_get_intent.rs b/crates/router/src/core/payments/operations/payment_get_intent.rs
index 3cc26e7b67f..0041209eb0f 100644
--- a/crates/router/src/core/payments/operations/payment_get_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_get_intent.rs
@@ -10,6 +10,7 @@ use crate::{
     core::{
         errors::{self, RouterResult},
         payments::{self, helpers, operations},
+        utils::ValidatePlatformMerchant,
     },
     db::errors::StorageErrorExt,
     routes::{app::ReqState, SessionState},
@@ -89,7 +90,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, payments::PaymentIntentData<F>, Payme
         _profile: &domain::Profile,
         key_store: &domain::MerchantKeyStore,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<operations::GetTrackerResponse<payments::PaymentIntentData<F>>> {
         let db = &*state.store;
         let key_manager_state = &state.into();
@@ -99,6 +100,9 @@ impl<F: Send + Clone + Sync> GetTracker<F, payments::PaymentIntentData<F>, Payme
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         let payment_data = payments::PaymentIntentData {
             flow: PhantomData,
             payment_intent,
diff --git a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs
index 0e189583d0a..9f21dbc9981 100644
--- a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs
+++ b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs
@@ -73,6 +73,8 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsPostSess
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        // TODO (#7195): Add platform merchant account validation once publishable key auth is solved
+
         helpers::authenticate_client_secret(Some(request.client_secret.peek()), &payment_intent)?;
 
         let mut payment_attempt = db
diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs
index e5321b1f984..1591b1d6a47 100644
--- a/crates/router/src/core/payments/operations/payment_reject.rs
+++ b/crates/router/src/core/payments/operations/payment_reject.rs
@@ -11,6 +11,7 @@ use crate::{
     core::{
         errors::{self, RouterResult, StorageErrorExt},
         payments::{helpers, operations, PaymentAddress, PaymentData},
+        utils::ValidatePlatformMerchant,
     },
     events::audit_events::{AuditEvent, AuditEventType},
     routes::{app::ReqState, SessionState},
@@ -43,7 +44,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, PaymentsCancelRequest
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<operations::GetTrackerResponse<'a, F, PaymentsCancelRequest, PaymentData<F>>>
     {
         let db = &*state.store;
@@ -66,6 +67,9 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, PaymentsCancelRequest
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         helpers::validate_payment_status_against_not_allowed_statuses(
             payment_intent.status,
             &[
diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs
index 0e94fbe09c6..be4f804a8a7 100644
--- a/crates/router/src/core/payments/operations/payment_session.rs
+++ b/crates/router/src/core/payments/operations/payment_session.rs
@@ -68,6 +68,8 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsSessionR
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        // TODO (#7195): Add platform merchant account validation once publishable key auth is solved
+
         helpers::validate_payment_status_against_not_allowed_statuses(
             payment_intent.status,
             &[
diff --git a/crates/router/src/core/payments/operations/payment_session_intent.rs b/crates/router/src/core/payments/operations/payment_session_intent.rs
index ec59ba3473e..9bca88c6d04 100644
--- a/crates/router/src/core/payments/operations/payment_session_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_session_intent.rs
@@ -10,7 +10,7 @@ use super::{BoxedOperation, Domain, GetTracker, Operation, ValidateRequest};
 use crate::{
     core::{
         errors::{self, RouterResult, StorageErrorExt},
-        payments::{self, operations, operations::ValidateStatusForOperation},
+        payments::{self, helpers, operations, operations::ValidateStatusForOperation},
     },
     routes::SessionState,
     types::{api, domain, storage::enums},
@@ -112,6 +112,8 @@ impl<F: Send + Clone + Sync> GetTracker<F, payments::PaymentIntentData<F>, Payme
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        // TODO (#7195): Add platform merchant account validation once publishable key auth is solved
+
         self.validate_status_for_operation(payment_intent.status)?;
 
         let client_secret = header_payload
diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs
index 1da9a1a2264..299d7237807 100644
--- a/crates/router/src/core/payments/operations/payment_start.rs
+++ b/crates/router/src/core/payments/operations/payment_start.rs
@@ -68,6 +68,8 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsStartReq
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        // TODO (#7195): Add platform merchant account validation once Merchant ID auth is solved
+
         helpers::validate_payment_status_against_not_allowed_statuses(
             payment_intent.status,
             &[
diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs
index 44f0c9172f9..c458f95ad97 100644
--- a/crates/router/src/core/payments/operations/payment_status.rs
+++ b/crates/router/src/core/payments/operations/payment_status.rs
@@ -213,7 +213,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRetrieve
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<
         operations::GetTrackerResponse<'a, F, api::PaymentsRetrieveRequest, PaymentData<F>>,
     > {
@@ -225,6 +225,7 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRetrieve
             request,
             self,
             merchant_account.storage_scheme,
+            platform_merchant_account,
         )
         .await
     }
@@ -252,6 +253,7 @@ async fn get_tracker_for_sync<
     any(feature = "v2", feature = "v1"),
     not(feature = "payment_methods_v2")
 ))]
+#[allow(clippy::too_many_arguments)]
 async fn get_tracker_for_sync<
     'a,
     F: Send + Clone,
@@ -264,6 +266,7 @@ async fn get_tracker_for_sync<
     request: &api::PaymentsRetrieveRequest,
     operation: Op,
     storage_scheme: enums::MerchantStorageScheme,
+    platform_merchant_account: Option<&domain::MerchantAccount>,
 ) -> RouterResult<operations::GetTrackerResponse<'a, F, api::PaymentsRetrieveRequest, PaymentData<F>>>
 {
     let (payment_intent, mut payment_attempt, currency, amount);
@@ -274,6 +277,7 @@ async fn get_tracker_for_sync<
         merchant_account.get_id(),
         key_store,
         storage_scheme,
+        platform_merchant_account,
     )
     .await?;
 
@@ -579,6 +583,7 @@ pub async fn get_payment_intent_payment_attempt(
     merchant_id: &common_utils::id_type::MerchantId,
     key_store: &domain::MerchantKeyStore,
     storage_scheme: enums::MerchantStorageScheme,
+    _platform_merchant_account: Option<&domain::MerchantAccount>,
 ) -> RouterResult<(storage::PaymentIntent, storage::PaymentAttempt)> {
     let key_manager_state: KeyManagerState = state.into();
     let db = &*state.store;
@@ -662,4 +667,6 @@ pub async fn get_payment_intent_payment_attempt(
     get_pi_pa()
         .await
         .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)
+
+    // TODO (#7195): Add platform merchant account validation once client_secret auth is solved
 }
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index 0e60407aa7c..ac37513f2b9 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -81,6 +81,8 @@ impl<F: Send + Clone + Sync> GetTracker<F, PaymentData<F>, api::PaymentsRequest>
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        // TODO (#7195): Add platform merchant account validation once publishable key auth is solved
+
         if let Some(order_details) = &request.order_details {
             helpers::validate_order_details_amount(
                 order_details.to_owned(),
diff --git a/crates/router/src/core/payments/operations/payment_update_intent.rs b/crates/router/src/core/payments/operations/payment_update_intent.rs
index 4782d237e21..ba5ba772f82 100644
--- a/crates/router/src/core/payments/operations/payment_update_intent.rs
+++ b/crates/router/src/core/payments/operations/payment_update_intent.rs
@@ -21,9 +21,10 @@ use crate::{
     core::{
         errors::{self, RouterResult},
         payments::{
-            self,
+            self, helpers,
             operations::{self, ValidateStatusForOperation},
         },
+        utils::ValidatePlatformMerchant,
     },
     db::errors::StorageErrorExt,
     routes::{app::ReqState, SessionState},
@@ -135,7 +136,7 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentIntentData<F>, PaymentsUpda
         _profile: &domain::Profile,
         key_store: &domain::MerchantKeyStore,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<operations::GetTrackerResponse<payments::PaymentIntentData<F>>> {
         let db = &*state.store;
         let key_manager_state = &state.into();
@@ -145,6 +146,9 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentIntentData<F>, PaymentsUpda
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         self.validate_status_for_operation(payment_intent.status)?;
 
         let PaymentsUpdateIntentRequest {
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 2c816ad39d1..95c50f2f17e 100644
--- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
+++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs
@@ -15,6 +15,7 @@ use crate::{
             self, helpers, operations, CustomerDetails, IncrementalAuthorizationDetails,
             PaymentAddress,
         },
+        utils::ValidatePlatformMerchant,
     },
     routes::{app::ReqState, SessionState},
     services,
@@ -48,7 +49,7 @@ impl<F: Send + Clone + Sync>
         key_store: &domain::MerchantKeyStore,
         _auth_flow: services::AuthFlow,
         _header_payload: &hyperswitch_domain_models::payments::HeaderPayload,
-        _platform_merchant_account: Option<&domain::MerchantAccount>,
+        platform_merchant_account: Option<&domain::MerchantAccount>,
     ) -> RouterResult<
         operations::GetTrackerResponse<
             'a,
@@ -77,6 +78,9 @@ impl<F: Send + Clone + Sync>
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent
+            .validate_platform_merchant(platform_merchant_account.map(|ma| ma.get_id()))?;
+
         helpers::validate_payment_status_against_allowed_statuses(
             payment_intent.status,
             &[enums::IntentStatus::RequiresCapture],
diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs
index 5b9c90f3add..bcda2af8768 100644
--- a/crates/router/src/core/payments/operations/tax_calculation.rs
+++ b/crates/router/src/core/payments/operations/tax_calculation.rs
@@ -79,6 +79,8 @@ impl<F: Send + Clone + Sync>
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        // TODO (#7195): Add platform merchant account validation once publishable key auth is solved
+
         helpers::validate_payment_status_against_not_allowed_statuses(
             payment_intent.status,
             &[
diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs
index 71cc3dceebb..aa8204b7e9d 100644
--- a/crates/router/src/core/utils.rs
+++ b/crates/router/src/core/utils.rs
@@ -1680,3 +1680,36 @@ pub(crate) fn validate_profile_id_from_auth_layer<T: GetProfileId + std::fmt::De
         (None, None) | (None, Some(_)) => Ok(()),
     }
 }
+
+pub(crate) trait ValidatePlatformMerchant {
+    fn get_platform_merchant_id(&self) -> Option<&common_utils::id_type::MerchantId>;
+
+    fn validate_platform_merchant(
+        &self,
+        auth_platform_merchant_id: Option<&common_utils::id_type::MerchantId>,
+    ) -> CustomResult<(), errors::ApiErrorResponse> {
+        let data_platform_merchant_id = self.get_platform_merchant_id();
+        match (data_platform_merchant_id, auth_platform_merchant_id) {
+            (Some(data_platform_merchant_id), Some(auth_platform_merchant_id)) => {
+                common_utils::fp_utils::when(
+                    data_platform_merchant_id != auth_platform_merchant_id,
+                    || {
+                        Err(report!(errors::ApiErrorResponse::PaymentNotFound)).attach_printable(format!(
+                     "Data platform merchant id: {data_platform_merchant_id:?} does not match with auth platform merchant id: {auth_platform_merchant_id:?}"))
+                    },
+                )
+            }
+            (Some(_), None) | (None, Some(_)) => {
+                Err(report!(errors::ApiErrorResponse::InvalidPlatformOperation))
+                    .attach_printable("Platform merchant id is missing in either data or auth")
+            }
+            (None, None) => Ok(()),
+        }
+    }
+}
+
+impl ValidatePlatformMerchant for storage::PaymentIntent {
+    fn get_platform_merchant_id(&self) -> Option<&common_utils::id_type::MerchantId> {
+        self.platform_merchant_id.as_ref()
+    }
+}
diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs
index 5f9fe729eeb..09f3f1df330 100644
--- a/crates/router/src/routes/payment_methods.rs
+++ b/crates/router/src/routes/payment_methods.rs
@@ -508,6 +508,7 @@ pub async fn list_payment_method_api(
         &req,
         payload,
         |state, auth: auth::AuthenticationData, req, _| {
+            // TODO (#7195): Fill platform_merchant_account in the client secret auth and pass it here.
             cards::list_payment_methods(state, auth.merchant_account, auth.key_store, req)
         },
         &*auth,

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

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

## Description
<!-- Describe your changes in detail -->
Currently payment_intent stores platform_merchant_id. This can be used to identify if the payment was created by platform merchant.

If the payment was initialized by platform merchant, the merchant who is the owner of the payment should not be able to do any operations on the payment and vice versa.

So, we need those validations on payment intents to check if the current merchant can be allowed to perform those operations even if the authentication module allows it.


These payment ops are modified in the process.
| Operation                                | Validation Added | Auth Used                      |
| ---------------------------------------- | ---------------- | ------------------------------ |
| Payment Approve                          | Yes              | JWT + API Key                  |
| Payment Cancel                           | Yes              | API Key                        |
| Payment Capture                          | Yes              | API Key                        |
| Complete Authorize                       | No               | Client Secret + API Key        |
| Payment Confirm                          | No               | Client Secret + API Key        |
| Payment Reject                           | Yes              | API Key                        |
| Payment Post Session Tokens              | No               | Publishable Key Auth           |
| Payment Session                          | No               | Publishable Key Auth           |
| Payment Start                            | No               | Merchant ID Auth               |
| Payment Status                           | No               | Client Secret + API Key + JWT  |
| Payment Update                           | No               | Publishable Key Auth + API Key |
| Payment Update Intent                    | Yes              | API Key                        |
| Payment Incremental Authorization        | Yes              | API Key                        |
| Payment Session Update / Tax Calculation | No               | Publishable Key Auth           |
| Payment Create                           | No               | API Key + JWT                  |
| Payment Intent Create                    | No               | API Key + JWT                  |
| Payment Session Intent                   | No               | Publishable Key Auth           |
| Payment Get Intent                       | Yes              | API Key                        |
| Payment Confirm Intent                   | No               | Publishable Key Auth           |
| Payment Get                              | Yes              | API Key + JWT                  |
| Payment Capture V2                       | Yes              | API Key + JWT                  |
| Payment Get Intent                       | Yes              | API Key                        |


### 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).
-->
Closes #7203.

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
1. Create two merchant accounts and make one platform. Refer #6882 to know what is a platform merchant and how to create a platform merchant account.
2. Create a payment for normal merchant account using platform merchant account
    ```bash
    curl --location 'http://localhost:8080/payments' \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --header 'x-connected-merchant-id: merchant_1739261637' \
    --header 'api-key: PLATFORM_API_KEY' \
    --data '{
        "amount": 6545,
        "currency": "USD"
    }'
    ```
3. Try to make any of the above mentioned operations using normal merchant account and it will throw error. Using payment cancel as an example.
    ```bash
    curl --location 'http://localhost:8080/payments/pay_Hj5V6MPOVqIL44ODkX1j/cancel' \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --header 'api-key: NORMAL_MERCHANT_API_KEY' \
    --data '{
      "cancellation_reason": "requested_by_customer"
    }'
    ```
    ```json
    {
        "error": {
            "type": "invalid_request",
            "message": "Invalid platform account operation",
            "code": "IR_44"
        }
    }
    ```
    - And the API should work if hit with platform merchant account api key
    ```bash
    curl --location 'http://localhost:8080/payments/pay_Hj5V6MPOVqIL44ODkX1j/cancel' \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --header 'x-connected-merchant-id: merchant_1739261637' \
    --header 'api-key: PLATFORM_API_KEY' \
    --data '{
      "cancellation_reason": "requested_by_customer"
    }'
    ```


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

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