Bug: [FEATURE] Add support for profile-specific default routing fallback 



### Feature Description

Currently every merchant has a default fallback which is a list of all of their configured connectors. We now want to make this profile-specific, i.e. each profile will have an associated default fallback that is a list of all the connectors associated with that profile.

This issue also entails development of Read/Write APIs for profile specific default fallbacks, and integration with the payments core. 

Further on , we can also later on add the `mca_id` as many connectors with the same name can be there under a single `profile_id`


### Possible Implementation

In interest of backwards compatibility, create two separate default fallback APIs for profiles (Read & Write). Additionally, implement profile-specific fallback usage in payments core routing with a feature flag. 

### Have you spent some time checking if this feature request has been raised before?

- [X] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

No, but I'm happy to collaborate on a PR with someone else
diff --git a/crates/api_models/src/events/routing.rs b/crates/api_models/src/events/routing.rs
index 5eca01acc6f..a09735bc572 100644
--- a/crates/api_models/src/events/routing.rs
+++ b/crates/api_models/src/events/routing.rs
@@ -1,8 +1,9 @@
 use common_utils::events::{ApiEventMetric, ApiEventsType};
 
 use crate::routing::{
-    LinkedRoutingConfigRetrieveResponse, MerchantRoutingAlgorithm, RoutingAlgorithmId,
-    RoutingConfigRequest, RoutingDictionaryRecord, RoutingKind,
+    LinkedRoutingConfigRetrieveResponse, MerchantRoutingAlgorithm, ProfileDefaultRoutingConfig,
+    RoutingAlgorithmId, RoutingConfigRequest, RoutingDictionaryRecord, RoutingKind,
+    RoutingPayloadWrapper,
 };
 #[cfg(feature = "business_profile_routing")]
 use crate::routing::{RoutingRetrieveLinkQuery, RoutingRetrieveQuery};
@@ -37,6 +38,17 @@ impl ApiEventMetric for LinkedRoutingConfigRetrieveResponse {
     }
 }
 
