Bug: add debit routing support for saved card flow



Once debit routing is performed for a card and the card is saved in the payment, we can also store the debit routing output. This allows us to reuse the saved data in future saved card flows instead of re-running the debit routing process.
diff --git a/crates/api_models/src/open_router.rs b/crates/api_models/src/open_router.rs
index ce0960f04ea..f80623efc64 100644
--- a/crates/api_models/src/open_router.rs
+++ b/crates/api_models/src/open_router.rs
@@ -1,6 +1,6 @@
 use std::{collections::HashMap, fmt::Debug};
 
-use common_utils::{id_type, types::MinorUnit};
+use common_utils::{errors, id_type, types::MinorUnit};
 pub use euclid::{
     dssa::types::EuclidAnalysable,
     frontend::{
@@ -10,7 +10,10 @@ pub use euclid::{
 };
 use serde::{Deserialize, Serialize};
 
-use crate::enums::{Currency, PaymentMethod};
+use crate::{
+    enums::{Currency, PaymentMethod},
+    payment_methods,
+};
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
@@ -69,6 +72,37 @@ pub struct DebitRoutingOutput {
     pub card_type: common_enums::CardType,
 }
 
+impl From<&DebitRoutingOutput> for payment_methods::CoBadgedCardData {
+    fn from(output: &DebitRoutingOutput) -> Self {
+        Self {
+            co_badged_card_networks: output.co_badged_card_networks.clone(),
+            issuer_country_code: output.issuer_country,
+            is_regulated: output.is_regulated,
+            regulated_name: output.regulated_name.clone(),
+        }
+    }
+}
+
+impl TryFrom<(payment_methods::CoBadgedCardData, String)> for DebitRoutingRequestData {
+    type Error = error_stack::Report<errors::ParsingError>;
+
+    fn try_from(
+        (output, card_type): (payment_methods::CoBadgedCardData, String),
+    ) -> Result<Self, Self::Error> {
+        let parsed_card_type = card_type.parse::<common_enums::CardType>().map_err(|_| {
+            error_stack::Report::new(errors::ParsingError::EnumParseFailure("CardType"))
+        })?;
+
+        Ok(Self {
+            co_badged_card_networks: output.co_badged_card_networks,
+            issuer_country: output.issuer_country_code,
+            is_regulated: output.is_regulated,
+            regulated_name: output.regulated_name,
+            card_type: parsed_card_type,
+        })
+    }
+}
+
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct CoBadgedCardRequest {
     pub merchant_category_code: common_enums::MerchantCategoryCode,
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 0f53776e644..972b51d0f97 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -985,6 +985,15 @@ pub struct CardDetailsPaymentMethod {
     pub card_type: Option<String>,
     #[serde(default = "saved_in_locker_default")]
     pub saved_to_locker: bool,
+    pub co_badged_card_data: Option<CoBadgedCardData>,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+pub struct CoBadgedCardData {
+    pub co_badged_card_networks: Vec<api_enums::CardNetwork>,
+    pub issuer_country_code: common_enums::CountryAlpha2,
+    pub is_regulated: bool,
+    pub regulated_name: Option<common_enums::RegulatedName>,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)]
@@ -1312,6 +1321,7 @@ impl From<CardDetail> for CardDetailsPaymentMethod {
             card_network: item.card_network,
             card_type: item.card_type.map(|card| card.to_string()),
             saved_to_locker: true,
+            co_badged_card_data: None,
         }
     }
 }
@@ -1320,8 +1330,10 @@ impl From<CardDetail> for CardDetailsPaymentMethod {
     any(feature = "v1", feature = "v2"),
     not(feature = "payment_methods_v2")
 ))]
-impl From<CardDetailFromLocker> for CardDetailsPaymentMethod {
-    fn from(item: CardDetailFromLocker) -> Self {
+impl From<(CardDetailFromLocker, Option<&CoBadgedCardData>)> for CardDetailsPaymentMethod {
+    fn from(
+        (item, co_badged_card_data): (CardDetailFromLocker, Option<&CoBadgedCardData>),
+    ) -> Self {
         Self {
             issuer_country: item.issuer_country,
             last4_digits: item.last4_digits,
@@ -1334,6 +1346,7 @@ impl From<CardDetailFromLocker> for CardDetailsPaymentMethod {
             card_network: item.card_network,
             card_type: item.card_type,
             saved_to_locker: item.saved_to_locker,
+            co_badged_card_data: co_badged_card_data.cloned(),
         }
     }
 }
@@ -1353,6 +1366,7 @@ impl From<CardDetailFromLocker> for CardDetailsPaymentMethod {
             card_network: item.card_network,
             card_type: item.card_type,
             saved_to_locker: item.saved_to_locker,
+            co_badged_card_data: None,
         }
     }
 }
diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs
index edbbcb5005c..1f3ed408810 100644
--- a/crates/common_enums/src/enums.rs
+++ b/crates/common_enums/src/enums.rs
@@ -2330,15 +2330,17 @@ pub enum CardNetwork {
     strum::EnumIter,
     strum::EnumString,
     utoipa::ToSchema,
-    Copy,
 )]
 #[router_derive::diesel_enum(storage_type = "db_enum")]
 #[serde(rename_all = "snake_case")]
 pub enum RegulatedName {
     #[serde(rename = "GOVERNMENT NON-EXEMPT INTERCHANGE FEE (WITH FRAUD)")]
+    #[strum(serialize = "GOVERNMENT NON-EXEMPT INTERCHANGE FEE (WITH FRAUD)")]
     NonExemptWithFraud,
-    #[serde(rename = "GOVERNMENT EXEMPT INTERCHANGE FEE")]
-    ExemptFraud,
+
+    #[serde(untagged)]
+    #[strum(default)]
+    Unknown(String),
 }
 
 #[derive(
@@ -2378,8 +2380,8 @@ pub enum PanOrToken {
     Copy,
 )]
 #[router_derive::diesel_enum(storage_type = "db_enum")]
+#[strum(serialize_all = "UPPERCASE")]
 #[serde(rename_all = "snake_case")]
-#[strum(serialize_all = "lowercase")]
 pub enum CardType {
     Credit,
     Debit,
@@ -2413,6 +2415,23 @@ impl CardNetwork {
             | Self::Maestro => true,
         }
     }
+
+    pub fn is_us_local_network(&self) -> bool {
+        match self {
+            Self::Star | Self::Pulse | Self::Accel | Self::Nyce => true,
+            Self::Interac
+            | Self::CartesBancaires
+            | Self::Visa
+            | Self::Mastercard
+            | Self::AmericanExpress
+            | Self::JCB
+            | Self::DinersClub
+            | Self::Discover
+            | Self::UnionPay
+            | Self::RuPay
+            | Self::Maestro => false,
+        }
+    }
 }
 
 /// Stage of the dispute
diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs
index 2d386d0f002..6ecbf665c50 100644
--- a/crates/hyperswitch_domain_models/src/payment_method_data.rs
+++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs
@@ -77,6 +77,14 @@ impl PaymentMethodData {
     pub fn is_network_token_payment_method_data(&self) -> bool {
         matches!(self, Self::NetworkToken(_))
     }
+
+    pub fn get_co_badged_card_data(&self) -> Option<&payment_methods::CoBadgedCardData> {
+        if let Self::Card(card) = self {
+            card.co_badged_card_data.as_ref()
+        } else {
+            None
+        }
+    }
 }
 
 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
@@ -92,6 +100,7 @@ pub struct Card {
     pub bank_code: Option<String>,
     pub nick_name: Option<Secret<String>>,
     pub card_holder_name: Option<Secret<String>>,
+    pub co_badged_card_data: Option<payment_methods::CoBadgedCardData>,
 }
 
 #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
