Bug: add `debit_routing_savings` in analytics payment attempt



We need to add debit_routing_savings to the payment analytics. This will provide the savings per card network, as well as the total savings for a profile.
diff --git a/crates/analytics/docs/clickhouse/scripts/payment_attempts.sql b/crates/analytics/docs/clickhouse/scripts/payment_attempts.sql
index 6673b73fedb..16815e9a33d 100644
--- a/crates/analytics/docs/clickhouse/scripts/payment_attempts.sql
+++ b/crates/analytics/docs/clickhouse/scripts/payment_attempts.sql
@@ -44,6 +44,7 @@ CREATE TABLE payment_attempt_queue (
     `profile_id` String,
     `card_network` Nullable(String),
     `routing_approach` LowCardinality(Nullable(String)),
+    `debit_routing_savings` Nullable(UInt32),
     `sign_flag` Int8
 ) ENGINE = Kafka SETTINGS kafka_broker_list = 'kafka0:29092',
 kafka_topic_list = 'hyperswitch-payment-attempt-events',
@@ -98,6 +99,7 @@ CREATE TABLE payment_attempts (
     `profile_id` String,
     `card_network` Nullable(String),
     `routing_approach` LowCardinality(Nullable(String)),
+    `debit_routing_savings` Nullable(UInt32),
     `sign_flag` Int8,
     INDEX connectorIndex connector TYPE bloom_filter GRANULARITY 1,
     INDEX paymentMethodIndex payment_method TYPE bloom_filter GRANULARITY 1,
@@ -155,6 +157,7 @@ CREATE MATERIALIZED VIEW payment_attempt_mv TO payment_attempts (
     `profile_id` String,
     `card_network` Nullable(String),
     `routing_approach` LowCardinality(Nullable(String)),
+    `debit_routing_savings` Nullable(UInt32),
     `sign_flag` Int8
 ) AS
 SELECT
@@ -204,6 +207,7 @@ SELECT
     profile_id,
     card_network,
     routing_approach,
+    debit_routing_savings,
     sign_flag
 FROM
     payment_attempt_queue
diff --git a/crates/analytics/src/payments/accumulator.rs b/crates/analytics/src/payments/accumulator.rs
index 20ccc634068..6d7dca22a30 100644
--- a/crates/analytics/src/payments/accumulator.rs
+++ b/crates/analytics/src/payments/accumulator.rs
@@ -18,6 +18,7 @@ pub struct PaymentMetricsAccumulator {
     pub connector_success_rate: SuccessRateAccumulator,
     pub payments_distribution: PaymentsDistributionAccumulator,
     pub failure_reasons_distribution: FailureReasonsDistributionAccumulator,
+    pub debit_routing: DebitRoutingAccumulator,
 }
 
 #[derive(Debug, Default)]
@@ -58,6 +59,12 @@ pub struct ProcessedAmountAccumulator {
     pub total_without_retries: Option<i64>,
 }
 
+#[derive(Debug, Default)]
+pub struct DebitRoutingAccumulator {
+    pub transaction_count: u64,
+    pub savings_amount: u64,
+}
+
 #[derive(Debug, Default)]
 pub struct AverageAccumulator {
     pub total: u32,
@@ -183,6 +190,27 @@ impl PaymentMetricAccumulator for SuccessRateAccumulator {
     }
 }
 
+impl PaymentMetricAccumulator for DebitRoutingAccumulator {
+    type MetricOutput = (Option<u64>, Option<u64>, Option<u64>);
+
+    fn add_metrics_bucket(&mut self, metrics: &PaymentMetricRow) {
+        if let Some(count) = metrics.count {
+            self.transaction_count += u64::try_from(count).unwrap_or(0);
+        }
+        if let Some(total) = metrics.total.as_ref().and_then(ToPrimitive::to_u64) {
+            self.savings_amount += total;
+        }
+    }
+
+    fn collect(self) -> Self::MetricOutput {
+        (
+            Some(self.transaction_count),
+            Some(self.savings_amount),
+            Some(0),
+        )
+    }
+}
+
 impl PaymentMetricAccumulator for PaymentsDistributionAccumulator {
     type MetricOutput = (
         Option<f64>,
@@ -440,6 +468,9 @@ impl PaymentMetricsAccumulator {
         ) = self.payments_distribution.collect();
         let (failure_reason_count, failure_reason_count_without_smart_retries) =
             self.failure_reasons_distribution.collect();
+        let (debit_routed_transaction_count, debit_routing_savings, debit_routing_savings_in_usd) =
+            self.debit_routing.collect();
+
         PaymentMetricsBucketValue {
             payment_success_rate: self.payment_success_rate.collect(),
             payment_count: self.payment_count.collect(),
@@ -463,6 +494,9 @@ impl PaymentMetricsAccumulator {
             failure_reason_count_without_smart_retries,
             payment_processed_amount_in_usd,
             payment_processed_amount_without_smart_retries_usd,
+            debit_routed_transaction_count,
+            debit_routing_savings,
+            debit_routing_savings_in_usd,
         }
     }
 }
diff --git a/crates/analytics/src/payments/core.rs b/crates/analytics/src/payments/core.rs
index e55ba2726af..c1922ffe924 100644
--- a/crates/analytics/src/payments/core.rs
+++ b/crates/analytics/src/payments/core.rs
@@ -171,6 +171,9 @@ pub async fn get_metrics(
                                 .connector_success_rate
                                 .add_metrics_bucket(&value);
                         }
+                        PaymentMetrics::DebitRouting | PaymentMetrics::SessionizedDebitRouting => {
+                            metrics_builder.debit_routing.add_metrics_bucket(&value);
+                        }
                         PaymentMetrics::PaymentsDistribution => {
                             metrics_builder
                                 .payments_distribution
@@ -294,6 +297,33 @@ pub async fn get_metrics(
             if let Some(count) = collected_values.failure_reason_count_without_smart_retries {
                 total_failure_reasons_count_without_smart_retries += count;
             }
+            if let Some(savings) = collected_values.debit_routing_savings {
+                let savings_in_usd = if let Some(ex_rates) = ex_rates {
+                    id.currency
+                        .and_then(|currency| {
+                            i64::try_from(savings)
+                                .inspect_err(|e| {
+                                    logger::error!(
+                                        "Debit Routing savings conversion error: {:?}",
+                                        e
+                                    )
+                                })
+                                .ok()
+                                .and_then(|savings_i64| {
+                                    convert(ex_rates, currency, Currency::USD, savings_i64)
+                                        .inspect_err(|e| {
+                                            logger::error!("Currency conversion error: {:?}", e)
+                                        })
+                                        .ok()
+                                })
+                        })
+                        .map(|savings| (savings * rust_decimal::Decimal::new(100, 0)).to_u64())
+                        .unwrap_or_default()
+                } else {
+                    None
+                };
+                collected_values.debit_routing_savings_in_usd = savings_in_usd;
+            }
             MetricsBucketResponse {
                 values: collected_values,
                 dimensions: id,
diff --git a/crates/analytics/src/payments/metrics.rs b/crates/analytics/src/payments/metrics.rs
index 67dc50c5152..b19c661322d 100644
--- a/crates/analytics/src/payments/metrics.rs
+++ b/crates/analytics/src/payments/metrics.rs
@@ -15,6 +15,7 @@ use crate::{
 
 mod avg_ticket_size;
 mod connector_success_rate;
+mod debit_routing;
 mod payment_count;
 mod payment_processed_amount;
 mod payment_success_count;
@@ -24,6 +25,7 @@ mod success_rate;
 
 use avg_ticket_size::AvgTicketSize;
 use connector_success_rate::ConnectorSuccessRate;
+use debit_routing::DebitRouting;
 use payment_count::PaymentCount;
 use payment_processed_amount::PaymentProcessedAmount;
 use payment_success_count::PaymentSuccessCount;
@@ -130,6 +132,11 @@ where
                     .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                     .await
             }
+            Self::DebitRouting => {
+                DebitRouting
+                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
+                    .await
+            }
             Self::SessionizedPaymentSuccessRate => {
                 sessionized_metrics::PaymentSuccessRate
                     .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
@@ -175,6 +182,11 @@ where
                     .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
                     .await
             }
+            Self::SessionizedDebitRouting => {
+                sessionized_metrics::DebitRouting
+                    .load_metrics(dimensions, auth, filters, granularity, time_range, pool)
+                    .await
+            }
         }
     }
 }
diff --git a/crates/analytics/src/payments/metrics/debit_routing.rs b/crates/analytics/src/payments/metrics/debit_routing.rs
new file mode 100644
index 00000000000..584221205cd
--- /dev/null
+++ b/crates/analytics/src/payments/metrics/debit_routing.rs
@@ -0,0 +1,151 @@
+use std::collections::HashSet;
+
+use api_models::analytics::{
+    payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
+    Granularity, TimeRange,
+};
+use common_utils::errors::ReportSwitchExt;
+use diesel_models::enums as storage_enums;
+use error_stack::ResultExt;
+use time::PrimitiveDateTime;
+
+use super::PaymentMetricRow;
+use crate::{
+    enums::AuthInfo,
+    query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
+    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
+};
+
+#[derive(Default)]
+pub(super) struct DebitRouting;
+
+#[async_trait::async_trait]
+impl<T> super::PaymentMetric<T> for DebitRouting
+where
+    T: AnalyticsDataSource + super::PaymentMetricAnalytics,
+    PrimitiveDateTime: ToSql<T>,
+    AnalyticsCollection: ToSql<T>,
+    Granularity: GroupByClause<T>,
+    Aggregate<&'static str>: ToSql<T>,
+    Window<&'static str>: ToSql<T>,
+{
+    async fn load_metrics(
+        &self,
+        dimensions: &[PaymentDimensions],
+        auth: &AuthInfo,
+        filters: &PaymentFilters,
+        granularity: Option<Granularity>,
+        time_range: &TimeRange,
+        pool: &T,
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+        let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);
+
+        for dim in dimensions.iter() {
+            query_builder.add_select_column(dim).switch()?;
+        }
+        query_builder
+            .add_select_column(Aggregate::Count {
+                field: None,
+                alias: Some("count"),
+            })
+            .switch()?;
+        query_builder
+            .add_select_column(Aggregate::Sum {
+                field: "debit_routing_savings",
+                alias: Some("total"),
+            })
+            .switch()?;
+        query_builder.add_select_column("currency").switch()?;
+        query_builder
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
+            .switch()?;
+        query_builder
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
+            .switch()?;
+
+        filters.set_filter_clause(&mut query_builder).switch()?;
+
+        auth.set_filter_clause(&mut query_builder).switch()?;
+
+        time_range
+            .set_filter_clause(&mut query_builder)
+            .attach_printable("Error filtering time range")
+            .switch()?;
+
+        for dim in dimensions.iter() {
+            query_builder
+                .add_group_by_clause(dim)
+                .attach_printable("Error grouping by dimensions")
+                .switch()?;
+        }
+
+        query_builder
+            .add_group_by_clause("currency")
+            .attach_printable("Error grouping by currency")
+            .switch()?;
+
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
+                .attach_printable("Error adding granularity")
+                .switch()?;
+        }
+
+        query_builder
+            .add_filter_clause(
+                PaymentDimensions::PaymentStatus,
+                storage_enums::AttemptStatus::Charged,
+            )
+            .switch()?;
+
+        query_builder
+            .execute_query::<PaymentMetricRow, _>(pool)
+            .await
+            .change_context(MetricsError::QueryBuildingError)?
+            .change_context(MetricsError::QueryExecutionFailure)?
+            .into_iter()
+            .map(|i| {
+                Ok((
+                    PaymentMetricsBucketIdentifier::new(
+                        i.currency.as_ref().map(|i| i.0),
+                        None,
+                        i.connector.clone(),
+                        i.authentication_type.as_ref().map(|i| i.0),
+                        i.payment_method.clone(),
+                        i.payment_method_type.clone(),
+                        i.client_source.clone(),
+                        i.client_version.clone(),
+                        i.profile_id.clone(),
+                        i.card_network.clone(),
+                        i.merchant_id.clone(),
+                        i.card_last_4.clone(),
+                        i.card_issuer.clone(),
+                        i.error_reason.clone(),
+                        i.routing_approach.as_ref().map(|i| i.0),
+                        TimeRange {
+                            start_time: match (granularity, i.start_bucket) {
+                                (Some(g), Some(st)) => g.clip_to_start(st)?,
+                                _ => time_range.start_time,
+                            },
+                            end_time: granularity.as_ref().map_or_else(
+                                || Ok(time_range.end_time),
+                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
+                            )?,
+                        },
+                    ),
+                    i,
+                ))
+            })
+            .collect::<error_stack::Result<
+                HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
+                crate::query::PostProcessingError,
+            >>()
+            .change_context(MetricsError::PostProcessingFailure)
+    }
+}
diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics.rs b/crates/analytics/src/payments/metrics/sessionized_metrics.rs
index e3a5e370534..9d10c9db008 100644
--- a/crates/analytics/src/payments/metrics/sessionized_metrics.rs
+++ b/crates/analytics/src/payments/metrics/sessionized_metrics.rs
@@ -1,5 +1,6 @@
 mod avg_ticket_size;
 mod connector_success_rate;