+impl ApiEventMetric for RoutingPayloadWrapper {
+    fn get_api_event_type(&self) -> Option<ApiEventsType> {
+        Some(ApiEventsType::Routing)
+    }
+}
+impl ApiEventMetric for ProfileDefaultRoutingConfig {
+    fn get_api_event_type(&self) -> Option<ApiEventsType> {
+        Some(ApiEventsType::Routing)
+    }
+}
+
 #[cfg(feature = "business_profile_routing")]
 impl ApiEventMetric for RoutingRetrieveQuery {
     fn get_api_event_type(&self) -> Option<ApiEventsType> {
diff --git a/crates/api_models/src/routing.rs b/crates/api_models/src/routing.rs
index 425ca364191..363df5389a7 100644
--- a/crates/api_models/src/routing.rs
+++ b/crates/api_models/src/routing.rs
@@ -40,6 +40,12 @@ pub struct RoutingConfigRequest {
     pub profile_id: Option<String>,
 }
 
+#[derive(Debug, serde::Serialize)]
+pub struct ProfileDefaultRoutingConfig {
+    pub profile_id: String,
+    pub connectors: Vec<RoutableConnectorChoice>,
+}
+
 #[cfg(feature = "business_profile_routing")]
 #[derive(Debug, serde::Deserialize, serde::Serialize)]
 pub struct RoutingRetrieveQuery {
@@ -389,6 +395,13 @@ pub enum RoutingAlgorithmKind {
     Advanced,
 }
 
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+
+pub struct RoutingPayloadWrapper {
+    pub updated_config: Vec<RoutableConnectorChoice>,
+    pub profile_id: String,
+}
+
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 #[serde(
     tag = "type",
diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml
index d765a5b5c5e..8f6906e0685 100644
--- a/crates/router/Cargo.toml
+++ b/crates/router/Cargo.toml
@@ -9,13 +9,13 @@ readme = "README.md"
 license.workspace = true
 
 [features]
-default = ["kv_store", "stripe", "oltp", "olap", "backwards_compatibility", "accounts_cache", "dummy_connector", "payouts"]
+default = ["kv_store", "stripe", "oltp", "olap", "backwards_compatibility", "accounts_cache", "dummy_connector", "payouts", "profile_specific_fallback_routing"]
 s3 = ["dep:aws-sdk-s3", "dep:aws-config"]
 kms = ["external_services/kms", "dep:aws-config"]
 email = ["external_services/email", "dep:aws-config"]
 basilisk = ["kms"]
 stripe = ["dep:serde_qs"]
-release = ["kms", "stripe", "basilisk", "s3", "email", "business_profile_routing", "accounts_cache", "kv_store", "olap"]
+release = ["kms", "stripe", "basilisk", "s3", "email", "business_profile_routing", "accounts_cache", "kv_store", "profile_specific_fallback_routing"]
 olap = ["data_models/olap", "storage_impl/olap", "scheduler/olap"]
 oltp = ["data_models/oltp", "storage_impl/oltp"]
 kv_store = ["scheduler/kv_store"]
@@ -24,6 +24,7 @@ openapi = ["olap", "oltp", "payouts"]
 vergen = ["router_env/vergen"]
 backwards_compatibility = ["api_models/backwards_compatibility", "euclid/backwards_compatibility", "kgraph_utils/backwards_compatibility"]
 business_profile_routing=["api_models/business_profile_routing"]
+profile_specific_fallback_routing = []
 dummy_connector = ["api_models/dummy_connector", "euclid/dummy_connector", "kgraph_utils/dummy_connector"]
 connector_choice_mca_id = ["api_models/connector_choice_mca_id", "euclid/connector_choice_mca_id", "kgraph_utils/connector_choice_mca_id"]
 external_access_dc = ["dummy_connector"]
diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs
index e1e5ea744e2..5ccd9e96486 100644
--- a/crates/router/src/core/admin.rs
+++ b/crates/router/src/core/admin.rs
@@ -916,13 +916,16 @@ pub async fn create_payment_connector(
     let mut default_routing_config =
         routing_helpers::get_merchant_default_config(&*state.store, merchant_id).await?;
 
+    let mut default_routing_config_for_profile =
+        routing_helpers::get_merchant_default_config(&*state.clone().store, &profile_id).await?;
+
     let mca = state
         .store
         .insert_merchant_connector_account(merchant_connector_account, &key_store)
         .await
         .to_duplicate_response(
             errors::ApiErrorResponse::DuplicateMerchantConnectorAccount {
-                profile_id,
+                profile_id: profile_id.clone(),
                 connector_name: req.connector_name.to_string(),
             },
         )?;
@@ -939,7 +942,7 @@ pub async fn create_payment_connector(
         };
 
         if !default_routing_config.contains(&choice) {
-            default_routing_config.push(choice);
+            default_routing_config.push(choice.clone());
             routing_helpers::update_merchant_default_config(
                 &*state.store,
                 merchant_id,
@@ -947,6 +950,15 @@ pub async fn create_payment_connector(
             )
             .await?;
         }
+        if !default_routing_config_for_profile.contains(&choice.clone()) {
+            default_routing_config_for_profile.push(choice);
+            routing_helpers::update_merchant_default_config(
+                &*state.store,
+                &profile_id.clone(),
+                default_routing_config_for_profile,
+            )
+            .await?;
+        }
     }
 
     metrics::MCA_CREATE.add(
diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs
index 4134ddf65ea..3b89d4e38e4 100644
--- a/crates/router/src/core/payments/routing.rs
+++ b/crates/router/src/core/payments/routing.rs
@@ -71,7 +71,10 @@ pub struct SessionRoutingPmTypeInput<'a> {
     routing_algorithm: &'a MerchantAccountRoutingAlgorithm,
     backend_input: dsl_inputs::BackendInput,
     allowed_connectors: FxHashMap<String, api::GetToken>,
-    #[cfg(feature = "business_profile_routing")]
+    #[cfg(any(
+        feature = "business_profile_routing",
+        feature = "profile_specific_fallback_routing"
+    ))]
     profile_id: Option<String>,
 }
 static ROUTING_CACHE: StaticCache<CachedAlgorithm> = StaticCache::new();
@@ -207,10 +210,22 @@ pub async fn perform_static_routing_v1<F: Clone>(
     let algorithm_id = if let Some(id) = algorithm_ref.algorithm_id {
         id
     } else {
-        let fallback_config =
-            routing_helpers::get_merchant_default_config(&*state.clone().store, merchant_id)
-                .await
-                .change_context(errors::RoutingError::FallbackConfigFetchFailed)?;
+        let fallback_config = routing_helpers::get_merchant_default_config(
+            &*state.clone().store,
+            #[cfg(not(feature = "profile_specific_fallback_routing"))]
+            merchant_id,
+            #[cfg(feature = "profile_specific_fallback_routing")]
+            {
+                payment_data
+                    .payment_intent
+                    .profile_id
+                    .as_ref()
+                    .get_required_value("profile_id")
+                    .change_context(errors::RoutingError::ProfileIdMissing)?
+            },
+        )
+        .await
+        .change_context(errors::RoutingError::FallbackConfigFetchFailed)?;
 
         return Ok(fallback_config);
     };
@@ -616,10 +631,22 @@ pub async fn perform_fallback_routing<F: Clone>(
     eligible_connectors: Option<&Vec<api_enums::RoutableConnectors>>,
     #[cfg(feature = "business_profile_routing")] profile_id: Option<String>,
 ) -> RoutingResult<Vec<routing_types::RoutableConnectorChoice>> {
-    let fallback_config =
-        routing_helpers::get_merchant_default_config(&*state.store, &key_store.merchant_id)
-            .await
-            .change_context(errors::RoutingError::FallbackConfigFetchFailed)?;
+    let fallback_config = routing_helpers::get_merchant_default_config(
+        &*state.store,
+        #[cfg(not(feature = "profile_specific_fallback_routing"))]
+        &key_store.merchant_id,
+        #[cfg(feature = "profile_specific_fallback_routing")]
+        {
+            payment_data
+                .payment_intent
+                .profile_id
+                .as_ref()
+                .get_required_value("profile_id")
+                .change_context(errors::RoutingError::ProfileIdMissing)?
+        },
+    )
+    .await
+    .change_context(errors::RoutingError::FallbackConfigFetchFailed)?;
     let backend_input = make_dsl_input(payment_data)?;
 
     perform_kgraph_filtering(
@@ -819,8 +846,11 @@ pub async fn perform_session_flow_routing(
             routing_algorithm: &routing_algorithm,
             backend_input: backend_input.clone(),
             allowed_connectors,
-            #[cfg(feature = "business_profile_routing")]
-            profile_id: session_input.payment_intent.clone().profile_id,
+            #[cfg(any(
+                feature = "business_profile_routing",
+                feature = "profile_specific_fallback_routing"
+            ))]
+            profile_id: session_input.payment_intent.profile_id.clone(),
         };
         let maybe_choice = perform_session_routing_for_pm_type(session_pm_input).await?;
 
@@ -880,7 +910,16 @@ async fn perform_session_routing_for_pm_type(
             } else {
                 routing_helpers::get_merchant_default_config(
                     &*session_pm_input.state.clone().store,
+                    #[cfg(not(feature = "profile_specific_fallback_routing"))]
                     merchant_id,
+                    #[cfg(feature = "profile_specific_fallback_routing")]
+                    {
+                        session_pm_input
+                            .profile_id
+                            .as_ref()
+                            .get_required_value("profile_id")
+                            .change_context(errors::RoutingError::ProfileIdMissing)?
+                    },
                 )
                 .await
                 .change_context(errors::RoutingError::FallbackConfigFetchFailed)?
@@ -903,7 +942,16 @@ async fn perform_session_routing_for_pm_type(
     if final_selection.is_empty() {
         let fallback = routing_helpers::get_merchant_default_config(
             &*session_pm_input.state.clone().store,
+            #[cfg(not(feature = "profile_specific_fallback_routing"))]
             merchant_id,
+            #[cfg(feature = "profile_specific_fallback_routing")]
+            {
+                session_pm_input
+                    .profile_id
+                    .as_ref()
+                    .get_required_value("profile_id")
+                    .change_context(errors::RoutingError::ProfileIdMissing)?
+            },
         )
         .await
         .change_context(errors::RoutingError::FallbackConfigFetchFailed)?;
diff --git a/crates/router/src/core/routing.rs b/crates/router/src/core/routing.rs
index 723611ed500..4171c338563 100644
--- a/crates/router/src/core/routing.rs
+++ b/crates/router/src/core/routing.rs
@@ -13,13 +13,14 @@ use diesel_models::routing_algorithm::RoutingAlgorithm;
 use error_stack::{IntoReport, ResultExt};
 use rustc_hash::FxHashSet;
 
-#[cfg(feature = "business_profile_routing")]
-use crate::core::utils::validate_and_get_business_profile;
 #[cfg(feature = "business_profile_routing")]
 use crate::types::transformers::{ForeignInto, ForeignTryInto};
 use crate::{
     consts,
-    core::errors::{RouterResponse, StorageErrorExt},
+    core::{
+        errors::{RouterResponse, StorageErrorExt},
+        utils as core_utils,
+    },
     routes::AppState,
     types::domain,
     utils::{self, OptionExt, ValueExt},
@@ -111,8 +112,12 @@ pub async fn create_routing_config(
             })
             .attach_printable("Profile_id not provided")?;
 
-        validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id)
-            .await?;
+        core_utils::validate_and_get_business_profile(
+            db,
+            Some(&profile_id),
+            &merchant_account.merchant_id,
+        )
+        .await?;
 
         helpers::validate_connectors_in_routing_config(
             db,
@@ -229,7 +234,7 @@ pub async fn link_routing_config(
             .await
             .change_context(errors::ApiErrorResponse::ResourceIdNotFound)?;
 
-        let business_profile = validate_and_get_business_profile(
+        let business_profile = core_utils::validate_and_get_business_profile(
             db,
             Some(&routing_algorithm.profile_id),
             &merchant_account.merchant_id,
@@ -332,7 +337,7 @@ pub async fn retrieve_routing_config(
             .await
             .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)?;
 
-        validate_and_get_business_profile(
+        core_utils::validate_and_get_business_profile(
             db,
             Some(&routing_algorithm.profile_id),
             &merchant_account.merchant_id,
@@ -401,9 +406,12 @@ pub async fn unlink_routing_config(
                 field_name: "profile_id",
             })
             .attach_printable("Profile_id not provided")?;
-        let business_profile =
-            validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id)
-                .await?;
+        let business_profile = core_utils::validate_and_get_business_profile(
+            db,
+            Some(&profile_id),
+            &merchant_account.merchant_id,
+        )
+        .await?;
         match business_profile {
             Some(business_profile) => {
                 let routing_algo_ref: routing_types::RoutingAlgorithmRef = business_profile
@@ -622,13 +630,15 @@ pub async fn retrieve_linked_routing_config(
     #[cfg(feature = "business_profile_routing")]
     {
         let business_profiles = if let Some(profile_id) = query_params.profile_id {
-            validate_and_get_business_profile(db, Some(&profile_id), &merchant_account.merchant_id)
-                .await?
-                .map(|profile| vec![profile])
-                .get_required_value("BusinessProfile")
-                .change_context(errors::ApiErrorResponse::BusinessProfileNotFound {
-                    id: profile_id,
-                })?
+            core_utils::validate_and_get_business_profile(
+                db,
+                Some(&profile_id),
+                &merchant_account.merchant_id,
+            )
+            .await?
+            .map(|profile| vec![profile])
+            .get_required_value("BusinessProfile")
+            .change_context(errors::ApiErrorResponse::BusinessProfileNotFound { id: profile_id })?
         } else {
             db.list_business_profile_by_merchant_id(&merchant_account.merchant_id)
                 .await
@@ -711,3 +721,118 @@ pub async fn retrieve_linked_routing_config(
         Ok(service_api::ApplicationResponse::Json(response))
     }
 }
+
+pub async fn retrieve_default_routing_config_for_profiles(
+    state: AppState,
+    merchant_account: domain::MerchantAccount,
+) -> RouterResponse<Vec<routing_types::ProfileDefaultRoutingConfig>> {
+    let db = state.store.as_ref();
+
+    let all_profiles = db
+        .list_business_profile_by_merchant_id(&merchant_account.merchant_id)
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::ResourceIdNotFound)
+        .attach_printable("error retrieving all business profiles for merchant")?;
+
+    let retrieve_config_futures = all_profiles
+        .iter()
+        .map(|prof| helpers::get_merchant_default_config(db, &prof.profile_id))
+        .collect::<Vec<_>>();
+
+    let configs = futures::future::join_all(retrieve_config_futures)
+        .await
+        .into_iter()
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let default_configs = configs
+        .into_iter()
+        .zip(all_profiles.iter().map(|prof| prof.profile_id.clone()))
+        .map(
+            |(config, profile_id)| routing_types::ProfileDefaultRoutingConfig {
+                profile_id,
+                connectors: config,
+            },
+        )
+        .collect::<Vec<_>>();
+
+    Ok(service_api::ApplicationResponse::Json(default_configs))
+}
+
+pub async fn update_default_routing_config_for_profile(
+    state: AppState,
+    merchant_account: domain::MerchantAccount,
+    updated_config: Vec<routing_types::RoutableConnectorChoice>,
+    profile_id: String,
+) -> RouterResponse<routing_types::ProfileDefaultRoutingConfig> {
+    let db = state.store.as_ref();
+
+    let business_profile = core_utils::validate_and_get_business_profile(
+        db,
+        Some(&profile_id),
+        &merchant_account.merchant_id,
+    )
+    .await?
+    .get_required_value("BusinessProfile")
+    .change_context(errors::ApiErrorResponse::BusinessProfileNotFound { id: profile_id })?;
+    let default_config =
+        helpers::get_merchant_default_config(db, &business_profile.profile_id).await?;
+
+    utils::when(default_config.len() != updated_config.len(), || {
+        Err(errors::ApiErrorResponse::PreconditionFailed {
+            message: "current config and updated config have different lengths".to_string(),
+        })
+        .into_report()
+    })?;
+
+    let existing_set = FxHashSet::from_iter(default_config.iter().map(|c| {
+        (
+            c.connector.to_string(),
+            #[cfg(feature = "connector_choice_mca_id")]
+            c.merchant_connector_id.as_ref(),
+            #[cfg(not(feature = "connector_choice_mca_id"))]
+            c.sub_label.as_ref(),
+        )
+    }));
+
+    let updated_set = FxHashSet::from_iter(updated_config.iter().map(|c| {
+        (
+            c.connector.to_string(),
+            #[cfg(feature = "connector_choice_mca_id")]
+            c.merchant_connector_id.as_ref(),
+            #[cfg(not(feature = "connector_choice_mca_id"))]
+            c.sub_label.as_ref(),
+        )
+    }));
+
+    let symmetric_diff = existing_set
+        .symmetric_difference(&updated_set)
+        .cloned()
+        .collect::<Vec<_>>();
+
+    utils::when(!symmetric_diff.is_empty(), || {
+        let error_str = symmetric_diff
+            .into_iter()
+            .map(|(connector, ident)| format!("'{connector}:{ident:?}'"))
+            .collect::<Vec<_>>()
+            .join(", ");
+
+        Err(errors::ApiErrorResponse::InvalidRequestData {
+            message: format!("connector mismatch between old and new configs ({error_str})"),
+        })
+        .into_report()
+    })?;
+
+    helpers::update_merchant_default_config(
+        db,
+        &business_profile.profile_id,
+        updated_config.clone(),
+    )
+    .await?;
+
+    Ok(service_api::ApplicationResponse::Json(
+        routing_types::ProfileDefaultRoutingConfig {
+            profile_id: business_profile.profile_id,
+            connectors: updated_config,
+        },
+    ))
+}
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index c34c542d1b6..7f5c720be60 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -324,6 +324,16 @@ impl Routing {
                 web::resource("/{algorithm_id}/activate")
                     .route(web::post().to(cloud_routing::routing_link_config)),
             )
+            .service(
+                web::resource("/default/profile/{profile_id}").route(
+                    web::post().to(cloud_routing::routing_update_default_config_for_profile),
+                ),
+            )
+            .service(
+                web::resource("/default/profile").route(
+                    web::get().to(cloud_routing::routing_retrieve_default_config_for_profiles),
+                ),
+            )
     }
 }
 
diff --git a/crates/router/src/routes/routing.rs b/crates/router/src/routes/routing.rs
index b87116f47fc..606111a8881 100644
--- a/crates/router/src/routes/routing.rs
+++ b/crates/router/src/routes/routing.rs
@@ -296,3 +296,60 @@ pub async fn routing_retrieve_linked_config(
         .await
     }
 }
+
+#[cfg(feature = "olap")]
+#[instrument(skip_all)]
+pub async fn routing_retrieve_default_config_for_profiles(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+) -> impl Responder {
+    oss_api::server_wrap(
+        Flow::RoutingRetrieveDefaultConfig,
+        state,
+        &req,
+        (),
+        |state, auth: auth::AuthenticationData, _| {
+            routing::retrieve_default_routing_config_for_profiles(state, auth.merchant_account)
+        },
+        #[cfg(not(feature = "release"))]
+        auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+        #[cfg(feature = "release")]
+        &auth::JWTAuth,
+        api_locking::LockAction::NotApplicable,
+    )
+    .await
+}
+
+#[cfg(feature = "olap")]
+#[instrument(skip_all)]
+pub async fn routing_update_default_config_for_profile(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    path: web::Path<String>,
+    json_payload: web::Json<Vec<routing_types::RoutableConnectorChoice>>,
+) -> impl Responder {
+    let routing_payload_wrapper = routing_types::RoutingPayloadWrapper {
+        updated_config: json_payload.into_inner(),
+        profile_id: path.into_inner(),
+    };
+    oss_api::server_wrap(
+        Flow::RoutingUpdateDefaultConfig,
+        state,
+        &req,
+        routing_payload_wrapper,
+        |state, auth: auth::AuthenticationData, wrapper| {
+            routing::update_default_routing_config_for_profile(
+                state,
+                auth.merchant_account,
+                wrapper.updated_config,
+                wrapper.profile_id,
+            )
+        },
+        #[cfg(not(feature = "release"))]
+        auth::auth_type(&auth::ApiKeyAuth, &auth::JWTAuth, req.headers()),
+        #[cfg(feature = "release")]
+        &auth::JWTAuth,
+        api_locking::LockAction::NotApplicable,
+    )
+    .await
+}

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

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

## Description
`default-fallbacks` are defined specific to profile i.e every profile will correspond to different fallbacks and while deriving the fallbacks we are doing that based on profile.

### Additional Changes

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

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

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


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

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


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
The tests will be same as this PR:
https://github.com/juspay/hyperswitch-cloud/pull/2949

## 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
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