@@ -120,6 +129,7 @@ pub struct CardDetail {
     pub bank_code: Option<String>,
     pub nick_name: Option<Secret<String>>,
     pub card_holder_name: Option<Secret<String>>,
+    pub co_badged_card_data: Option<payment_methods::CoBadgedCardData>,
 }
 
 impl CardDetailsForNetworkTransactionId {
@@ -162,6 +172,7 @@ impl From<&Card> for CardDetail {
             bank_code: item.bank_code.to_owned(),
             nick_name: item.nick_name.to_owned(),
             card_holder_name: item.card_holder_name.to_owned(),
+            co_badged_card_data: item.co_badged_card_data.to_owned(),
         }
     }
 }
@@ -723,6 +734,7 @@ impl TryFrom<payment_methods::PaymentMethodCreateData> for PaymentMethodData {
                 bank_code: None,
                 nick_name,
                 card_holder_name,
+                co_badged_card_data: None,
             })),
         }
     }
@@ -732,7 +744,7 @@ impl From<api_models::payments::PaymentMethodData> for PaymentMethodData {
     fn from(api_model_payment_method_data: api_models::payments::PaymentMethodData) -> Self {
         match api_model_payment_method_data {
             api_models::payments::PaymentMethodData::Card(card_data) => {
-                Self::Card(Card::from(card_data))
+                Self::Card(Card::from((card_data, None)))
             }
             api_models::payments::PaymentMethodData::CardRedirect(card_redirect) => {
                 Self::CardRedirect(From::from(card_redirect))
@@ -782,8 +794,18 @@ impl From<api_models::payments::PaymentMethodData> for PaymentMethodData {
     }
 }
 
-impl From<api_models::payments::Card> for Card {
-    fn from(value: api_models::payments::Card) -> Self {
+impl
+    From<(
+        api_models::payments::Card,
+        Option<payment_methods::CoBadgedCardData>,
+    )> for Card
+{
+    fn from(
+        (value, co_badged_card_data_optional): (
+            api_models::payments::Card,
+            Option<payment_methods::CoBadgedCardData>,
+        ),
+    ) -> Self {
         let api_models::payments::Card {
             card_number,
             card_exp_month,
@@ -810,6 +832,7 @@ impl From<api_models::payments::Card> for Card {
             bank_code,
             nick_name,
             card_holder_name,
+            co_badged_card_data: co_badged_card_data_optional,
         }
     }
 }
@@ -1875,6 +1898,16 @@ pub enum PaymentMethodsData {
     NetworkToken(NetworkTokenDetailsPaymentMethod),
 }
 
+impl PaymentMethodsData {
+    pub fn get_co_badged_card_data(&self) -> Option<payment_methods::CoBadgedCardData> {
+        if let Self::Card(card) = self {
+            card.co_badged_card_data.clone()
+        } else {
+            None
+        }
+    }
+}
+
 #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
 pub struct NetworkTokenDetailsPaymentMethod {
     pub last4_digits: Option<String>,
@@ -1909,6 +1942,7 @@ pub struct CardDetailsPaymentMethod {
     pub card_type: Option<String>,
     #[serde(default = "saved_in_locker_default")]
     pub saved_to_locker: bool,
+    pub co_badged_card_data: Option<payment_methods::CoBadgedCardData>,
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -1926,6 +1960,7 @@ impl From<payment_methods::CardDetail> for CardDetailsPaymentMethod {
             card_network: item.card_network,
             card_type: item.card_type.map(|card| card.to_string()),
             saved_to_locker: true,
+            co_badged_card_data: None,
         }
     }
 }
diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs
index 955d01c94df..de7d9641449 100644
--- a/crates/hyperswitch_domain_models/src/payment_methods.rs
+++ b/crates/hyperswitch_domain_models/src/payment_methods.rs
@@ -12,7 +12,11 @@ use common_utils::{
 };
 use diesel_models::{enums as storage_enums, PaymentMethodUpdate};
 use error_stack::ResultExt;
+#[cfg(feature = "v1")]
+use masking::ExposeInterface;
 use masking::{PeekInterface, Secret};
+#[cfg(feature = "v1")]
+use router_env::logger;
 #[cfg(feature = "v2")]
 use rustc_hash::FxHashMap;
 #[cfg(feature = "v2")]
@@ -20,13 +24,11 @@ use serde_json::Value;
 use time::PrimitiveDateTime;
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-use crate::{
-    address::Address, payment_method_data as domain_payment_method_data,
-    type_encryption::OptionalEncryptableJsonType,
-};
+use crate::{address::Address, type_encryption::OptionalEncryptableJsonType};
 use crate::{
     mandates::{self, CommonMandateReference},
     merchant_key_store::MerchantKeyStore,
+    payment_method_data as domain_payment_method_data,
     type_encryption::{crypto_operation, AsyncLift, CryptoOperation},
 };
 
@@ -131,6 +133,25 @@ impl PaymentMethod {
         &self.payment_method_id
     }
 
+    #[cfg(feature = "v1")]
+    pub fn get_payment_methods_data(
+        &self,
+    ) -> Option<domain_payment_method_data::PaymentMethodsData> {
+        self.payment_method_data
+            .clone()
+            .map(|value| value.into_inner().expose())
+            .and_then(|value| {
+                serde_json::from_value::<domain_payment_method_data::PaymentMethodsData>(value)
+                    .map_err(|error| {
+                        logger::warn!(
+                            ?error,
+                            "Failed to parse payment method data in payment method info"
+                        );
+                    })
+                    .ok()
+            })
+    }
+
     #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
     pub fn get_id(&self) -> &id_type::GlobalPaymentMethodId {
         &self.id
diff --git a/crates/router/src/core/debit_routing.rs b/crates/router/src/core/debit_routing.rs
index d704c47a521..4b1a7d03990 100644
--- a/crates/router/src/core/debit_routing.rs
+++ b/crates/router/src/core/debit_routing.rs
@@ -28,7 +28,7 @@ pub async fn perform_debit_routing<F, Req, D>(
     operation: &BoxedOperation<'_, F, Req, D>,
     state: &SessionState,
     business_profile: &domain::Profile,
-    payment_data: &D,
+    payment_data: &mut D,
     connector: Option<ConnectorCallType>,
 ) -> (Option<ConnectorCallType>, bool)
 where
@@ -210,7 +210,7 @@ async fn handle_pre_determined_connector<F, D>(
     debit_routing_config: &settings::DebitRoutingConfig,
     debit_routing_supported_connectors: HashSet<api_enums::Connector>,
     connector_data: &api::ConnectorRoutingData,
-    payment_data: &D,
+    payment_data: &mut D,
     acquirer_country: enums::CountryAlpha2,
 ) -> Option<ConnectorCallType>
 where
@@ -236,45 +236,123 @@ where
     None
 }
 
-pub async fn get_sorted_co_badged_networks_by_fee<F: Clone, D: OperationSessionGetters<F>>(
+pub async fn get_sorted_co_badged_networks_by_fee<
+    F: Clone,
+    D: OperationSessionGetters<F> + OperationSessionSetters<F>,
+>(
     state: &SessionState,
-    payment_data: &D,
+    payment_data: &mut D,
     acquirer_country: enums::CountryAlpha2,
 ) -> Option<Vec<enums::CardNetwork>> {
     logger::debug!("Fetching sorted card networks");
-
-    let payment_method_data_optional = payment_data.get_payment_method_data();
     let payment_attempt = payment_data.get_payment_attempt();
 
-    let co_badged_card_request = api_models::open_router::CoBadgedCardRequest {
-        merchant_category_code: enums::MerchantCategoryCode::Mcc0001,
-        acquirer_country,
-        // we need to populate this in case of save card flows
-        // this should we populated by checking for the payment method info
-        // payment method info is some then we will have to send the card isin as null
-        co_badged_card_data: None,
+    let (saved_co_badged_card_data, saved_card_type, card_isin) =
+        extract_saved_card_info(payment_data);
+
+    let debit_routing_output_optional = match (
+        saved_co_badged_card_data
+            .clone()
+            .zip(saved_card_type.clone()),
+        card_isin.clone(),
+    ) {
+        (None, None) => {
+            logger::debug!("Neither co-badged data nor ISIN found; skipping routing");
+            None
+        }
+        _ => {
+            let co_badged_card_data = saved_co_badged_card_data
+                .zip(saved_card_type)
+                .and_then(|(co_badged, card_type)| {
+                    api_models::open_router::DebitRoutingRequestData::try_from((
+                        co_badged, card_type,
+                    ))
+                    .map(Some)
+                    .map_err(|error| {
+                        logger::warn!("Failed to convert co-badged card data: {:?}", error);
+                    })
+                    .ok()
+                })
+                .flatten();
+
+            if co_badged_card_data.is_none() && card_isin.is_none() {
+                logger::debug!("Neither co-badged data nor ISIN found; skipping routing");
+                return None;
+            }
+
+            let co_badged_card_request = api_models::open_router::CoBadgedCardRequest {
+                merchant_category_code: enums::MerchantCategoryCode::Mcc0001,
+                acquirer_country,
+                co_badged_card_data,
+            };
+
+            routing::perform_open_routing_for_debit_routing(
+                state,
+                payment_attempt,
+                co_badged_card_request,
+                card_isin,
+            )
+            .await
+            .map_err(|error| {
+                logger::warn!(?error, "Debit routing call to open router failed");
+            })
+            .ok()
+        }
     };
 
-    if let Some(hyperswitch_domain_models::payment_method_data::PaymentMethodData::Card(card)) =
-        payment_method_data_optional
-    {
-        // perform_open_routing_for_debit_routing
-        let debit_routing_output_optional = routing::perform_open_routing_for_debit_routing(
-            state,
-            payment_attempt,
-            co_badged_card_request,
-            Some(Secret::new(card.card_number.get_card_isin())),
-        )
-        .await
-        .map_err(|error| {
-            logger::warn!(?error, "Failed to calculate total fees per network");
-        })
-        .ok()
-        .map(|data| data.co_badged_card_networks);
+    debit_routing_output_optional
+        .as_ref()
+        .map(|debit_routing_output| payment_data.set_co_badged_card_data(debit_routing_output));
+
+    debit_routing_output_optional.map(|data| {
+        logger::info!(
+            "Co-badged card networks: {:?}",
+            data.co_badged_card_networks
+        );
+        data.co_badged_card_networks
+    })
+}
 
-        return debit_routing_output_optional;
+fn extract_saved_card_info<F, D>(
+    payment_data: &D,
+) -> (
+    Option<api_models::payment_methods::CoBadgedCardData>,
+    Option<String>,
+    Option<Secret<String>>,
+)
+where
+    D: OperationSessionGetters<F>,
+{
+    let payment_method_data_optional = payment_data.get_payment_method_data();
+    match payment_data
+        .get_payment_method_info()
+        .and_then(|info| info.get_payment_methods_data())
+    {
+        Some(hyperswitch_domain_models::payment_method_data::PaymentMethodsData::Card(card)) => {
+            match (&card.co_badged_card_data, &card.card_isin) {
+                (Some(co_badged), _) => {
+                    logger::debug!("Co-badged card data found in saved payment method");
+                    (Some(co_badged.clone()), card.card_type, None)
+                }
+                (None, Some(card_isin)) => {
+                    logger::debug!("No co-badged data; using saved card ISIN");
+                    (None, None, Some(Secret::new(card_isin.clone())))
+                }
+                _ => (None, None, None),
+            }
+        }
+        _ => match payment_method_data_optional {
+            Some(hyperswitch_domain_models::payment_method_data::PaymentMethodData::Card(card)) => {
+                logger::debug!("Using card data from payment request");
+                (
+                    None,
+                    None,
+                    Some(Secret::new(card.card_number.get_card_isin())),
+                )
+            }
+            _ => (None, None, None),
+        },
     }
-    None
 }
 
 fn check_connector_support_for_network(
@@ -317,7 +395,7 @@ async fn handle_retryable_connector<F, D>(
     debit_routing_config: &settings::DebitRoutingConfig,
     debit_routing_supported_connectors: HashSet<api_enums::Connector>,
     connector_data_list: Vec<api::ConnectorRoutingData>,
-    payment_data: &D,
+    payment_data: &mut D,
     acquirer_country: enums::CountryAlpha2,
 ) -> Option<ConnectorCallType>
 where
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 990071b37e4..95924f06308 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -783,6 +783,11 @@ pub(crate) async fn get_payment_method_create_request(
         Some(pm_data) => match payment_method {
             Some(payment_method) => match pm_data {
                 domain::PaymentMethodData::Card(card) => {
+                    let card_network = get_card_network_with_us_local_debit_network_override(
+                        card.card_network.clone(),
+                        card.co_badged_card_data.as_ref(),
+                    );
+
                     let card_detail = payment_methods::CardDetail {
                         card_number: card.card_number.clone(),
                         card_exp_month: card.card_exp_month.clone(),
@@ -790,7 +795,7 @@ pub(crate) async fn get_payment_method_create_request(
                         card_holder_name: billing_name,
                         nick_name: card.nick_name.clone(),
                         card_issuing_country: card.card_issuing_country.clone(),
-                        card_network: card.card_network.clone(),
+                        card_network: card_network.clone(),
                         card_issuer: card.card_issuer.clone(),
                         card_type: card.card_type.clone(),
                     };
@@ -806,8 +811,8 @@ pub(crate) async fn get_payment_method_create_request(
                         card: Some(card_detail),
                         metadata: None,
                         customer_id: customer_id.clone(),
-                        card_network: card
-                            .card_network
+                        card_network: card_network
+                            .clone()
                             .as_ref()
                             .map(|card_network| card_network.to_string()),
                         client_secret: None,
@@ -855,6 +860,32 @@ pub(crate) async fn get_payment_method_create_request(
     }
 }
 
+/// Determines the appropriate card network to to be stored.
+///
+/// If the provided card network is a US local network, this function attempts to
+/// override it with the first global network from the co-badged card data, if available.
+/// Otherwise, it returns the original card network as-is.
+///
+fn get_card_network_with_us_local_debit_network_override(
+    card_network: Option<common_enums::CardNetwork>,
+    co_badged_card_data: Option<&payment_methods::CoBadgedCardData>,
+) -> Option<common_enums::CardNetwork> {
+    // logger::debug!("get_card_network_with_us_local_debit_network_override",);
+    if let Some(true) = card_network
+        .as_ref()
+        .map(|network| network.is_us_local_network())
+    {
+        co_badged_card_data.and_then(|data| {
+            data.co_badged_card_networks
+                .iter()
+                .find(|network| network.is_global_network())
+                .cloned()
+        })
+    } else {
+        card_network
+    }
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[instrument(skip_all)]
 pub async fn create_payment_method(
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index c228975faac..d65cb2ffb87 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -774,7 +774,7 @@ pub async fn skip_locker_call_and_migrate_payment_method(
         .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;
 
     let payment_method_card_details =
-        PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()));
+        PaymentMethodsData::Card(CardDetailsPaymentMethod::from((card.clone(), None)));
 
     let payment_method_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> = Some(
         create_encrypted_data(
@@ -932,10 +932,9 @@ pub async fn save_network_token_and_update_payment_method(
         Ok(resp) => {
             logger::debug!("Network token added to locker");
             let (token_pm_resp, _duplication_check) = resp;
-            let pm_token_details = token_pm_resp
-                .card
-                .as_ref()
-                .map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone())));
+            let pm_token_details = token_pm_resp.card.as_ref().map(|card| {
+                PaymentMethodsData::Card(CardDetailsPaymentMethod::from((card.clone(), None)))
+            });
             let pm_network_token_data_encrypted = pm_token_details
                 .async_map(|pm_card| {
                     create_encrypted_data(
@@ -1382,6 +1381,7 @@ pub async fn add_payment_method_data(
                             card_issuer: card_info.as_ref().and_then(|ci| ci.card_issuer.clone()),
                             card_type: card_info.as_ref().and_then(|ci| ci.card_type.clone()),
                             saved_to_locker: true,
+                            co_badged_card_data: None,
                         };
                         let pm_data_encrypted: Encryptable<Secret<serde_json::Value>> =
                             create_encrypted_data(
@@ -1647,7 +1647,10 @@ pub async fn add_payment_method(
                     });
 
                     let updated_pmd = updated_card.as_ref().map(|card| {
-                        PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()))
+                        PaymentMethodsData::Card(CardDetailsPaymentMethod::from((
+                            card.clone(),
+                            None,
+                        )))
                     });
                     let pm_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> =
                         updated_pmd
@@ -1911,7 +1914,10 @@ pub async fn save_migration_payment_method(
                     });
 
                     let updated_pmd = updated_card.as_ref().map(|card| {
-                        PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()))
+                        PaymentMethodsData::Card(CardDetailsPaymentMethod::from((
+                            card.clone(),
+                            None,
+                        )))
                     });
                     let pm_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> =
                         updated_pmd
@@ -2024,7 +2030,7 @@ pub async fn insert_payment_method(
     let pm_card_details = resp
         .card
         .clone()
-        .map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone())));
+        .map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from((card.clone(), None))));
     let key_manager_state = state.into();
     let pm_data_encrypted: crypto::OptionalEncryptableValue = pm_card_details
         .clone()
@@ -2247,9 +2253,9 @@ pub async fn update_customer_payment_method(
                 saved_to_locker: true,
             });
 
-            let updated_pmd = updated_card
-                .as_ref()
-                .map(|card| PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone())));
+            let updated_pmd = updated_card.as_ref().map(|card| {
+                PaymentMethodsData::Card(CardDetailsPaymentMethod::from((card.clone(), None)))
+            });
             let key_manager_state = (&state).into();
             let pm_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> = updated_pmd
                 .async_map(|updated_pmd| {
diff --git a/crates/router/src/core/payment_methods/tokenize.rs b/crates/router/src/core/payment_methods/tokenize.rs
index 21e2ed4feef..cce741d2c40 100644
--- a/crates/router/src/core/payment_methods/tokenize.rs
+++ b/crates/router/src/core/payment_methods/tokenize.rs
@@ -273,6 +273,7 @@ where
             card_network: card_details.card_network.clone(),
             card_type: card_details.card_type.clone(),
             saved_to_locker,
+            co_badged_card_data: card_details.co_badged_card_data.clone(),
         });
         create_encrypted_data(&self.state.into(), self.key_store, pm_data)
             .await
@@ -298,6 +299,7 @@ where
             card_network: card_details.card_network.clone(),
             card_type: card_details.card_type.clone(),
             saved_to_locker,
+            co_badged_card_data: None,
         });
         create_encrypted_data(&self.state.into(), self.key_store, token_data)
             .await
diff --git a/crates/router/src/core/payment_methods/tokenize/card_executor.rs b/crates/router/src/core/payment_methods/tokenize/card_executor.rs
index eb9d3d6b6c6..e04e688933d 100644
--- a/crates/router/src/core/payment_methods/tokenize/card_executor.rs
+++ b/crates/router/src/core/payment_methods/tokenize/card_executor.rs
@@ -131,6 +131,7 @@ impl<'a> NetworkTokenizationBuilder<'a, CardRequestValidated> {
                 .map_or(card_req.card_issuing_country.clone(), |card_info| {
                     card_info.card_issuing_country.clone()
                 }),
+            co_badged_card_data: None,
         };
         NetworkTokenizationBuilder {
             state: std::marker::PhantomData,
diff --git a/crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs b/crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs
index 2249434b107..a55896b36c5 100644
--- a/crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs
+++ b/crates/router/src/core/payment_methods/tokenize/payment_method_executor.rs
@@ -151,6 +151,7 @@ impl<'a> NetworkTokenizationBuilder<'a, PmValidated> {
             card_issuing_country: optional_card_info
                 .as_ref()
                 .and_then(|card_info| card_info.card_issuing_country.clone()),
+            co_badged_card_data: None,
         };
         NetworkTokenizationBuilder {
             state: std::marker::PhantomData,
diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs
index 2231f7d89f6..af60d07a466 100644
--- a/crates/router/src/core/payment_methods/vault.rs
+++ b/crates/router/src/core/payment_methods/vault.rs
@@ -121,6 +121,7 @@ impl Vaultable for domain::Card {
             card_type: None,
             nick_name: value1.nickname.map(masking::Secret::new),
             card_holder_name: value1.card_holder_name,
+            co_badged_card_data: None,
         };
 
         let supp_data = SupplementaryVaultData {
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 56988beec87..789a4f581b3 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -360,7 +360,7 @@ where
         &operation,
         state,
         &business_profile,
-        &payment_data,
+        &mut payment_data,
         connector,
     )
     .await;
@@ -615,8 +615,8 @@ where
                         (business_profile.is_debit_routing_enabled && is_debit_routing_performed)
                             .then(|| find_connector_with_networks(&mut connectors))
                             .flatten()
-                            .map(|(connector_data, local_network)| {
-                                payment_data.set_local_network(local_network);
+                            .map(|(connector_data, network)| {
+                                payment_data.set_card_network(network);
                                 connector_data
                             }) {
                         connector_from_network
@@ -8076,7 +8076,11 @@ pub trait OperationSessionSetters<F> {
         &mut self,
         merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
     );
-    fn set_local_network(&mut self, local_network: enums::CardNetwork);
+    fn set_card_network(&mut self, card_network: enums::CardNetwork);
+    fn set_co_badged_card_data(
+        &mut self,
+        debit_routing_ouput: &api_models::open_router::DebitRoutingOutput,
+    );
     #[cfg(feature = "v1")]
     fn set_capture_method_in_attempt(&mut self, capture_method: enums::CaptureMethod);
     fn set_frm_message(&mut self, frm_message: FraudCheck);
@@ -8306,9 +8310,37 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentData<F> {
         self.payment_attempt.merchant_connector_id = merchant_connector_id;
     }
 
-    fn set_local_network(&mut self, local_network: enums::CardNetwork) {
+    fn set_card_network(&mut self, card_network: enums::CardNetwork) {
+        if let Some(domain::PaymentMethodData::Card(card)) = &mut self.payment_method_data {
+            card.card_network = Some(card_network);
+        };
+    }
+
+    fn set_co_badged_card_data(
+        &mut self,
+        debit_routing_ouput: &api_models::open_router::DebitRoutingOutput,
+    ) {
+        let co_badged_card_data =
+            api_models::payment_methods::CoBadgedCardData::from(debit_routing_ouput);
+        let card_type = debit_routing_ouput
+            .card_type
+            .clone()
+            .to_string()
+            .to_uppercase();
+        logger::debug!("set co-badged card data");
         if let Some(domain::PaymentMethodData::Card(card)) = &mut self.payment_method_data {
-            card.card_network = Some(local_network);
+            card.co_badged_card_data = Some(co_badged_card_data);
+            card.card_type = Some(card_type);
+            logger::debug!("set co-badged card data in payment method data");
+        } else if let Some(
+            hyperswitch_domain_models::payment_method_data::PaymentMethodsData::Card(card),
+        ) = &mut self
+            .get_payment_method_info()
+            .and_then(|payment_method_info| payment_method_info.get_payment_methods_data())
+        {
+            card.co_badged_card_data = Some(co_badged_card_data);
+            card.card_type = Some(card_type);
+            logger::debug!("set co-badged card data in payment method info");
         };
     }
 
@@ -8534,7 +8566,14 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentIntentData<F> {
         todo!()
     }
 
-    fn set_local_network(&mut self, local_network: enums::CardNetwork) {
+    fn set_card_network(&mut self, card_network: enums::CardNetwork) {
+        todo!()
+    }
+
+    fn set_co_badged_card_data(
+        &mut self,
+        debit_routing_ouput: &api_models::open_router::DebitRoutingOutput,
+    ) {
         todo!()
     }
 
@@ -8775,7 +8814,14 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentConfirmData<F> {
         todo!()
     }
 
-    fn set_local_network(&mut self, local_network: enums::CardNetwork) {
+    fn set_card_network(&mut self, card_network: enums::CardNetwork) {
+        todo!()
+    }
+
+    fn set_co_badged_card_data(
+        &mut self,
+        debit_routing_ouput: &api_models::open_router::DebitRoutingOutput,
+    ) {
         todo!()
     }
 
@@ -8988,7 +9034,14 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentStatusData<F> {
         todo!()
     }
 
-    fn set_local_network(&mut self, local_network: enums::CardNetwork) {
+    fn set_card_network(&mut self, card_network: enums::CardNetwork) {
+        todo!()
+    }
+
+    fn set_co_badged_card_data(
+        &mut self,
+        debit_routing_ouput: &api_models::open_router::DebitRoutingOutput,
+    ) {
         todo!()
     }
 
@@ -9211,7 +9264,14 @@ impl<F: Clone> OperationSessionSetters<F> for PaymentCaptureData<F> {
         todo!()
     }
 
-    fn set_local_network(&mut self, local_network: enums::CardNetwork) {
+    fn set_card_network(&mut self, card_network: enums::CardNetwork) {
+        todo!()
+    }
+
+    fn set_co_badged_card_data(
+        &mut self,
+        debit_routing_ouput: &api_models::open_router::DebitRoutingOutput,
+    ) {
         todo!()
     }
 
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 8bd2c0d3b73..6b6d23951d4 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -2116,6 +2116,11 @@ pub async fn retrieve_payment_method_data_with_permanent_token(
             .network_token_requestor_reference_id
             .clone(),
     );
+
+    let co_badged_card_data = payment_method_info
+        .get_payment_methods_data()
+        .and_then(|payment_methods_data| payment_methods_data.get_co_badged_card_data());
+
     match vault_fetch_action {
         VaultFetchAction::FetchCardDetailsFromLocker => {
             let card = vault_data
@@ -2128,6 +2133,7 @@ pub async fn retrieve_payment_method_data_with_permanent_token(
                         &payment_intent.merchant_id,
                         locker_id,
                         card_token_data,
+                        co_badged_card_data,
                     )
                     .await
                 })
@@ -2178,6 +2184,7 @@ pub async fn retrieve_payment_method_data_with_permanent_token(
                                     &payment_intent.merchant_id,
                                     locker_id,
                                     card_token_data,
+                                    co_badged_card_data,
                                 )
                                 .await
                             })
@@ -2242,6 +2249,7 @@ pub async fn retrieve_card_with_permanent_token_for_external_authentication(
             &payment_intent.merchant_id,
             locker_id,
             card_token_data,
+            None,
         )
         .await
         .change_context(errors::ApiErrorResponse::InternalServerError)
@@ -2259,7 +2267,9 @@ pub async fn fetch_card_details_from_locker(
     merchant_id: &id_type::MerchantId,
     locker_id: &str,
     card_token_data: Option<&domain::CardToken>,
+    co_badged_card_data: Option<api_models::payment_methods::CoBadgedCardData>,
 ) -> RouterResult<domain::Card> {
+    logger::debug!("Fetching card details from locker");
     let card = cards::get_card_from_locker(state, customer_id, merchant_id, locker_id)
         .await
         .change_context(errors::ApiErrorResponse::InternalServerError)
@@ -2304,7 +2314,7 @@ pub async fn fetch_card_details_from_locker(
         card_issuing_country: None,
         bank_code: None,
     };
-    Ok(api_card.into())
+    Ok(domain::Card::from((api_card, co_badged_card_data)))
 }
 
 #[cfg(all(
@@ -4737,15 +4747,26 @@ pub async fn get_additional_payment_data(
                 _ => None,
             };
 
-            let card_network = match card_data
+            // Added an additional check for card_data.co_badged_card_data.is_some()
+            // because is_cobadged_card() only returns true if the card number matches a specific regex.
+            // However, this regex does not cover all possible co-badged networks.
+            // The co_badged_card_data field is populated based on a co-badged BIN lookup
+            // and helps identify co-badged cards that may not match the regex alone.
+            // Determine the card network based on cobadge detection and co-badged BIN data
+            let is_cobadged_based_on_regex = card_data
                 .card_number
                 .is_cobadged_card()
                 .change_context(errors::ApiErrorResponse::InternalServerError)
                 .attach_printable(
                     "Card cobadge check failed due to an invalid card network regex",
-                )? {
-                true => card_data.card_network.clone(),
-                false => None,
+                )?;
+
+            let card_network = match (
+                is_cobadged_based_on_regex,
+                card_data.co_badged_card_data.is_some(),
+            ) {
+                (false, false) => None,
+                _ => card_data.card_network.clone(),
             };
 
             let last4 = Some(card_data.card_number.get_last4());
diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs
index 40cd4c81612..1817c05e648 100644
--- a/crates/router/src/core/payments/tokenization.rs
+++ b/crates/router/src/core/payments/tokenization.rs
@@ -195,6 +195,11 @@ where
                         payment_method_billing_address,
                     )
                     .await?;
+                let payment_methods_data =
+                    &save_payment_method_data.request.get_payment_method_data();
+
+                let co_badged_card_data = payment_methods_data.get_co_badged_card_data();
+
                 let customer_id = customer_id.to_owned().get_required_value("customer_id")?;
                 let merchant_id = merchant_context.get_merchant_account().get_id();
                 let is_network_tokenization_enabled =
@@ -263,7 +268,7 @@ where
                     save_payment_method_data.request.get_payment_method_data(),
                 ) {
                     (Some(card), _) => Some(PaymentMethodsData::Card(
-                        CardDetailsPaymentMethod::from(card.clone()),
+                        CardDetailsPaymentMethod::from((card.clone(), co_badged_card_data)),
                     )),
                     (
                         _,
@@ -294,7 +299,10 @@ where
                 > = match network_token_resp {
                     Some(token_resp) => {
                         let pm_token_details = token_resp.card.as_ref().map(|card| {
-                            PaymentMethodsData::Card(CardDetailsPaymentMethod::from(card.clone()))
+                            PaymentMethodsData::Card(CardDetailsPaymentMethod::from((
+                                card.clone(),
+                                None,
+                            )))
                         });
 
                         pm_token_details
@@ -641,9 +649,10 @@ where
                                 });
 
                                 let updated_pmd = updated_card.as_ref().map(|card| {
-                                    PaymentMethodsData::Card(CardDetailsPaymentMethod::from(
+                                    PaymentMethodsData::Card(CardDetailsPaymentMethod::from((
                                         card.clone(),
-                                    ))
+                                        None,
+                                    )))
                                 });
                                 let pm_data_encrypted: Option<
                                     Encryptable<Secret<serde_json::Value>>,
diff --git a/crates/router/src/core/payouts/helpers.rs b/crates/router/src/core/payouts/helpers.rs
index 2cbb532bc35..8b71c02349b 100644
--- a/crates/router/src/core/payouts/helpers.rs
+++ b/crates/router/src/core/payouts/helpers.rs
@@ -494,6 +494,7 @@ pub async fn save_payout_data_to_locker(
                             card_network: card_info.card_network,
                             card_type: card_info.card_type,
                             saved_to_locker: true,
+                            co_badged_card_data: None,
                         },
                     )
                 })
@@ -514,6 +515,7 @@ pub async fn save_payout_data_to_locker(
                             card_network: None,
                             card_type: None,
                             saved_to_locker: true,
+                            co_badged_card_data: None,
                         },
                     )
                 });
diff --git a/crates/router/src/utils/verify_connector.rs b/crates/router/src/utils/verify_connector.rs
index b13ba70e6fb..0f5d9e6b318 100644
--- a/crates/router/src/utils/verify_connector.rs
+++ b/crates/router/src/utils/verify_connector.rs
@@ -24,6 +24,7 @@ pub fn generate_card_from_details(
         card_issuing_country: None,
         bank_code: None,
         card_holder_name: None,
+        co_badged_card_data: None,
     })
 }
 
diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs
index 8b3372d7dec..3497a048a8a 100644
--- a/crates/router/tests/connectors/aci.rs
+++ b/crates/router/tests/connectors/aci.rs
@@ -52,6 +52,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
                 bank_code: None,
                 nick_name: Some(Secret::new("nick_name".into())),
                 card_holder_name: Some(Secret::new("card holder name".into())),
+                co_badged_card_data: None,
             }),
             confirm: true,
             statement_descriptor_suffix: None,
@@ -302,6 +303,7 @@ async fn payments_create_failure() {
                 bank_code: None,
                 nick_name: Some(Secret::new("nick_name".into())),
                 card_holder_name: Some(Secret::new("card holder name".into())),
+                co_badged_card_data: None,
             });
 
         let response = services::api::execute_connector_processing_step(
diff --git a/crates/router/tests/connectors/adyen.rs b/crates/router/tests/connectors/adyen.rs
index c7ad3b69a32..d7017d3d44e 100644
--- a/crates/router/tests/connectors/adyen.rs
+++ b/crates/router/tests/connectors/adyen.rs
@@ -154,6 +154,7 @@ impl AdyenTest {
                 bank_code: None,
                 nick_name: Some(Secret::new("nick_name".into())),
                 card_holder_name: Some(Secret::new("card holder name".into())),
+                co_badged_card_data: None,
             }),
             confirm: true,
             statement_descriptor_suffix: None,
diff --git a/crates/router/tests/connectors/airwallex.rs b/crates/router/tests/connectors/airwallex.rs
index 0e538818d50..bf5a06f157a 100644
--- a/crates/router/tests/connectors/airwallex.rs
+++ b/crates/router/tests/connectors/airwallex.rs
@@ -83,6 +83,7 @@ fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
             bank_code: None,
             nick_name: Some(Secret::new("nick_name".into())),
             card_holder_name: Some(Secret::new("card holder name".into())),
+            co_badged_card_data: None,
         }),
         capture_method: Some(diesel_models::enums::CaptureMethod::Manual),
         router_return_url: Some("https://google.com".to_string()),
diff --git a/crates/router/tests/connectors/fiserv.rs b/crates/router/tests/connectors/fiserv.rs
index 78235278ed9..77ab8223145 100644
--- a/crates/router/tests/connectors/fiserv.rs
+++ b/crates/router/tests/connectors/fiserv.rs
@@ -54,6 +54,7 @@ fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
             bank_code: None,
             nick_name: Some(Secret::new("nick_name".into())),
             card_holder_name: Some(Secret::new("card holder name".into())),
+            co_badged_card_data: None,
         }),
         capture_method: Some(diesel_models::enums::CaptureMethod::Manual),
         ..utils::PaymentAuthorizeType::default().0