+mod debit_routing;
 mod failure_reasons;
 mod payment_count;
 mod payment_processed_amount;
@@ -9,6 +10,7 @@ mod retries_count;
 mod success_rate;
 pub(super) use avg_ticket_size::AvgTicketSize;
 pub(super) use connector_success_rate::ConnectorSuccessRate;
+pub(super) use debit_routing::DebitRouting;
 pub(super) use failure_reasons::FailureReasons;
 pub(super) use payment_count::PaymentCount;
 pub(super) use payment_processed_amount::PaymentProcessedAmount;
diff --git a/crates/analytics/src/payments/metrics/sessionized_metrics/debit_routing.rs b/crates/analytics/src/payments/metrics/sessionized_metrics/debit_routing.rs
new file mode 100644
index 00000000000..f7c84e1b65c
--- /dev/null
+++ b/crates/analytics/src/payments/metrics/sessionized_metrics/debit_routing.rs
@@ -0,0 +1,152 @@
+use std::collections::HashSet;
+
+use api_models::analytics::{
+    payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
+    Granularity, TimeRange,
+};
+use common_utils::errors::ReportSwitchExt;
+use diesel_models::enums as storage_enums;
+use error_stack::ResultExt;
+use time::PrimitiveDateTime;
+
+use super::PaymentMetricRow;
+use crate::{
+    enums::AuthInfo,
+    query::{Aggregate, GroupByClause, QueryBuilder, QueryFilter, SeriesBucket, ToSql, Window},
+    types::{AnalyticsCollection, AnalyticsDataSource, MetricsError, MetricsResult},
+};
+
+#[derive(Default)]
+pub(crate) struct DebitRouting;
+
+#[async_trait::async_trait]
+impl<T> super::PaymentMetric<T> for DebitRouting
+where
+    T: AnalyticsDataSource + super::PaymentMetricAnalytics,
+    PrimitiveDateTime: ToSql<T>,
+    AnalyticsCollection: ToSql<T>,
+    Granularity: GroupByClause<T>,
+    Aggregate<&'static str>: ToSql<T>,
+    Window<&'static str>: ToSql<T>,
+{
+    async fn load_metrics(
+        &self,
+        dimensions: &[PaymentDimensions],
+        auth: &AuthInfo,
+        filters: &PaymentFilters,
+        granularity: Option<Granularity>,
+        time_range: &TimeRange,
+        pool: &T,
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+        let mut query_builder: QueryBuilder<T> =
+            QueryBuilder::new(AnalyticsCollection::PaymentSessionized);
+
+        for dim in dimensions.iter() {
+            query_builder.add_select_column(dim).switch()?;
+        }
+        query_builder
+            .add_select_column(Aggregate::Count {
+                field: None,
+                alias: Some("count"),
+            })
+            .switch()?;
+        query_builder
+            .add_select_column(Aggregate::Sum {
+                field: "debit_routing_savings",
+                alias: Some("total"),
+            })
+            .switch()?;
+        query_builder.add_select_column("currency").switch()?;
+        query_builder
+            .add_select_column(Aggregate::Min {
+                field: "created_at",
+                alias: Some("start_bucket"),
+            })
+            .switch()?;
+        query_builder
+            .add_select_column(Aggregate::Max {
+                field: "created_at",
+                alias: Some("end_bucket"),
+            })
+            .switch()?;
+
+        filters.set_filter_clause(&mut query_builder).switch()?;
+
+        auth.set_filter_clause(&mut query_builder).switch()?;
+
+        time_range
+            .set_filter_clause(&mut query_builder)
+            .attach_printable("Error filtering time range")
+            .switch()?;
+
+        for dim in dimensions.iter() {
+            query_builder
+                .add_group_by_clause(dim)
+                .attach_printable("Error grouping by dimensions")
+                .switch()?;
+        }
+
+        query_builder
+            .add_group_by_clause("currency")
+            .attach_printable("Error grouping by currency")
+            .switch()?;
+
+        if let Some(granularity) = granularity {
+            granularity
+                .set_group_by_clause(&mut query_builder)
+                .attach_printable("Error adding granularity")
+                .switch()?;
+        }
+
+        query_builder
+            .add_filter_clause(
+                PaymentDimensions::PaymentStatus,
+                storage_enums::AttemptStatus::Charged,
+            )
+            .switch()?;
+
+        query_builder
+            .execute_query::<PaymentMetricRow, _>(pool)
+            .await
+            .change_context(MetricsError::QueryBuildingError)?
+            .change_context(MetricsError::QueryExecutionFailure)?
+            .into_iter()
+            .map(|i| {
+                Ok((
+                    PaymentMetricsBucketIdentifier::new(
+                        i.currency.as_ref().map(|i| i.0),
+                        None,
+                        i.connector.clone(),
+                        i.authentication_type.as_ref().map(|i| i.0),
+                        i.payment_method.clone(),
+                        i.payment_method_type.clone(),
+                        i.client_source.clone(),
+                        i.client_version.clone(),
+                        i.profile_id.clone(),
+                        i.card_network.clone(),
+                        i.merchant_id.clone(),
+                        i.card_last_4.clone(),
+                        i.card_issuer.clone(),
+                        i.error_reason.clone(),
+                        i.routing_approach.as_ref().map(|i| i.0),
+                        TimeRange {
+                            start_time: match (granularity, i.start_bucket) {
+                                (Some(g), Some(st)) => g.clip_to_start(st)?,
+                                _ => time_range.start_time,
+                            },
+                            end_time: granularity.as_ref().map_or_else(
+                                || Ok(time_range.end_time),
+                                |g| i.end_bucket.map(|et| g.clip_to_end(et)).transpose(),
+                            )?,
+                        },
+                    ),
+                    i,
+                ))
+            })
+            .collect::<error_stack::Result<
+                HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
+                crate::query::PostProcessingError,
+            >>()
+            .change_context(MetricsError::PostProcessingFailure)
+    }
+}
diff --git a/crates/api_models/src/analytics/payments.rs b/crates/api_models/src/analytics/payments.rs
index 537d6df09d1..ec5719f1adb 100644
--- a/crates/api_models/src/analytics/payments.rs
+++ b/crates/api_models/src/analytics/payments.rs
@@ -111,6 +111,7 @@ pub enum PaymentMetrics {
     AvgTicketSize,
     RetriesCount,
     ConnectorSuccessRate,
+    DebitRouting,
     SessionizedPaymentSuccessRate,
     SessionizedPaymentCount,
     SessionizedPaymentSuccessCount,
@@ -118,6 +119,7 @@ pub enum PaymentMetrics {
     SessionizedAvgTicketSize,
     SessionizedRetriesCount,
     SessionizedConnectorSuccessRate,
+    SessionizedDebitRouting,
     PaymentsDistribution,
     FailureReasons,
 }
@@ -128,8 +130,10 @@ impl ForexMetric for PaymentMetrics {
             self,
             Self::PaymentProcessedAmount
                 | Self::AvgTicketSize
+                | Self::DebitRouting
                 | Self::SessionizedPaymentProcessedAmount
                 | Self::SessionizedAvgTicketSize
+                | Self::SessionizedDebitRouting,
         )
     }
 }
