From 0d43f48c4514952825dddc4ad660ee35795358d1 Mon Sep 17 00:00:00 2001 From: Sai Harsha Vardhan <56996463+sai-harsha-vardhan@users.noreply.github.com> Date: Wed, 29 Oct 2025 12:35:37 +0530 Subject: [PATCH] feat(router): add `sdk_next_action` in payment method list response (#9922) Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- api-reference/v1/openapi_spec_v1.json | 13 ++++++- api-reference/v2/openapi_spec_v2.json | 7 ++++ crates/api_models/src/payment_methods.rs | 4 ++ crates/api_models/src/payments.rs | 2 + crates/common_utils/src/id_type/merchant.rs | 5 +++ .../router/src/core/payment_methods/cards.rs | 11 +++++- .../router/src/core/payment_methods/utils.rs | 39 ++++++++++++++++++- 7 files changed, 78 insertions(+), 3 deletions(-) diff --git a/api-reference/v1/openapi_spec_v1.json b/api-reference/v1/openapi_spec_v1.json index cacc0cf7aa..72fb802690 100644 --- a/api-reference/v1/openapi_spec_v1.json +++ b/api-reference/v1/openapi_spec_v1.json @@ -20871,6 +20871,13 @@ } } } + }, + { + "type": "string", + "description": "The next action is to perform eligibility check", + "enum": [ + "eligibility_check" + ] } ] }, @@ -23744,7 +23751,8 @@ "mandate_payment", "show_surcharge_breakup_screen", "request_external_three_ds_authentication", - "is_tax_calculation_enabled" + "is_tax_calculation_enabled", + "sdk_next_action" ], "properties": { "redirect_url": { @@ -23800,6 +23808,9 @@ "is_tax_calculation_enabled": { "type": "boolean", "description": "flag that indicates whether to calculate tax on the order amount" + }, + "sdk_next_action": { + "$ref": "#/components/schemas/SdkNextAction" } } }, diff --git a/api-reference/v2/openapi_spec_v2.json b/api-reference/v2/openapi_spec_v2.json index 6da1caf747..7f1676c71f 100644 --- a/api-reference/v2/openapi_spec_v2.json +++ b/api-reference/v2/openapi_spec_v2.json @@ -15823,6 +15823,13 @@ } } } + }, + { + "type": "string", + "description": "The next action is to perform eligibility check", + "enum": [ + "eligibility_check" + ] } ] }, diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs index 07bbbd0e94..e295687b2a 100644 --- a/crates/api_models/src/payment_methods.rs +++ b/crates/api_models/src/payment_methods.rs @@ -2044,6 +2044,10 @@ pub struct PaymentMethodListResponse { /// flag that indicates whether to calculate tax on the order amount pub is_tax_calculation_enabled: bool, + + /// indicates the next action to be performed by the SDK + #[schema(value_type = SdkNextAction)] + pub sdk_next_action: payments::SdkNextAction, } #[cfg(feature = "v1")] diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 0f5752c622..f20afcf61e 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -8113,6 +8113,8 @@ pub enum NextActionCall { AwaitMerchantCallback, /// The next action is to deny the payment with an error message Deny { message: String }, + /// The next action is to perform eligibility check + EligibilityCheck, } #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] diff --git a/crates/common_utils/src/id_type/merchant.rs b/crates/common_utils/src/id_type/merchant.rs index 3083ee7df0..ef99a4d1a9 100644 --- a/crates/common_utils/src/id_type/merchant.rs +++ b/crates/common_utils/src/id_type/merchant.rs @@ -226,4 +226,9 @@ impl MerchantId { self.get_string_repr() ) } + + /// Get should perform eligibility check key for payment + pub fn get_should_perform_eligibility_check_key(&self) -> String { + format!("should_perform_eligibility_{}", self.get_string_repr()) + } } diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index e61c269f9d..635cc39aac 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -79,7 +79,10 @@ use crate::{ core::{ configs, errors::{self, StorageErrorExt}, - payment_methods::{network_tokenization, transformers as payment_methods, vault}, + payment_methods::{ + network_tokenization, transformers as payment_methods, utils as payment_method_utils, + vault, + }, payments::{ helpers, routing::{self, SessionFlowRoutingInput}, @@ -3475,6 +3478,11 @@ pub async fn list_payment_methods( .as_ref() .and_then(|intent| intent.request_external_three_ds_authentication) .unwrap_or(false); + let sdk_next_action = payment_method_utils::get_sdk_next_action_for_payment_method_list( + db, + merchant_context.get_merchant_account().get_id(), + ) + .await; let merchant_surcharge_configs = if let Some((payment_attempt, payment_intent)) = payment_attempt.as_ref().zip(payment_intent) { @@ -3554,6 +3562,7 @@ pub async fn list_payment_methods( collect_shipping_details_from_wallets, collect_billing_details_from_wallets, is_tax_calculation_enabled: is_tax_connector_enabled && !skip_external_tax_calculation, + sdk_next_action, }, )) } diff --git a/crates/router/src/core/payment_methods/utils.rs b/crates/router/src/core/payment_methods/utils.rs index 0bff9033ca..3f4f44e355 100644 --- a/crates/router/src/core/payment_methods/utils.rs +++ b/crates/router/src/core/payment_methods/utils.rs @@ -14,9 +14,11 @@ use euclid::frontend::dir; use hyperswitch_constraint_graph as cgraph; use kgraph_utils::{error::KgraphError, transformers::IntoDirValue}; use masking::ExposeInterface; +#[cfg(feature = "v1")] +use router_env::logger; use storage_impl::redis::cache::{CacheKey, PM_FILTERS_CGRAPH_CACHE}; -use crate::{configs::settings, routes::SessionState}; +use crate::{configs::settings, db::StorageInterface, routes::SessionState}; #[cfg(feature = "v2")] use crate::{ db::{ @@ -811,6 +813,41 @@ fn compile_accepted_currency_for_mca( )) } +pub async fn get_merchant_config_for_eligibility_check( + db: &dyn StorageInterface, + merchant_id: &common_utils::id_type::MerchantId, +) -> bool { + let config = db + .find_config_by_key_unwrap_or( + &merchant_id.get_should_perform_eligibility_check_key(), + Some("false".to_string()), + ) + .await; + match config { + Ok(conf) => conf.config == "true", + Err(error) => { + logger::error!(?error); + false + } + } +} + +pub async fn get_sdk_next_action_for_payment_method_list( + db: &dyn StorageInterface, + merchant_id: &common_utils::id_type::MerchantId, +) -> api_models::payments::SdkNextAction { + let should_perform_eligibility_check = + get_merchant_config_for_eligibility_check(db, merchant_id).await; + let next_action_call = if should_perform_eligibility_check { + api_models::payments::NextActionCall::EligibilityCheck + } else { + api_models::payments::NextActionCall::Confirm + }; + api_models::payments::SdkNextAction { + next_action: next_action_call, + } +} + #[cfg(feature = "v2")] pub(super) async fn retrieve_payment_token_data( state: &SessionState,