diff --git a/crates/router/tests/connectors/rapyd.rs b/crates/router/tests/connectors/rapyd.rs
index ee6ac303e88..e173f4753d6 100644
--- a/crates/router/tests/connectors/rapyd.rs
+++ b/crates/router/tests/connectors/rapyd.rs
@@ -54,6 +54,7 @@ async fn should_only_authorize_payment() {
                     bank_code: None,
                     nick_name: Some(Secret::new("nick_name".into())),
                     card_holder_name: Some(Secret::new("card holder name".into())),
+                    co_badged_card_data: None,
                 }),
                 capture_method: Some(diesel_models::enums::CaptureMethod::Manual),
                 ..utils::PaymentAuthorizeType::default().0
@@ -82,6 +83,7 @@ async fn should_authorize_and_capture_payment() {
                     bank_code: None,
                     nick_name: Some(Secret::new("nick_name".into())),
                     card_holder_name: Some(Secret::new("card holder name".into())),
+                    co_badged_card_data: None,
                 }),
                 ..utils::PaymentAuthorizeType::default().0
             }),
diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs
index ede3aeb17db..d6925ae1667 100644
--- a/crates/router/tests/connectors/utils.rs
+++ b/crates/router/tests/connectors/utils.rs
@@ -941,6 +941,7 @@ impl Default for CCardType {
             bank_code: None,
             nick_name: Some(Secret::new("nick_name".into())),
             card_holder_name: Some(Secret::new("card holder name".into())),
+            co_badged_card_data: None,
         })
     }
 }