@@ -309,6 +313,9 @@ pub struct PaymentMetricsBucketValue {
     pub payments_failure_rate_distribution_with_only_retries: Option<f64>,
     pub failure_reason_count: Option<u64>,
     pub failure_reason_count_without_smart_retries: Option<u64>,
+    pub debit_routed_transaction_count: Option<u64>,
+    pub debit_routing_savings: Option<u64>,
+    pub debit_routing_savings_in_usd: Option<u64>,
 }
 
 #[derive(Debug, serde::Serialize)]
diff --git a/crates/api_models/src/open_router.rs b/crates/api_models/src/open_router.rs
index ba53f4c1f00..f5b80383bfb 100644
--- a/crates/api_models/src/open_router.rs
+++ b/crates/api_models/src/open_router.rs
@@ -67,7 +67,7 @@ pub struct DecidedGateway {
 
 #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
 pub struct DebitRoutingOutput {
-    pub co_badged_card_networks_info: Vec<CoBadgedCardNetworksInfo>,
+    pub co_badged_card_networks_info: CoBadgedCardNetworks,
     pub issuer_country: common_enums::CountryAlpha2,
     pub is_regulated: bool,
     pub regulated_name: Option<common_enums::RegulatedName>,
@@ -80,19 +80,19 @@ pub struct CoBadgedCardNetworksInfo {
     pub saving_percentage: f64,
 }
 
-impl DebitRoutingOutput {
-    pub fn get_co_badged_card_networks(&self) -> Vec<common_enums::CardNetwork> {
-        self.co_badged_card_networks_info
-            .iter()
-            .map(|data| data.network.clone())
-            .collect()
+#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
+pub struct CoBadgedCardNetworks(pub Vec<CoBadgedCardNetworksInfo>);
+
+impl CoBadgedCardNetworks {
+    pub fn get_card_networks(&self) -> Vec<common_enums::CardNetwork> {
+        self.0.iter().map(|info| info.network.clone()).collect()
     }
 }
 
 impl From<&DebitRoutingOutput> for payment_methods::CoBadgedCardData {
     fn from(output: &DebitRoutingOutput) -> Self {
         Self {
-            co_badged_card_networks: output.get_co_badged_card_networks(),
+            co_badged_card_networks_info: output.co_badged_card_networks_info.clone(),
             issuer_country_code: output.issuer_country,
             is_regulated: output.is_regulated,
             regulated_name: output.regulated_name.clone(),
@@ -111,7 +111,7 @@ impl TryFrom<(payment_methods::CoBadgedCardData, String)> for DebitRoutingReques
         })?;
 
         Ok(Self {
-            co_badged_card_networks_info: output.co_badged_card_networks,
+            co_badged_card_networks_info: output.co_badged_card_networks_info.get_card_networks(),
             issuer_country: output.issuer_country_code,
             is_regulated: output.is_regulated,
             regulated_name: output.regulated_name,
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 6a8f61484dc..0745fade987 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -19,7 +19,7 @@ use utoipa::{schema, ToSchema};
 #[cfg(feature = "payouts")]
 use crate::payouts;
 use crate::{
-    admin, enums as api_enums,
+    admin, enums as api_enums, open_router,
     payments::{self, BankCodeResponse},
 };
 
@@ -937,14 +937,14 @@ pub struct PaymentMethodResponse {
     pub network_token: Option<NetworkTokenResponse>,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
 pub enum PaymentMethodsData {
     Card(CardDetailsPaymentMethod),
     BankDetails(PaymentMethodDataBankCreds),
     WalletDetails(PaymentMethodDataWalletInfo),
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
 pub struct CardDetailsPaymentMethod {
     pub last4_digits: Option<String>,
     pub issuer_country: Option<String>,
@@ -958,12 +958,33 @@ 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>,
+    pub co_badged_card_data: Option<CoBadgedCardDataToBeSaved>,
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+impl From<&CoBadgedCardData> for CoBadgedCardDataToBeSaved {
+    fn from(co_badged_card_data: &CoBadgedCardData) -> Self {
+        Self {
+            co_badged_card_networks: co_badged_card_data
+                .co_badged_card_networks_info
+                .get_card_networks(),
+            issuer_country_code: co_badged_card_data.issuer_country_code,
+            is_regulated: co_badged_card_data.is_regulated,
+            regulated_name: co_badged_card_data.regulated_name.clone(),
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
 pub struct CoBadgedCardData {
-    pub co_badged_card_networks: Vec<api_enums::CardNetwork>,
+    pub co_badged_card_networks_info: open_router::CoBadgedCardNetworks,
+    pub issuer_country_code: common_enums::CountryAlpha2,
+    pub is_regulated: bool,
+    pub regulated_name: Option<common_enums::RegulatedName>,
+}
+
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
+pub struct CoBadgedCardDataToBeSaved {
+    pub co_badged_card_networks: Vec<common_enums::CardNetwork>,
     pub issuer_country_code: common_enums::CountryAlpha2,
     pub is_regulated: bool,
     pub regulated_name: Option<common_enums::RegulatedName>,
@@ -1325,7 +1346,7 @@ impl From<(CardDetailFromLocker, Option<&CoBadgedCardData>)> for CardDetailsPaym
             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(),
+            co_badged_card_data: co_badged_card_data.map(CoBadgedCardDataToBeSaved::from),
         }
     }
 }
diff --git a/crates/hyperswitch_domain_models/src/api.rs b/crates/hyperswitch_domain_models/src/api.rs
index f6d93497627..723cc458e7b 100644
--- a/crates/hyperswitch_domain_models/src/api.rs
+++ b/crates/hyperswitch_domain_models/src/api.rs
@@ -7,7 +7,7 @@ use common_utils::{
 
 use super::payment_method_data::PaymentMethodData;
 
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Debug, PartialEq)]
 pub enum ApplicationResponse<R> {
     Json(R),
     StatusOk,
@@ -54,7 +54,7 @@ impl<T: ApiEventMetric> ApiEventMetric for ApplicationResponse<T> {
 
 impl_api_event_type!(Miscellaneous, (PaymentLinkFormData, GenericLinkFormData));
 
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Debug, PartialEq)]
 pub struct RedirectionFormData {
     pub redirect_form: crate::router_response_types::RedirectForm,
     pub payment_method_data: Option<PaymentMethodData>,
diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs
index 5433c486fbe..7a420010657 100644
--- a/crates/hyperswitch_domain_models/src/payment_method_data.rs
+++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs
@@ -24,7 +24,7 @@ use time::Date;
 
 // We need to derive Serialize and Deserialize because some parts of payment method data are being
 // stored in the database as serde_json::Value
-#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
+#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
 pub enum PaymentMethodData {
     Card(Card),
     CardDetailsForNetworkTransactionId(CardDetailsForNetworkTransactionId),
@@ -88,9 +88,21 @@ impl PaymentMethodData {
             None
         }
     }
+
+    pub fn extract_debit_routing_saving_percentage(
+        &self,
+        network: &common_enums::CardNetwork,
+    ) -> Option<f64> {
+        self.get_co_badged_card_data()?
+            .co_badged_card_networks_info
+            .0
+            .iter()
+            .find(|info| &info.network == network)
+            .map(|info| info.saving_percentage)
+    }
 }
 
-#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
+#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
 pub struct Card {
     pub card_number: cards::CardNumber,
     pub card_exp_month: Secret<String>,
@@ -120,7 +132,7 @@ pub struct CardDetailsForNetworkTransactionId {
     pub card_holder_name: Option<Secret<String>>,
 }
 
-#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
+#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
 pub struct CardDetail {
     pub card_number: cards::CardNumber,
     pub card_exp_month: Secret<String>,
@@ -1961,7 +1973,7 @@ impl From<GooglePayWalletData> for payment_methods::PaymentMethodDataWalletInfo
     }
 }
 
-#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
 pub enum PaymentMethodsData {
     Card(CardDetailsPaymentMethod),
     BankDetails(payment_methods::PaymentMethodDataBankCreds), //PaymentMethodDataBankCreds and its transformations should be moved to the domain models
@@ -2005,7 +2017,7 @@ fn saved_in_locker_default() -> bool {
 }
 
 #[cfg(feature = "v1")]
-#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)]
 pub struct CardDetailsPaymentMethod {
     pub last4_digits: Option<String>,
     pub issuer_country: Option<String>,
diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
index 2b568b70af8..3baddfa98c5 100644
--- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
+++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs
@@ -9,14 +9,12 @@ use common_types::primitive_wrappers::{
 };
 #[cfg(feature = "v2")]
 use common_utils::{
-    crypto::Encryptable,
-    encryption::Encryption,
-    ext_traits::{Encode, ValueExt},
+    crypto::Encryptable, encryption::Encryption, ext_traits::Encode,
     types::keymanager::ToEncryptable,
 };
 use common_utils::{
     errors::{CustomResult, ValidationError},
-    ext_traits::OptionExt,
+    ext_traits::{OptionExt, ValueExt},
     id_type, pii,
     types::{
         keymanager::{self, KeyManagerState},
@@ -906,6 +904,7 @@ pub struct PaymentAttempt {
     pub setup_future_usage_applied: Option<storage_enums::FutureUsage>,
     pub routing_approach: Option<storage_enums::RoutingApproach>,
     pub connector_request_reference_id: Option<String>,
+    pub debit_routing_savings: Option<MinorUnit>,
 }
 
 #[cfg(feature = "v1")]
@@ -1063,6 +1062,10 @@ impl PaymentAttempt {
     pub fn get_total_surcharge_amount(&self) -> Option<MinorUnit> {
         self.amount_details.surcharge_amount
     }
+
+    pub fn extract_card_network(&self) -> Option<common_enums::CardNetwork> {
+        todo!()
+    }
 }
 
 #[cfg(feature = "v1")]
@@ -1074,6 +1077,25 @@ impl PaymentAttempt {
     pub fn get_total_surcharge_amount(&self) -> Option<MinorUnit> {
         self.net_amount.get_total_surcharge_amount()
     }
+
+    pub fn set_debit_routing_savings(&mut self, debit_routing_savings: Option<&MinorUnit>) {
+        self.debit_routing_savings = debit_routing_savings.copied();
+    }
+
+    pub fn extract_card_network(&self) -> Option<common_enums::CardNetwork> {
+        self.payment_method_data
+            .as_ref()
+            .and_then(|value| {
+                value
+                    .clone()
+                    .parse_value::<api_models::payments::AdditionalPaymentData>(
+                        "AdditionalPaymentData",
+                    )
+                    .ok()
+            })
+            .and_then(|data| data.get_additional_card_info())
+            .and_then(|card_info| card_info.card_network)
+    }
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -1283,6 +1305,7 @@ pub enum PaymentAttemptUpdate {
         connector_mandate_detail: Option<ConnectorMandateReferenceId>,
         charges: Option<common_types::payments::ConnectorChargeResponseData>,
         setup_future_usage_applied: Option<storage_enums::FutureUsage>,
+        debit_routing_savings: Option<MinorUnit>,
     },
     UnresolvedResponseUpdate {
         status: storage_enums::AttemptStatus,
@@ -1566,6 +1589,7 @@ impl PaymentAttemptUpdate {
                 connector_mandate_detail,
                 charges,
                 setup_future_usage_applied,
+                debit_routing_savings: _,
             } => DieselPaymentAttemptUpdate::ResponseUpdate {
                 status,
                 connector,
@@ -1756,6 +1780,35 @@ impl PaymentAttemptUpdate {
             },
         }
     }
+
+    pub fn get_debit_routing_savings(&self) -> Option<&MinorUnit> {
+        match self {
+            Self::ResponseUpdate {
+                debit_routing_savings,
+                ..
+            } => debit_routing_savings.as_ref(),
+            Self::Update { .. }
+            | Self::UpdateTrackers { .. }
+            | Self::AuthenticationTypeUpdate { .. }
+            | Self::ConfirmUpdate { .. }
+            | Self::RejectUpdate { .. }
+            | Self::BlocklistUpdate { .. }
+            | Self::PaymentMethodDetailsUpdate { .. }
+            | Self::ConnectorMandateDetailUpdate { .. }
+            | Self::VoidUpdate { .. }
+            | Self::UnresolvedResponseUpdate { .. }
+            | Self::StatusUpdate { .. }
+            | Self::ErrorUpdate { .. }
+            | Self::CaptureUpdate { .. }
+            | Self::AmountToCaptureUpdate { .. }
+            | Self::PreprocessingUpdate { .. }
+            | Self::ConnectorResponse { .. }
+            | Self::IncrementalAuthorizationAmountUpdate { .. }
+            | Self::AuthenticationUpdate { .. }
+            | Self::ManualUpdate { .. }
+            | Self::PostSessionTokensUpdate { .. } => None,
+        }
+    }
 }
 
 #[cfg(feature = "v2")]
@@ -2033,6 +2086,7 @@ impl behaviour::Conversion for PaymentAttempt {
                 setup_future_usage_applied: storage_model.setup_future_usage_applied,
                 routing_approach: storage_model.routing_approach,
                 connector_request_reference_id: storage_model.connector_request_reference_id,
+                debit_routing_savings: None,
             })
         }
         .await
diff --git a/crates/router/src/core/debit_routing.rs b/crates/router/src/core/debit_routing.rs
index 4975ffc4bd1..d4f7c8bd753 100644
--- a/crates/router/src/core/debit_routing.rs
+++ b/crates/router/src/core/debit_routing.rs
@@ -281,7 +281,10 @@ where
             &profile_id,
             &key_store,
             vec![connector_data.clone()],
-            debit_routing_output.get_co_badged_card_networks(),
+            debit_routing_output
+                .co_badged_card_networks_info
+                .clone()
+                .get_card_networks(),
         )
         .await
         .map_err(|error| {
@@ -454,7 +457,10 @@ where
             &profile_id,
             &key_store,
             connector_data_list.clone(),
-            debit_routing_output.get_co_badged_card_networks(),
+            debit_routing_output
+                .co_badged_card_networks_info
+                .clone()
+                .get_card_networks(),
         )
         .await
         .map_err(|error| {
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 4b1cff09be2..e8e5b2040ed 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -865,12 +865,15 @@ fn get_card_network_with_us_local_debit_network_override(
         .map(|network| network.is_us_local_network())
     {
         services::logger::debug!("Card network is a US local network, checking for global network in co-badged card data");
-        co_badged_card_data.and_then(|data| {
-            data.co_badged_card_networks
-                .iter()
-                .find(|network| network.is_global_network())
-                .cloned()
-        })
+        let info: Option<api_models::open_router::CoBadgedCardNetworksInfo> = co_badged_card_data
+            .and_then(|data| {
+                data.co_badged_card_networks_info
+                    .0
+                    .iter()
+                    .find(|info| info.network.is_global_network())
+                    .cloned()
+            });
+        info.map(|data| data.network)
     } else {
         card_network
     }
diff --git a/crates/router/src/core/payment_methods/tokenize.rs b/crates/router/src/core/payment_methods/tokenize.rs
index 3556673510c..f0eaea45d98 100644
--- a/crates/router/src/core/payment_methods/tokenize.rs
+++ b/crates/router/src/core/payment_methods/tokenize.rs
@@ -272,8 +272,12 @@ 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(),
+            co_badged_card_data: card_details
+                .co_badged_card_data
+                .as_ref()
+                .map(|data| data.into()),
         });
+
         create_encrypted_data(&self.state.into(), self.key_store, pm_data)
             .await
             .inspect_err(|err| logger::info!("Error encrypting payment method data: {:?}", err))
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index b12704aab1f..1d5e2a7b4af 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -471,7 +471,7 @@ where
 
     // To perform router related operation for PaymentResponse
     PaymentResponse: Operation<F, FData, Data = D>,
-    FData: Send + Sync + Clone,
+    FData: Send + Sync + Clone + router_types::Capturable,
 {
     let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation);
 
@@ -1844,7 +1844,7 @@ pub async fn payments_core<F, Res, Req, Op, FData, D>(
 ) -> RouterResponse<Res>
 where
     F: Send + Clone + Sync,
-    FData: Send + Sync + Clone,
+    FData: Send + Sync + Clone + router_types::Capturable,
     Op: Operation<F, Req, Data = D> + Send + Sync + Clone,
     Req: Debug + Authenticate + Clone,
     D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index d855ca84e18..9065dcd2ce3 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -44,6 +44,7 @@ use hyperswitch_domain_models::{
 use hyperswitch_interfaces::integrity::{CheckIntegrity, FlowIntegrity, GetIntegrityObject};
 use josekit::jwe;
 use masking::{ExposeInterface, PeekInterface, SwitchStrategy};
+use num_traits::{FromPrimitive, ToPrimitive};
 use openssl::{
     derive::Deriver,
     pkey::PKey,
@@ -52,6 +53,7 @@ use openssl::{
 #[cfg(feature = "v2")]
 use redis_interface::errors::RedisError;
 use router_env::{instrument, logger, tracing};
+use rust_decimal::Decimal;
 use serde::{Deserialize, Serialize};
 use uuid::Uuid;
 use x509_parser::parse_x509_certificate;
@@ -5208,6 +5210,54 @@ pub fn get_applepay_metadata(
         })
 }
 
+pub fn calculate_debit_routing_savings(net_amount: i64, saving_percentage: f64) -> MinorUnit {
+    logger::debug!(
+        ?net_amount,
+        ?saving_percentage,
+        "Calculating debit routing saving amount"
+    );
+
+    let net_decimal = Decimal::from_i64(net_amount).unwrap_or_else(|| {
+        logger::warn!(?net_amount, "Invalid net_amount, using 0");
+        Decimal::ZERO
+    });
+
+    let percentage_decimal = Decimal::from_f64(saving_percentage).unwrap_or_else(|| {
+        logger::warn!(?saving_percentage, "Invalid saving_percentage, using 0");
+        Decimal::ZERO
+    });
+
+    let savings_decimal = net_decimal * percentage_decimal / Decimal::from(100);
+    let rounded_savings = savings_decimal.round();
+
+    let savings_int = rounded_savings.to_i64().unwrap_or_else(|| {
+        logger::warn!(
+            ?rounded_savings,
+            "Debit routing savings calculation overflowed when converting to i64"
+        );
+        0
+    });
+
+    MinorUnit::new(savings_int)
+}
+
+pub fn get_debit_routing_savings_amount(
+    payment_method_data: &domain::PaymentMethodData,
+    payment_attempt: &PaymentAttempt,
+) -> Option<MinorUnit> {
+    let card_network = payment_attempt.extract_card_network()?;
+
+    let saving_percentage =
+        payment_method_data.extract_debit_routing_saving_percentage(&card_network)?;
+
+    let net_amount = payment_attempt.get_total_amount().get_amount_as_i64();
+
+    Some(calculate_debit_routing_savings(
+        net_amount,
+        saving_percentage,
+    ))
+}
+
 #[cfg(all(feature = "retry", feature = "v1"))]
 pub async fn get_apple_pay_retryable_connectors<F, D>(
     state: &SessionState,
diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs
index 939679ef51f..e72555b2ede 100644
--- a/crates/router/src/core/payments/operations/payment_response.rs
+++ b/crates/router/src/core/payments/operations/payment_response.rs
@@ -1767,6 +1767,14 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
                             let payment_method_id =
                                 payment_data.payment_attempt.payment_method_id.clone();
 
+                            let debit_routing_savings =
+                                payment_data.payment_method_data.as_ref().and_then(|data| {
+                                    payments_helpers::get_debit_routing_savings_amount(
+                                        data,
+                                        &payment_data.payment_attempt,
+                                    )
+                                });
+
                             utils::add_apple_pay_payment_status_metrics(
                                 router_data.status,
                                 router_data.apple_pay_flow.clone(),
@@ -1857,6 +1865,7 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
                                         setup_future_usage_applied: payment_data
                                             .payment_attempt
                                             .setup_future_usage_applied,
+                                        debit_routing_savings,
                                     }),
                                 ),
                             };
diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs
index 728396ef530..f7d8b3e888b 100644
--- a/crates/router/src/core/payments/retry.rs
+++ b/crates/router/src/core/payments/retry.rs
@@ -48,7 +48,7 @@ pub async fn do_gsm_actions<F, ApiRequest, FData, D>(
 ) -> RouterResult<types::RouterData<F, FData, types::PaymentsResponseData>>
 where
     F: Clone + Send + Sync,
-    FData: Send + Sync,
+    FData: Send + Sync + types::Capturable,
     payments::PaymentResponse: operations::Operation<F, FData>,
     D: payments::OperationSessionGetters<F>
         + payments::OperationSessionSetters<F>
@@ -345,7 +345,7 @@ pub async fn do_retry<F, ApiRequest, FData, D>(
 ) -> RouterResult<types::RouterData<F, FData, types::PaymentsResponseData>>
 where
     F: Clone + Send + Sync,
-    FData: Send + Sync,
+    FData: Send + Sync + types::Capturable,
     payments::PaymentResponse: operations::Operation<F, FData>,
     D: payments::OperationSessionGetters<F>
         + payments::OperationSessionSetters<F>
@@ -425,7 +425,7 @@ pub async fn modify_trackers<F, FData, D>(
 ) -> RouterResult<()>
 where
     F: Clone + Send,
-    FData: Send,
+    FData: Send + types::Capturable,
     D: payments::OperationSessionGetters<F> + payments::OperationSessionSetters<F> + Send + Sync,
 {
     let new_attempt_count = payment_data.get_payment_intent().attempt_count + 1;
@@ -451,6 +451,13 @@ where
                 .and_then(|connector_response| connector_response.additional_payment_method_data),
         )?;
 
+    let debit_routing_savings = payment_data.get_payment_method_data().and_then(|data| {
+        payments::helpers::get_debit_routing_savings_amount(
+            data,
+            payment_data.get_payment_attempt(),
+        )
+    });
+
     match router_data.response {
         Ok(types::PaymentsResponseData::TransactionResponse {
             resource_id,
@@ -506,6 +513,7 @@ where
                 connector_mandate_detail: None,
                 charges,
                 setup_future_usage_applied: None,
+                debit_routing_savings,
             };
 
             #[cfg(feature = "v1")]
diff --git a/crates/router/src/core/routing/transformers.rs b/crates/router/src/core/routing/transformers.rs
index 6560e6786c8..b13dee1bcb4 100644
--- a/crates/router/src/core/routing/transformers.rs
+++ b/crates/router/src/core/routing/transformers.rs
@@ -180,7 +180,7 @@ impl OpenRouterDecideGatewayRequestExt for OpenRouterDecideGatewayRequest {
         Self {
             payment_info: PaymentInfo {
                 payment_id: attempt.payment_id.clone(),
-                amount: attempt.net_amount.get_order_amount(),
+                amount: attempt.net_amount.get_total_amount(),
                 currency: attempt.currency.unwrap_or(storage_enums::Currency::USD),
                 payment_type: "ORDER_PAYMENT".to_string(),
                 card_isin: card_isin.map(|value| value.peek().clone()),
diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs
index 7f24d2f5c99..68af56f2262 100644
--- a/crates/router/src/db/kafka_store.rs
+++ b/crates/router/src/db/kafka_store.rs
@@ -1520,11 +1520,18 @@ impl PaymentAttemptInterface for KafkaStore {
         payment_attempt: storage::PaymentAttemptUpdate,
         storage_scheme: MerchantStorageScheme,
     ) -> CustomResult<storage::PaymentAttempt, errors::StorageError> {
-        let attempt = self
+        let mut attempt = self
             .diesel_store
-            .update_payment_attempt_with_attempt_id(this.clone(), payment_attempt, storage_scheme)
+            .update_payment_attempt_with_attempt_id(
+                this.clone(),
+                payment_attempt.clone(),
+                storage_scheme,
+            )
             .await?;
 
+        let debit_routing_savings = payment_attempt.get_debit_routing_savings();
+
+        attempt.set_debit_routing_savings(debit_routing_savings);
         if let Err(er) = self
             .kafka_producer
             .log_payment_attempt(&attempt, Some(this), self.tenant_id.clone())
diff --git a/crates/router/src/services/kafka/payment_attempt.rs b/crates/router/src/services/kafka/payment_attempt.rs
index f51e5a12d29..e0dbc6ad213 100644
--- a/crates/router/src/services/kafka/payment_attempt.rs
+++ b/crates/router/src/services/kafka/payment_attempt.rs
@@ -70,6 +70,7 @@ pub struct KafkaPaymentAttempt<'a> {
     pub card_network: Option<String>,
     pub card_discovery: Option<String>,
     pub routing_approach: Option<storage_enums::RoutingApproach>,
+    pub debit_routing_savings: Option<MinorUnit>,
 }
 
 #[cfg(feature = "v1")]
@@ -132,6 +133,7 @@ impl<'a> KafkaPaymentAttempt<'a> {
                 .card_discovery
                 .map(|discovery| discovery.to_string()),
             routing_approach: attempt.routing_approach,
+            debit_routing_savings: attempt.debit_routing_savings,
         }
     }
 }
diff --git a/crates/router/src/services/kafka/payment_attempt_event.rs b/crates/router/src/services/kafka/payment_attempt_event.rs
index e2a88e2c29d..a54ff3cc28a 100644
--- a/crates/router/src/services/kafka/payment_attempt_event.rs
+++ b/crates/router/src/services/kafka/payment_attempt_event.rs
@@ -71,6 +71,7 @@ pub struct KafkaPaymentAttemptEvent<'a> {
     pub card_network: Option<String>,
     pub card_discovery: Option<String>,
     pub routing_approach: Option<storage_enums::RoutingApproach>,
+    pub debit_routing_savings: Option<MinorUnit>,
 }
 
 #[cfg(feature = "v1")]
@@ -133,6 +134,7 @@ impl<'a> KafkaPaymentAttemptEvent<'a> {
                 .card_discovery
                 .map(|discovery| discovery.to_string()),
             routing_approach: attempt.routing_approach,
+            debit_routing_savings: attempt.debit_routing_savings,
         }
     }
 }
diff --git a/crates/storage_impl/src/mock_db/payment_attempt.rs b/crates/storage_impl/src/mock_db/payment_attempt.rs
index 88ddc824b2f..ec27f9bed65 100644
--- a/crates/storage_impl/src/mock_db/payment_attempt.rs
+++ b/crates/storage_impl/src/mock_db/payment_attempt.rs
@@ -237,6 +237,7 @@ impl PaymentAttemptInterface for MockDb {
             setup_future_usage_applied: payment_attempt.setup_future_usage_applied,
             routing_approach: payment_attempt.routing_approach,
             connector_request_reference_id: payment_attempt.connector_request_reference_id,
+            debit_routing_savings: None,
         };
         payment_attempts.push(payment_attempt.clone());
         Ok(payment_attempt)
diff --git a/crates/storage_impl/src/payments/payment_attempt.rs b/crates/storage_impl/src/payments/payment_attempt.rs
index 2c69c0766ba..b3fccea353e 100644
--- a/crates/storage_impl/src/payments/payment_attempt.rs
+++ b/crates/storage_impl/src/payments/payment_attempt.rs
@@ -689,6 +689,7 @@ impl<T: DatabaseStore> PaymentAttemptInterface for KVRouterStore<T> {
                     connector_request_reference_id: payment_attempt
                         .connector_request_reference_id
                         .clone(),
+                    debit_routing_savings: None,
                 };
 
                 let field = format!("pa_{}", created_attempt.attempt_id);
@@ -1989,6 +1990,7 @@ impl DataModelExt for PaymentAttempt {
             setup_future_usage_applied: storage_model.setup_future_usage_applied,
             routing_approach: storage_model.routing_approach,
             connector_request_reference_id: storage_model.connector_request_reference_id,
+            debit_routing_savings: None,
         }
     }
 }

<!-- 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 -->
This pull request introduces a new feature to track and analyze debit routing savings and integrates it across multiple components of the analytics system. It also refactors the handling of co-badged card networks to provide additional details, such as saving percentages. Below is a breakdown of the most important changes grouped by theme:

### Debit Routing Analytics Integration:
* Added a new column `debit_routing_savings` to the `payment_attempt_queue`, `payment_attempts`, and `payment_attempt_mv` tables in ClickHouse for tracking debit routing savings. 
* Updated the `PaymentMetricsAccumulator` struct to include a new `DebitRoutingAccumulator`, which tracks transaction counts and savings amounts. Implemented the necessary methods for metric collection and aggregation.
* Introduced a new `PaymentMetrics::DebitRouting` enum variant and its corresponding implementation to load metrics, process data, and convert savings to USD.


### Additional Changes

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

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

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


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

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


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
-> Enable debit routing for a profile
-> Configure adyen connector with local debit networks enabled
-> Make some debit routing payments
```
{
    "amount": 1,
    "amount_to_capture": 1,
    "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_{{$timestamp}}",
    "return_url": "http://127.0.0.1:4040",
    "payment_method": "card",
    "payment_method_type": "debit",
    "payment_method_data": {
        "card": {
            "card_number": "4000 0330 0330 0335",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "card_cvc": "737"
        }
    },
    "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"
        }
    },
    "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
    "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_xrXjk0rlKJG83LNngQ2B",
    "merchant_id": "merchant_1751293949",
    "status": "succeeded",
    "amount": 150000,
    "net_amount": 150000,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 150000,
    "connector": "adyen",
    "client_secret": "pay_xrXjk0rlKJG83LNngQ2B_secret_doz5GI9CEnlmcQoBpiNT",
    "created": "2025-06-30T15:09:44.649Z",
    "currency": "USD",
    "customer_id": "cu_1751296185",
    "customer": {
        "id": "cu_1751296185",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "attempts": [
        {
            "attempt_id": "pay_xrXjk0rlKJG83LNngQ2B_1",
            "status": "charged",
            "amount": 150000,
            "order_tax_amount": null,
            "currency": "USD",
            "connector": "adyen",
            "error_message": null,
            "payment_method": "card",
            "connector_transaction_id": "KGRXNH7KQZ9TPM75",
            "capture_method": "automatic",
            "authentication_type": "no_three_ds",
            "created_at": "2025-06-30T15:09:44.649Z",
            "modified_at": "2025-06-30T15:09:45.587Z",
            "cancellation_reason": null,
            "mandate_id": null,
            "error_code": null,
            "payment_token": null,
            "connector_metadata": null,
            "payment_experience": null,
            "payment_method_type": "debit",
            "reference_id": "pay_xrXjk0rlKJG83LNngQ2B_1",
            "unified_code": null,
            "unified_message": null,
            "client_source": null,
            "client_version": 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": "0335",
            "card_type": null,
            "card_network": "Nyce",
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "400003",
            "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": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "KGRXNH7KQZ9TPM75",
    "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_xrXjk0rlKJG83LNngQ2B_1",
    "payment_link": null,
    "profile_id": "pro_0YmTwtjkst9iUDkg4R5D",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_d1x2St1F4pbgEFYNmxOV",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-06-30T15:24:44.649Z",
    "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": "pm_pRJ3v7spaJ1pfIsMlAqD",
    "payment_method_status": "active",
    "updated": "2025-06-30T15:09:45.566Z",
    "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,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}
```
-> Payment FIlters
```
curl --location 'http://localhost:8080/analytics/v1/org/filters/payments' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'api-key: hyperswitch' \
--header 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZTAxZDlhMzgtMDdlMi00ZmFiLTg3ZmYtZWU0NmE2YTU2MDlhIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzUxMjkzOTQ5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc1MTQ2Njc1MSwib3JnX2lkIjoib3JnX2tOa2k3aXBKS1h4NFc3bGVJU3FQIiwicHJvZmlsZV9pZCI6InByb18wWW1Ud3Rqa3N0OWlVRGtnNFI1RCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.jty5ccBH_Em-odSAlde-FQLMC34aoGdV_UYsJFoUN-w' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--data '{
    "timeRange": {
        "startTime": "2024-09-03T18:30:00.000Z",
        "endTime": "2025-09-12T09:22:30.000Z"
    },
    "groupByNames": [
        "connector",
        "payment_method",
        "payment_method_type",
        "currency",
        "authentication_type",
        "status",
        "client_source",
        "client_version",
        "profile_id",
        "routing_approach"
    ],
    "source": "BATCH",
    "delta": true
}'
```
```
{
    "queryData": [
        {
            "dimension": "connector",
            "values": [
                "adyen"
            ]
        },
        {
            "dimension": "payment_method",
            "values": [
                "card"
            ]
        },
        {
            "dimension": "payment_method_type",
            "values": [
                "debit"
            ]
        },
        {
            "dimension": "currency",
            "values": [
                "USD"
            ]
        },
        {
            "dimension": "authentication_type",
            "values": [
                "no_three_ds"
            ]
        },
        {
            "dimension": "status",
            "values": [
                "charged"
            ]
        },
        {
            "dimension": "client_source",
            "values": []
        },
        {
            "dimension": "client_version",
            "values": []
        },
        {
            "dimension": "profile_id",
            "values": [
                "pro_0YmTwtjkst9iUDkg4R5D"
            ]
        },
        {
            "dimension": "routing_approach",
            "values": [
                "default_fallback",
                "debit_routing"
            ]
        }
    ]
}
```
-> Payment metric that gives total debit routed txn and savings
```
curl --location 'http://localhost:8080/analytics/v1/org/metrics/payments' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--header 'api-key: dev_cW7LmHwdGurYUqCHLMkUX8AfU9uYzKJc6sT0bsAB1wQJFe6lOP01lRO30Dj0WpcH' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZTAxZDlhMzgtMDdlMi00ZmFiLTg3ZmYtZWU0NmE2YTU2MDlhIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzUxMjkzOTQ5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc1MTQ2Njc1MSwib3JnX2lkIjoib3JnX2tOa2k3aXBKS1h4NFc3bGVJU3FQIiwicHJvZmlsZV9pZCI6InByb18wWW1Ud3Rqa3N0OWlVRGtnNFI1RCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.jty5ccBH_Em-odSAlde-FQLMC34aoGdV_UYsJFoUN-w' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-03-01T18:30:00Z",
            "endTime": "2025-07-31T09:22:00Z"
        },
        
        
        
        
        
        "filters": {
          "routing_approach": [
            "debit_routing"
          ]
        },
        "source": "BATCH",
        "metrics": [
            "debit_routing"
        ],
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "delta": true
    }
]'
```
```
{
    "queryData": [
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 8,
            "debit_routing_savings": 369,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": null,
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        }
    ],
    "metaData": [
        {
            "total_payment_processed_amount": 0,
            "total_payment_processed_amount_in_usd": null,
            "total_payment_processed_amount_without_smart_retries": 0,
            "total_payment_processed_amount_without_smart_retries_usd": null,
            "total_payment_processed_count": 0,
            "total_payment_processed_count_without_smart_retries": 0,
            "total_failure_reasons_count": 0,
            "total_failure_reasons_count_without_smart_retries": 0
        }
    ]
}
```
-> Payment metrics that gives savings per txn
```
curl --location 'http://localhost:8080/analytics/v1/org/metrics/payments' \
--header 'Accept: */*' \
--header 'Accept-Language: en-US,en;q=0.9' \
--header 'Connection: keep-alive' \
--header 'Content-Type: application/json' \
--header 'Origin: http://localhost:9000' \
--header 'Referer: http://localhost:9000/' \
--header 'Sec-Fetch-Dest: empty' \
--header 'Sec-Fetch-Mode: cors' \
--header 'Sec-Fetch-Site: same-site' \
--header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' \
--header 'sec-ch-ua: "Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"' \
--header 'sec-ch-ua-mobile: ?0' \
--header 'sec-ch-ua-platform: "macOS"' \
--header 'api-key: dev_cW7LmHwdGurYUqCHLMkUX8AfU9uYzKJc6sT0bsAB1wQJFe6lOP01lRO30Dj0WpcH' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZTAxZDlhMzgtMDdlMi00ZmFiLTg3ZmYtZWU0NmE2YTU2MDlhIiwibWVyY2hhbnRfaWQiOiJtZXJjaGFudF8xNzUxMjkzOTQ5Iiwicm9sZV9pZCI6Im9yZ19hZG1pbiIsImV4cCI6MTc1MTQ2Njc1MSwib3JnX2lkIjoib3JnX2tOa2k3aXBKS1h4NFc3bGVJU3FQIiwicHJvZmlsZV9pZCI6InByb18wWW1Ud3Rqa3N0OWlVRGtnNFI1RCIsInRlbmFudF9pZCI6InB1YmxpYyJ9.jty5ccBH_Em-odSAlde-FQLMC34aoGdV_UYsJFoUN-w' \
--data '[
    {
        "timeRange": {
            "startTime": "2025-03-01T18:30:00Z",
            "endTime": "2025-07-31T09:22:00Z"
        },
        "groupByNames": [
            "card_network"
        ],
        
        
        "filters": {
          "routing_approach": [
            "debit_routing"
          ]
        },
        "source": "BATCH",
        "metrics": [
            "debit_routing"
        ],
        "timeSeries": {
            "granularity": "G_ONEDAY"
        },
        "delta": true
    }
]'
```
```
{
    "queryData": [
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 2,
            "debit_routing_savings": 107,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": "Star",
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        },
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 2,
            "debit_routing_savings": 199,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": "Nyce",
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        },
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 3,
            "debit_routing_savings": 0,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": "Visa",
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        },
        {
            "payment_success_rate": null,
            "payment_count": null,
            "payment_success_count": null,
            "payment_processed_amount": 0,
            "payment_processed_amount_in_usd": null,
            "payment_processed_count": null,
            "payment_processed_amount_without_smart_retries": 0,
            "payment_processed_amount_without_smart_retries_usd": null,
            "payment_processed_count_without_smart_retries": null,
            "avg_ticket_size": null,
            "payment_error_message": null,
            "retries_count": null,
            "retries_amount_processed": 0,
            "connector_success_rate": null,
            "payments_success_rate_distribution": null,
            "payments_success_rate_distribution_without_smart_retries": null,
            "payments_success_rate_distribution_with_only_retries": null,
            "payments_failure_rate_distribution": null,
            "payments_failure_rate_distribution_without_smart_retries": null,
            "payments_failure_rate_distribution_with_only_retries": null,
            "failure_reason_count": 0,
            "failure_reason_count_without_smart_retries": 0,
            "debit_routed_transaction_count": 1,
            "debit_routing_savings": 63,
            "debit_routing_savings_in_usd": null,
            "currency": "USD",
            "status": null,
            "connector": null,
            "authentication_type": null,
            "payment_method": null,
            "payment_method_type": null,
            "client_source": null,
            "client_version": null,
            "profile_id": null,
            "card_network": "Accel",
            "merchant_id": null,
            "card_last_4": null,
            "card_issuer": null,
            "error_reason": null,
            "routing_approach": null,
            "time_range": {
                "start_time": "2025-06-30T00:00:00.000Z",
                "end_time": "2025-06-30T23:00:00.000Z"
            },
            "time_bucket": "2025-06-30 00:00:00"
        }
    ],
    "metaData": [
        {
            "total_payment_processed_amount": 0,
            "total_payment_processed_amount_in_usd": null,
            "total_payment_processed_amount_without_smart_retries": 0,
            "total_payment_processed_amount_without_smart_retries_usd": null,
            "total_payment_processed_count": 0,
            "total_payment_processed_count_without_smart_retries": 0,
            "total_failure_reasons_count": 0,
            "total_failure_reasons_count_without_smart_retries": 0
        }
    ]
}
```

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