diff --git a/crates/router/tests/connectors/worldline.rs b/crates/router/tests/connectors/worldline.rs
index 793a1cc15f4..22fd198bd0a 100644
--- a/crates/router/tests/connectors/worldline.rs
+++ b/crates/router/tests/connectors/worldline.rs
@@ -84,6 +84,7 @@ impl WorldlineTest {
                 bank_code: None,
                 nick_name: Some(Secret::new("nick_name".into())),
                 card_holder_name: Some(Secret::new("card holder name".into())),
+                co_badged_card_data: None,
             }),
             confirm: true,
             statement_descriptor_suffix: None,

## 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 -->
Once debit routing is performed for a card and the card is saved in the payment, we can also store the debit routing output. This allows us to reuse the saved data in future saved card flows instead of re-running the debit routing process.

Changes:

In this PR, support for co-badged card data has been introduced. This data will be stored in the payment_method_data column of the payment_methods table and will contain the debit routing output.

In the saved card flow, we check if the co-badged card data is present in the payment_method_data of the payment method. If it is present, the same data will be sent to the open router for debit routing.

If the co-badged card data is not available, then the card_isin, which contains the card BIN, will be used to call the open router.

### 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`
-->
add debit routing support for saved card flow

## 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)?
-->
Tested locally by creating dummy co-badged card bin dump
-> Create a merchant account and business profile
-> Enable debit routing and provide merchant business country for the business profile
```
curl --location 'http://localhost:8080/account/merchant_1745690754/business_profile/pro_OiJkBiFuCYbYAkCG9X02' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: ' \
--data '{
    "is_debit_routing_enabled": true,
    "merchant_business_country": "US"

}'
```
-> Create a payment
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'x-tenant-id: hyperswitch' \
--header 'api-key: dev_t6MGc7fYh7s9QLODlx0Pvl5QaGQtKhHFq0eUOJm6hNBfrWK2FqqWZ4tDXpqMUzfZ' \
--data-raw '{
    "amount": 100,
    "amount_to_capture": 100,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "setup_future_usage": "on_session",
    "capture_on": "2022-09-10T10:11:12Z",
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+1",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "customer_id": "cu_1745917372",
    "return_url": "http://127.0.0.1:4040",
    "payment_method": "card",
    "payment_method_type": "debit",
    "payment_method_data": {
        "card": {
            "card_number": "4400002000000004",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "card_cvc": "737"
        }
    },
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX",
            "last_name": "ss"
        },
        "email": "raj@gmail.com"
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX"
        }
    },
    "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": "125.0.0.1"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    }
}'
```
```
{
  "payment_id": "pay_p70wBAMKn2Cwih0biDX0",
  "merchant_id": "merchant_1745690754",
  "status": "succeeded",
  "amount": 100,
  "net_amount": 100,
  "shipping_cost": null,
  "amount_capturable": 0,
  "amount_received": 100,
  "connector": "adyen",
  "client_secret": "pay_p70wBAMKn2Cwih0biDX0_secret_n9DPdVNK5DMvaPoYj3y2",
  "created": "2025-04-29T09:02:58.609Z",
  "currency": "USD",
  "customer_id": "cu_1745917372",
  "customer": {
    "id": "cu_1745917372",
    "name": "John Doe",
    "email": "guest@example.com",
    "phone": "999999999",
    "phone_country_code": "+1"
  },
  "description": "Its my first payment request",
  "refunds": null,
  "disputes": null,
  "mandate_id": null,
  "mandate_data": null,
  "setup_future_usage": "on_session",
  "off_session": null,
  "capture_on": null,
  "capture_method": "automatic",
  "payment_method": "card",
  "payment_method_data": {
    "card": {
      "last4": "0004",
      "card_type": null,
      "card_network": null,
      "card_issuer": null,
      "card_issuing_country": null,
      "card_isin": "440000",
      "card_extended_bin": null,
      "card_exp_month": "03",
      "card_exp_year": "2030",
      "card_holder_name": "joseph Doe",
      "payment_checks": null,
      "authentication_data": null
    },
    "billing": null
  },
  "payment_token": null,
  "shipping": {
    "address": {
      "city": "San Fransico",
      "country": "US",
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "zip": "94122",
      "state": "California",
      "first_name": "PiX",
      "last_name": null
    },
    "phone": null,
    "email": null
  },
  "billing": {
    "address": {
      "city": "San",
      "country": "US",
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "zip": "94122",
      "state": "California",
      "first_name": "PiX",
      "last_name": "ss"
    },
    "phone": null,
    "email": "raj@gmail.com"
  },
  "order_details": null,
  "email": "guest@example.com",
  "name": "John Doe",
  "phone": "999999999",
  "return_url": "http://127.0.0.1:4040/",
  "authentication_type": "no_three_ds",
  "statement_descriptor_name": "joseph",
  "statement_descriptor_suffix": "JS",
  "next_action": null,
  "cancellation_reason": null,
  "error_code": null,
  "error_message": null,
  "unified_code": null,
  "unified_message": null,
  "payment_experience": null,
  "payment_method_type": "debit",
  "connector_label": null,
  "business_country": null,
  "business_label": "default",
  "business_sub_label": null,
  "allowed_payment_method_types": null,
  "ephemeral_key": {
    "customer_id": "cu_1745917372",
    "created_at": 1745917378,
    "expires": 1745920978,
    "secret": "epk_248a7b7506aa4a60b28db8ddf75d38ad"
  },
  "manual_retry_allowed": false,
  "connector_transaction_id": "B6WPZCJ7DLDD9J75",
  "frm_message": null,
  "metadata": {
    "udf1": "value1",
    "login_date": "2019-09-10T10:11:12Z",
    "new_customer": "true"
  },
  "connector_metadata": null,
  "feature_metadata": null,
  "reference_id": "pay_p70wBAMKn2Cwih0biDX0_1",
  "payment_link": null,
  "profile_id": "pro_OiJkBiFuCYbYAkCG9X02",
  "surcharge_details": null,
  "attempt_count": 1,
  "merchant_decision": null,
  "merchant_connector_id": "mca_VyX6BwB09KJrmeR1ODFD",
  "incremental_authorization_allowed": null,
  "authorization_count": null,
  "incremental_authorizations": null,
  "external_authentication_details": null,
  "external_3ds_authentication_attempted": false,
  "expires_on": "2025-04-29T09:17:58.609Z",
  "fingerprint": null,
  "browser_info": {
    "language": "nl-NL",
    "time_zone": 0,
    "ip_address": "125.0.0.1",
    "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",
    "color_depth": 24,
    "java_enabled": true,
    "screen_width": 1536,
    "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "screen_height": 723,
    "java_script_enabled": true
  },
  "payment_method_id": null,
  "payment_method_status": null,
  "updated": "2025-04-29T09:03:00.705Z",
  "split_payments": null,
  "frm_metadata": null,
  "extended_authorization_applied": null,
  "capture_before": null,
  "merchant_order_reference_id": null,
  "order_tax_amount": null,
  "connector_mandate_id": null,
  "card_discovery": "manual",
  "force_3ds_challenge": false,
  "force_3ds_challenge_trigger": false,
  "issuer_error_code": null,
  "issuer_error_message": null
}
```
-> Connector request indicating the card brand as star
![image](https://github.com/user-attachments/assets/42033c7c-cdf2-449e-8164-544c747a2f2a)
-> Create a payment for the same customer
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_t6MGc7fYh7s9QLODlx0Pvl5QaGQtKhHFq0eUOJm6hNBfrWK2FqqWZ4tDXpqMUzfZ' \
--data-raw '{
    "amount": 6100,
    "currency": "USD",
    "confirm": false,
    "business_country": "US",
    "business_label": "default",
    "amount_to_capture": 6100,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "return_url": "https://google.com",
    "email": "something@gmail.com",
    "setup_future_usage": "on_session",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "customer_id": "cu_1745917372",

    "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"
        }
    }
}'
```
```
{
  "payment_id": "pay_icPaUi7x7A2gK2F43q56",
  "merchant_id": "merchant_1745690754",
  "status": "requires_payment_method",
  "amount": 6100,
  "net_amount": 6100,
  "shipping_cost": null,
  "amount_capturable": 0,
  "amount_received": null,
  "connector": null,
  "client_secret": "pay_icPaUi7x7A2gK2F43q56_secret_gKv1GroVoPf0i000siHK",
  "created": "2025-04-29T09:06:25.436Z",
  "currency": "USD",
  "customer_id": "cu_1745917372",
  "customer": {
    "id": "cu_1745917372",
    "name": "Joseph Doe",
    "email": "something@gmail.com",
    "phone": "999999999",
    "phone_country_code": "+65"
  },
  "description": "Its my first payment request",
  "refunds": null,
  "disputes": null,
  "mandate_id": null,
  "mandate_data": null,
  "setup_future_usage": "on_session",
  "off_session": null,
  "capture_on": null,
  "capture_method": "automatic",
  "payment_method": null,
  "payment_method_data": null,
  "payment_token": null,
  "shipping": null,
  "billing": {
    "address": {
      "city": "San Fransico",
      "country": "US",
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "zip": "94122",
      "state": "California",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    },
    "email": null
  },
  "order_details": null,
  "email": "something@gmail.com",
  "name": "Joseph Doe",
  "phone": "999999999",
  "return_url": "https://google.com/",
  "authentication_type": null,
  "statement_descriptor_name": "Juspay",
  "statement_descriptor_suffix": "Router",
  "next_action": null,
  "cancellation_reason": null,
  "error_code": null,
  "error_message": null,
  "unified_code": null,
  "unified_message": null,
  "payment_experience": null,
  "payment_method_type": null,
  "connector_label": null,
  "business_country": "US",
  "business_label": "default",
  "business_sub_label": null,
  "allowed_payment_method_types": null,
  "ephemeral_key": {
    "customer_id": "cu_1745917372",
    "created_at": 1745917585,
    "expires": 1745921185,
    "secret": "epk_03223a8293164e14a0b1dc07cc86404a"
  },
  "manual_retry_allowed": null,
  "connector_transaction_id": null,
  "frm_message": null,
  "metadata": null,
  "connector_metadata": null,
  "feature_metadata": null,
  "reference_id": null,
  "payment_link": null,
  "profile_id": "pro_OiJkBiFuCYbYAkCG9X02",
  "surcharge_details": null,
  "attempt_count": 1,
  "merchant_decision": null,
  "merchant_connector_id": null,
  "incremental_authorization_allowed": null,
  "authorization_count": null,
  "incremental_authorizations": null,
  "external_authentication_details": null,
  "external_3ds_authentication_attempted": false,
  "expires_on": "2025-04-29T09:21:25.436Z",
  "fingerprint": null,
  "browser_info": null,
  "payment_method_id": null,
  "payment_method_status": null,
  "updated": "2025-04-29T09:06:25.462Z",
  "split_payments": null,
  "frm_metadata": null,
  "extended_authorization_applied": null,
  "capture_before": null,
  "merchant_order_reference_id": null,
  "order_tax_amount": null,
  "connector_mandate_id": null,
  "card_discovery": null,
  "force_3ds_challenge": false,
  "force_3ds_challenge_trigger": false,
  "issuer_error_code": null,
  "issuer_error_message": null
}
```
-> list payment methods for the same customer
```
curl --location 'http://localhost:8080/customers/cu_1745917372/payment_methods' \
--header 'Accept: application/json' \
--header 'api-key: dev_t6MGc7fYh7s9QLODlx0Pvl5QaGQtKhHFq0eUOJm6hNBfrWK2FqqWZ4tDXpqMUzfZ'
```
```
{
  "customer_payment_methods": [
    {
      "payment_token": "token_mzQEW3GchjpQQDxWqQ7G",
      "payment_method_id": "pm_KNynHcJOxmcco1GrzdWm",
      "customer_id": "cu_1745917372",
      "payment_method": "card",
      "payment_method_type": "debit",
      "payment_method_issuer": null,
      "payment_method_issuer_code": null,
      "recurring_enabled": false,
      "installment_payment_enabled": false,
      "payment_experience": [
        "redirect_to_url"
      ],
      "card": {
        "scheme": "Star",
        "issuer_country": null,
        "last4_digits": "0004",
        "expiry_month": "03",
        "expiry_year": "2030",
        "card_token": null,
        "card_holder_name": "joseph Doe",
        "card_fingerprint": null,
        "nick_name": null,
        "card_network": "Star",
        "card_isin": "440000",
        "card_issuer": null,
        "card_type": null,
        "saved_to_locker": true
      },
      "metadata": null,
      "created": "2025-04-29T09:03:00.719Z",
      "bank": null,
      "surcharge_details": null,
      "requires_cvv": true,
      "last_used_at": "2025-04-29T09:03:00.719Z",
      "default_payment_method_set": true,
      "billing": {
        "address": {
          "city": "San",
          "country": "US",
          "line1": "1467",
          "line2": "Harrison Street",
          "line3": "Harrison Street",
          "zip": "94122",
          "state": "California",
          "first_name": "joseph",
          "last_name": "Doe"
        },
        "phone": null,
        "email": "raj@gmail.com"
      }
    }
  ],
  "is_guest_customer": null
}
```
-> Confirm the a payment with the payment token
```
curl --location 'http://localhost:8080/payments/pay_icPaUi7x7A2gK2F43q56/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: pk_dev_f3e0703c217345e3ace5d6c6cd2046ad' \
--data '{
    "payment_token": "token_mzQEW3GchjpQQDxWqQ7G",
    "payment_method_type": "debit",
    "payment_method": "card",
    "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": "125.0.0.1"
    },
    "client_secret": "pay_icPaUi7x7A2gK2F43q56_secret_gKv1GroVoPf0i000siHK",
    "setup_future_usage": "on_session",
    "payment_method_data": {
        "card_token": {
            "card_cvc": "123"
        }
    }
}'
```
```
{
  "payment_id": "pay_icPaUi7x7A2gK2F43q56",
  "merchant_id": "merchant_1745690754",
  "status": "failed",
  "amount": 6100,
  "net_amount": 6100,
  "shipping_cost": null,
  "amount_capturable": 0,
  "amount_received": null,
  "connector": "adyen",
  "client_secret": "pay_icPaUi7x7A2gK2F43q56_secret_gKv1GroVoPf0i000siHK",
  "created": "2025-04-29T09:06:25.436Z",
  "currency": "USD",
  "customer_id": "cu_1745917372",
  "customer": {
    "id": "cu_1745917372",
    "name": "Joseph Doe",
    "email": "something@gmail.com",
    "phone": "999999999",
    "phone_country_code": "+65"
  },
  "description": "Its my first payment request",
  "refunds": null,
  "disputes": null,
  "mandate_id": null,
  "mandate_data": null,
  "setup_future_usage": "on_session",
  "off_session": null,
  "capture_on": null,
  "capture_method": "automatic",
  "payment_method": "card",
  "payment_method_data": {
    "card": {
      "last4": "0004",
      "card_type": null,
      "card_network": null,
      "card_issuer": null,
      "card_issuing_country": null,
      "card_isin": "440000",
      "card_extended_bin": null,
      "card_exp_month": "03",
      "card_exp_year": "2030",
      "card_holder_name": "joseph Doe",
      "payment_checks": null,
      "authentication_data": null
    },
    "billing": null
  },
  "payment_token": "token_mzQEW3GchjpQQDxWqQ7G",
  "shipping": null,
  "billing": {
    "address": {
      "city": "San Fransico",
      "country": "US",
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "zip": "94122",
      "state": "California",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    },
    "email": null
  },
  "order_details": null,
  "email": "something@gmail.com",
  "name": "Joseph Doe",
  "phone": "999999999",
  "return_url": "https://google.com/",
  "authentication_type": "no_three_ds",
  "statement_descriptor_name": "Juspay",
  "statement_descriptor_suffix": "Router",
  "next_action": null,
  "cancellation_reason": null,
  "error_code": "24",
  "error_message": "CVC Declined",
  "unified_code": "UE_9000",
  "unified_message": "Something went wrong",
  "payment_experience": null,
  "payment_method_type": "debit",
  "connector_label": "adyen_US_default",
  "business_country": "US",
  "business_label": "default",
  "business_sub_label": null,
  "allowed_payment_method_types": null,
  "ephemeral_key": null,
  "manual_retry_allowed": true,
  "connector_transaction_id": "C87D7CD547P6TNV5",
  "frm_message": null,
  "metadata": null,
  "connector_metadata": null,
  "feature_metadata": null,
  "reference_id": null,
  "payment_link": null,
  "profile_id": "pro_OiJkBiFuCYbYAkCG9X02",
  "surcharge_details": null,
  "attempt_count": 1,
  "merchant_decision": null,
  "merchant_connector_id": "mca_VyX6BwB09KJrmeR1ODFD",
  "incremental_authorization_allowed": false,
  "authorization_count": null,
  "incremental_authorizations": null,
  "external_authentication_details": null,
  "external_3ds_authentication_attempted": false,
  "expires_on": "2025-04-29T09:21:25.436Z",
  "fingerprint": null,
  "browser_info": {
    "os_type": null,
    "language": "nl-NL",
    "time_zone": 0,
    "ip_address": "125.0.0.1",
    "os_version": null,
    "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",
    "color_depth": 24,
    "device_model": null,
    "java_enabled": true,
    "screen_width": 1536,
    "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "screen_height": 723,
    "accept_language": "en",
    "java_script_enabled": true
  },
  "payment_method_id": "pm_KNynHcJOxmcco1GrzdWm",
  "payment_method_status": "active",
  "updated": "2025-04-29T09:10:38.933Z",
  "split_payments": null,
  "frm_metadata": null,
  "extended_authorization_applied": null,
  "capture_before": null,
  "merchant_order_reference_id": null,
  "order_tax_amount": null,
  "connector_mandate_id": null,
  "card_discovery": "saved_card",
  "force_3ds_challenge": false,
  "force_3ds_challenge_trigger": false,
  "issuer_error_code": null,
  "issuer_error_message": "DECLINED CVC Incorrect"
}
```
-> Logs showing the debit routing flow was triggered with the previously saved co-badged card data
![image](https://github.com/user-attachments/assets/f348a89a-8279-403c-a847-18ccc948d9e8)
-> Logs showing the card brand was set star in the connector request
![image](https://github.com/user-attachments/assets/01663089-f8f7-4d3a-807e-57bb97c74968)



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