    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn toggle_success_based_routing(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<api_models::routing::ToggleDynamicRoutingQuery>,
    path: web::Path<routing_types::ToggleDynamicRoutingPath>,
) -> impl Responder {
    let flow = Flow::ToggleDynamicRouting;
    let wrapper = routing_types::ToggleDynamicRoutingWrapper {
        feature_to_enable: query.into_inner().enable,
        profile_id: path.into_inner().profile_id,
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        wrapper.clone(),
        |state,
         auth: auth::AuthenticationData,
         wrapper: routing_types::ToggleDynamicRoutingWrapper,
         _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::toggle_specific_dynamic_routing(
                state,
                merchant_context,
                wrapper.feature_to_enable,
                wrapper.profile_id,
                api_models::routing::DynamicRoutingType::SuccessRateBasedRouting,
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn create_success_based_routing(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<api_models::routing::CreateDynamicRoutingQuery>,
    path: web::Path<routing_types::ToggleDynamicRoutingPath>,
    success_based_config: web::Json<routing_types::SuccessBasedRoutingConfig>,
) -> impl Responder {
    let flow = Flow::CreateDynamicRoutingConfig;
    let wrapper = routing_types::CreateDynamicRoutingWrapper {
        feature_to_enable: query.into_inner().enable,
        profile_id: path.into_inner().profile_id,
        payload: api_models::routing::DynamicRoutingPayload::SuccessBasedRoutingPayload(
            success_based_config.into_inner(),
        ),
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        wrapper.clone(),
        |state,
         auth: auth::AuthenticationData,
         wrapper: routing_types::CreateDynamicRoutingWrapper,
         _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::create_specific_dynamic_routing(
                state,
                merchant_context,
                wrapper.feature_to_enable,
                wrapper.profile_id,
                api_models::routing::DynamicRoutingType::SuccessRateBasedRouting,
                wrapper.payload,
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn success_based_routing_update_configs(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<routing_types::DynamicRoutingUpdateConfigQuery>,
    json_payload: web::Json<routing_types::SuccessBasedRoutingConfig>,
) -> impl Responder {
    let flow = Flow::UpdateDynamicRoutingConfigs;
    let routing_payload_wrapper = routing_types::SuccessBasedRoutingPayloadWrapper {
        updated_config: json_payload.into_inner(),
        algorithm_id: path.clone().algorithm_id,
        profile_id: path.clone().profile_id,
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        routing_payload_wrapper.clone(),
        |state, _, wrapper: routing_types::SuccessBasedRoutingPayloadWrapper, _| async {
            Box::pin(routing::success_based_routing_update_configs(
                state,
                wrapper.updated_config,
                wrapper.algorithm_id,
                wrapper.profile_id,
            ))
            .await
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: routing_payload_wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn elimination_routing_update_configs(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<routing_types::DynamicRoutingUpdateConfigQuery>,
    json_payload: web::Json<routing_types::EliminationRoutingConfig>,
) -> impl Responder {
    let flow = Flow::UpdateDynamicRoutingConfigs;
    let routing_payload_wrapper = routing_types::EliminationRoutingPayloadWrapper {
        updated_config: json_payload.into_inner(),
        algorithm_id: path.clone().algorithm_id,
        profile_id: path.clone().profile_id,
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        routing_payload_wrapper.clone(),
        |state, _, wrapper: routing_types::EliminationRoutingPayloadWrapper, _| async {
            Box::pin(routing::elimination_routing_update_configs(
                state,
                wrapper.updated_config,
                wrapper.algorithm_id,
                wrapper.profile_id,
            ))
            .await
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: routing_payload_wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn contract_based_routing_setup_config(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<routing_types::ToggleDynamicRoutingPath>,
    query: web::Query<api_models::routing::ToggleDynamicRoutingQuery>,
    json_payload: Option<web::Json<routing_types::ContractBasedRoutingConfig>>,
) -> impl Responder {
    let flow = Flow::ToggleDynamicRouting;
    let routing_payload_wrapper = routing_types::ContractBasedRoutingSetupPayloadWrapper {
        config: json_payload.map(|json| json.into_inner()),
        profile_id: path.into_inner().profile_id,
        features_to_enable: query.into_inner().enable,
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        routing_payload_wrapper.clone(),
        |state,
         auth: auth::AuthenticationData,
         wrapper: routing_types::ContractBasedRoutingSetupPayloadWrapper,
         _| async move {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            Box::pin(routing::contract_based_dynamic_routing_setup(
                state,
                merchant_context,
                wrapper.profile_id,
                wrapper.features_to_enable,
                wrapper.config,
            ))
            .await
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: routing_payload_wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn contract_based_routing_update_configs(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<routing_types::DynamicRoutingUpdateConfigQuery>,
    json_payload: web::Json<routing_types::ContractBasedRoutingConfig>,
) -> impl Responder {
    let flow = Flow::UpdateDynamicRoutingConfigs;
    let routing_payload_wrapper = routing_types::ContractBasedRoutingPayloadWrapper {
        updated_config: json_payload.into_inner(),
        algorithm_id: path.algorithm_id.clone(),
        profile_id: path.profile_id.clone(),
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        routing_payload_wrapper.clone(),
        |state,
         auth: auth::AuthenticationData,
         wrapper: routing_types::ContractBasedRoutingPayloadWrapper,
         _| async {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            Box::pin(routing::contract_based_routing_update_configs(
                state,
                wrapper.updated_config,
                merchant_context,
                wrapper.algorithm_id,
                wrapper.profile_id,
            ))
            .await
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: routing_payload_wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn toggle_elimination_routing(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<api_models::routing::ToggleDynamicRoutingQuery>,
    path: web::Path<routing_types::ToggleDynamicRoutingPath>,
) -> impl Responder {
    let flow = Flow::ToggleDynamicRouting;
    let wrapper = routing_types::ToggleDynamicRoutingWrapper {
        feature_to_enable: query.into_inner().enable,
        profile_id: path.into_inner().profile_id,
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        wrapper.clone(),
        |state,
         auth: auth::AuthenticationData,
         wrapper: routing_types::ToggleDynamicRoutingWrapper,
         _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::toggle_specific_dynamic_routing(
                state,
                merchant_context,
                wrapper.feature_to_enable,
                wrapper.profile_id,
                api_models::routing::DynamicRoutingType::EliminationRouting,
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn create_elimination_routing(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<api_models::routing::CreateDynamicRoutingQuery>,
    path: web::Path<routing_types::ToggleDynamicRoutingPath>,
    elimination_config: web::Json<routing_types::EliminationRoutingConfig>,
) -> impl Responder {
    let flow = Flow::CreateDynamicRoutingConfig;
    let wrapper = routing_types::CreateDynamicRoutingWrapper {
        feature_to_enable: query.into_inner().enable,
        profile_id: path.into_inner().profile_id,
        payload: api_models::routing::DynamicRoutingPayload::EliminationRoutingPayload(
            elimination_config.into_inner(),
        ),
    };
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        wrapper.clone(),
        |state,
         auth: auth::AuthenticationData,
         wrapper: routing_types::CreateDynamicRoutingWrapper,
         _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::create_specific_dynamic_routing(
                state,
                merchant_context,
                wrapper.feature_to_enable,
                wrapper.profile_id,
                api_models::routing::DynamicRoutingType::EliminationRouting,
                wrapper.payload,
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: wrapper.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1"))]
#[instrument(skip_all)]
pub async fn set_dynamic_routing_volume_split(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<api_models::routing::DynamicRoutingVolumeSplitQuery>,
    path: web::Path<routing_types::ToggleDynamicRoutingPath>,
) -> impl Responder {
    let flow = Flow::VolumeSplitOnRoutingType;
    let routing_info = api_models::routing::RoutingVolumeSplit {
        routing_type: api_models::routing::RoutingType::Dynamic,
        split: query.into_inner().split,
    };
    let payload = api_models::routing::RoutingVolumeSplitWrapper {
        routing_info,
        profile_id: path.into_inner().profile_id,
    };

    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        payload.clone(),
        |state,
         auth: auth::AuthenticationData,
         payload: api_models::routing::RoutingVolumeSplitWrapper,
         _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::configure_dynamic_routing_volume_split(
                state,
                merchant_context,
                payload.profile_id,
                payload.routing_info,
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: payload.profile_id,
                required_permission: Permission::ProfileRoutingWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1"))]
#[instrument(skip_all)]
pub async fn get_dynamic_routing_volume_split(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<routing_types::ToggleDynamicRoutingPath>,
) -> impl Responder {
    let flow = Flow::VolumeSplitOnRoutingType;

    let payload = path.into_inner();
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        payload.clone(),
        |state, auth: auth::AuthenticationData, payload, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            routing::retrieve_dynamic_routing_volume_split(
                state,
                merchant_context,
                payload.profile_id,
            )
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuthProfileFromRoute {
                profile_id: payload.profile_id,
                required_permission: Permission::ProfileRoutingRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}
const EUCLID_API_TIMEOUT: u64 = 5;
#[cfg(all(feature = "olap", feature = "v1"))]
#[instrument(skip_all)]
pub async fn evaluate_routing_rule(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<RoutingEvaluateRequest>,
) -> impl Responder {
    let json_payload = json_payload.into_inner();
    let flow = Flow::RoutingEvaluateRule;
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        json_payload.clone(),
        |state, _auth: auth::AuthenticationData, payload, _| async move {
            let euclid_response: RoutingEvaluateResponse =
                EuclidApiClient::send_decision_engine_request(
                    &state,
                    services::Method::Post,
                    "routing/evaluate",
                    Some(payload),
                    Some(EUCLID_API_TIMEOUT),
                    None,
                )
                .await
                .change_context(ApiErrorResponse::InternalServerError)?
                .response
                .ok_or(ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to evaluate routing rule")?;

            Ok(services::ApplicationResponse::Json(euclid_response))
        },
        &auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

use actix_web::HttpResponse;
#[instrument(skip_all, fields(flow = ?Flow::DecisionEngineRuleMigration))]
pub async fn migrate_routing_rules_for_profile(
    state: web::Data<AppState>,
    req: HttpRequest,
    query: web::Query<routing_types::RuleMigrationQuery>,
) -> HttpResponse {
    let flow = Flow::DecisionEngineRuleMigration;

    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        query.into_inner(),
        |state, _, query_params, _| async move {
            let merchant_id = query_params.merchant_id.clone();
            let (key_store, merchant_account) = get_merchant_account(&state, &merchant_id).await?;
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(merchant_account, key_store),
            ));
            let res = Box::pin(routing::migrate_rules_for_profile(
                state,
                merchant_context,
                query_params,
            ))
            .await?;
            Ok(services::ApplicationResponse::Json(res))
        },
        &auth::AdminApiAuth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

async fn get_merchant_account(
    state: &super::SessionState,
    merchant_id: &common_utils::id_type::MerchantId,
) -> common_utils::errors::CustomResult<(MerchantKeyStore, domain::MerchantAccount), ApiErrorResponse>
{
    let key_manager_state = &state.into();
    let key_store = state
        .store
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            merchant_id,
            &state.store.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(ApiErrorResponse::MerchantAccountNotFound)?;

    let merchant_account = state
        .store
        .find_merchant_account_by_merchant_id(key_manager_state, merchant_id, &key_store)
        .await
        .to_not_found_response(ApiErrorResponse::MerchantAccountNotFound)?;
    Ok((key_store, merchant_account))
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn call_decide_gateway_open_router(
    state: web::Data<AppState>,
    req: HttpRequest,
    payload: web::Json<api_models::open_router::OpenRouterDecideGatewayRequest>,
) -> impl Responder {
    let flow = Flow::DecisionEngineDecideGatewayCall;
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        payload.clone(),
        |state, _auth, payload, _| routing::decide_gateway_open_router(state.clone(), payload),
        &auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(all(feature = "olap", feature = "v1", feature = "dynamic_routing"))]
#[instrument(skip_all)]
pub async fn call_update_gateway_score_open_router(
    state: web::Data<AppState>,
    req: HttpRequest,
    payload: web::Json<api_models::open_router::UpdateScorePayload>,
) -> impl Responder {
    let flow = Flow::DecisionEngineGatewayFeedbackCall;
    Box::pin(oss_api::server_wrap(
        flow,
        state,
        &req,
        payload.clone(),
        |state, _auth, payload, _| {
            routing::update_gateway_score_open_router(state.clone(), payload)
        },
        &auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub async fn merchant_account_delete(
    state: SessionState,
    merchant_id: id_type::MerchantId,
) -> RouterResponse<api::MerchantAccountDeleteResponse> {
    let mut is_deleted = false;
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let merchant_key_store = db
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &state.store.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let merchant_account = db
        .find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &merchant_key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let is_merchant_account_deleted = db
        .delete_merchant_account_by_merchant_id(&merchant_id)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
    if is_merchant_account_deleted {
        let is_merchant_key_store_deleted = db
            .delete_merchant_key_store_by_merchant_id(&merchant_id)
            .await
            .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;
        is_deleted = is_merchant_account_deleted && is_merchant_key_store_deleted;
    }

    let state = state.clone();
    authentication::decision::spawn_tracked_job(
        async move {
            authentication::decision::revoke_api_key(
                &state,
                merchant_account.publishable_key.into(),
            )
            .await
        },
        authentication::decision::REVOKE,
    );

    match db
        .delete_config_by_key(merchant_id.get_requires_cvv_key().as_str())
        .await
    {
        Ok(_) => Ok::<_, errors::ApiErrorResponse>(()),
        Err(err) => {
            if err.current_context().is_db_not_found() {
                logger::error!("requires_cvv config not found in db: {err:?}");
                Ok(())
            } else {
                Err(err
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed while deleting requires_cvv config"))?
            }
        }
    }
    .ok();

    let response = api::MerchantAccountDeleteResponse {
        merchant_id,
        deleted: is_deleted,
    };
    Ok(service_api::ApplicationResponse::Json(response))
}


pub struct BacsBankTransferAdditionalData {
    /// Partially masked sort code for Bacs payment method
    #[schema(value_type = String, example = "108800")]
    pub bank_sort_code: MaskedSortCode,

    /// Bank account's owner name
    #[schema(value_type = String, example = "0001****3456")]
    pub bank_account_number: MaskedBankAccount,

    /// Bank name
    #[schema(value_type = Option<String>, example = "Deutsche Bank")]
    pub bank_name: Option<String>,

    /// Bank country code
    #[schema(value_type = Option<CountryAlpha2>, example = "US")]
    pub bank_country_code: Option<common_enums::CountryAlpha2>,

    /// Bank city
    #[schema(value_type = Option<String>, example = "California")]
    pub bank_city: Option<String>,
}


pub struct GenericLinkFormData {
    pub js_data: String,
    pub css_data: String,
    pub sdk_url: url::Url,
    pub html_meta_tags: String,
}


pub struct FrmMetricsBucketResponse {
    #[serde(flatten)]
    pub values: FrmMetricsBucketValue,
    #[serde(flatten)]
    pub dimensions: FrmMetricsBucketIdentifier,
}


pub struct TimelinePayment {
    pub value: OverpaymentAbsoluteThreshold,
    pub network: String,
    pub transaction_id: String,
}


impl common_utils::events::ApiEventMetric for EphemeralKeyCreateRequest {
    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
        Some(common_utils::events::ApiEventsType::Miscellaneous)
    }
}

impl common_utils::events::ApiEventMetric for for EphemeralKeyCreateRequest


pub async fn read_from_stream(
        &self,
        stream_name: &str,
        max_read_count: u64,
    ) -> errors::DrainerResult<StreamReadResult> {
        // "0-0" id gives first entry
        let stream_id = "0-0";
        let (output, execution_time) = common_utils::date_time::time_it(|| async {
            self.redis_conn
                .stream_read_entries(stream_name, stream_id, Some(max_read_count))
                .await
                .map_err(errors::DrainerError::from)
        })
        .await;

        metrics::REDIS_STREAM_READ_TIME.record(
            execution_time,
            router_env::metric_attributes!(("stream", stream_name.to_owned())),
        );

        Ok(output?)
    }


File: crates/analytics/src/payments/metrics/debit_routing.rs

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.clone()),
                        i.signature_network.clone(),
                        i.is_issuer_regulated,
                        i.is_debit_routed,
                        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)
    }
}


pub struct ClientAuthCheckInfoResponse {
    id: String,
    client_reference_information: ClientReferenceInformation,
    consumer_authentication_information: CybersourceConsumerAuthInformationEnrollmentResponse,
    status: CybersourceAuthEnrollmentStatus,
    error_information: Option<CybersourceErrorInformation>,
}


pub fn validate_connectors_in_routing_config(&self) -> RouterResult<()> {
        match self.routing_algorithm {
            routing_types::StaticRoutingAlgorithm::Single(choice) => {
                self.connector_choice(choice)?;
            }

            routing_types::StaticRoutingAlgorithm::Priority(list) => {
                for choice in list {
                    self.connector_choice(choice)?;
                }
            }

            routing_types::StaticRoutingAlgorithm::VolumeSplit(splits) => {
                for split in splits {
                    self.connector_choice(&split.connector)?;
                }
            }

            routing_types::StaticRoutingAlgorithm::Advanced(program) => {
                let check_connector_selection =
                    |selection: &routing_types::ConnectorSelection| -> RouterResult<()> {
                        match selection {
                            routing_types::ConnectorSelection::VolumeSplit(splits) => {
                                for split in splits {
                                    self.connector_choice(&split.connector)?;
                                }
                            }

                            routing_types::ConnectorSelection::Priority(list) => {
                                for choice in list {
                                    self.connector_choice(choice)?;
                                }
                            }
                        }

                        Ok(())
                    };

                check_connector_selection(&program.default_selection)?;

                for rule in &program.rules {
                    check_connector_selection(&rule.connector_selection)?;
                }
            }

            routing_types::StaticRoutingAlgorithm::ThreeDsDecisionRule(_) => {
                return Err(errors::ApiErrorResponse::InternalServerError).attach_printable(
                    "Invalid routing algorithm three_ds decision rule received",
                )?;
            }
        }

        Ok(())
    }


pub struct PlaidRecipientCreateAddress {
    pub street: String,
    pub city: String,
    pub postal_code: String,
    pub country: String,
}


pub struct AtomeData {
    atome: AtomeDetails,
    #[serde(rename = "type")]
    payment_method_type: AirwallexPaymentType,
}


pub struct Role {
    pub role_name: String,
    pub role_id: String,
    pub merchant_id: Option<id_type::MerchantId>,
    pub org_id: id_type::OrganizationId,
    #[diesel(deserialize_as = super::DieselArray<enums::PermissionGroup>)]
    pub groups: Vec<enums::PermissionGroup>,
    pub scope: enums::RoleScope,
    pub created_at: PrimitiveDateTime,
    pub created_by: String,
    pub last_modified_at: PrimitiveDateTime,
    pub last_modified_by: String,
    pub entity_type: enums::EntityType,
    pub profile_id: Option<id_type::ProfileId>,
    pub tenant_id: id_type::TenantId,
}


pub struct RuleMigrationResponse {
    pub profile_id: common_utils::id_type::ProfileId,
    pub euclid_algorithm_id: common_utils::id_type::RoutingId,
    pub decision_engine_algorithm_id: String,
    pub is_active_rule: bool,
}


/// Middleware to include request ID in response header.
pub struct RequestId;


impl api::RefundSync for Gocardless {}


impl api::PaymentAuthorize for Checkbook {}

impl api::PaymentAuthorize for for Checkbook


impl ConnectorTransactionId for Nexinets {
    #[cfg(feature = "v1")]
    fn connector_transaction_id(
        &self,
        payment_attempt: &PaymentAttempt,
    ) -> Result<Option<String>, ApiErrorResponse> {
        let metadata =
            Self::connector_transaction_id(self, payment_attempt.connector_metadata.as_ref());
        metadata.map_err(|_| ApiErrorResponse::ResourceIdNotFound)
    }

    #[cfg(feature = "v2")]
    fn connector_transaction_id(
        &self,
        payment_attempt: &PaymentAttempt,
    ) -> Result<Option<String>, ApiErrorResponse> {
        use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;

        let metadata = Self::connector_transaction_id(
            self,
            payment_attempt
                .connector_metadata
                .as_ref()
                .map(|connector_metadata| connector_metadata.peek()),
        );
        metadata.map_err(|_| ApiErrorResponse::ResourceIdNotFound)
    }
}

impl ConnectorTransactionId for for Nexinets


pub fn validate(&self) -> Result<(), ApplicationError> {
        use common_utils::fp_utils::when;

        when(self.expiry == 0, || {
            Err(ApplicationError::InvalidConfigurationValueError(
                "link's expiry should not be 0".into(),
            ))
        })
    }


Documentation: api-reference/v2/merchant-account/merchant-account--retrieve.mdx
# Type: Doc File

---
openapi: get /v2/merchant-accounts/{id}
---


pub async fn client_secret_delete(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<String>,
) -> HttpResponse {
    let flow = Flow::EphemeralKeyDelete;
    let payload = path.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _: auth::AuthenticationData, req, _| helpers::delete_client_secret(state, req),
        &auth::V2ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


File: crates/hyperswitch_interfaces/src/webhooks.rs
 Public structs: 1

//! Webhooks interface

use common_utils::{crypto, errors::CustomResult, ext_traits::ValueExt};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    api::ApplicationResponse, errors::api_error_response::ApiErrorResponse,
};
use masking::{ExposeInterface, Secret};

use crate::{api::ConnectorCommon, errors};

/// struct IncomingWebhookRequestDetails
#[derive(Debug)]
pub struct IncomingWebhookRequestDetails<'a> {
    /// method
    pub method: http::Method,
    /// uri
    pub uri: http::Uri,
    /// headers
    pub headers: &'a actix_web::http::header::HeaderMap,
    /// body
    pub body: &'a [u8],
    /// query_params
    pub query_params: String,
}

/// IncomingWebhookFlowError enum defining the error type for incoming webhook
#[derive(Debug)]
pub enum IncomingWebhookFlowError {
    /// Resource not found for the webhook
    ResourceNotFound,
    /// Internal error for the webhook
    InternalError,
}

impl From<&ApiErrorResponse> for IncomingWebhookFlowError {
    fn from(api_error_response: &ApiErrorResponse) -> Self {
        match api_error_response {
            ApiErrorResponse::WebhookResourceNotFound
            | ApiErrorResponse::DisputeNotFound { .. }
            | ApiErrorResponse::PayoutNotFound
            | ApiErrorResponse::MandateNotFound
            | ApiErrorResponse::PaymentNotFound
            | ApiErrorResponse::RefundNotFound
            | ApiErrorResponse::AuthenticationNotFound { .. } => Self::ResourceNotFound,
            _ => Self::InternalError,
        }
    }
}

/// Trait defining incoming webhook
#[async_trait::async_trait]
pub trait IncomingWebhook: ConnectorCommon + Sync {
    /// fn get_webhook_body_decoding_algorithm
    fn get_webhook_body_decoding_algorithm(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::DecodeMessage + Send>, errors::ConnectorError> {
        Ok(Box::new(crypto::NoAlgorithm))
    }

    /// fn get_webhook_body_decoding_message
    fn get_webhook_body_decoding_message(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        Ok(request.body.to_vec())
    }

    /// fn decode_webhook_body
    async fn decode_webhook_body(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
        connector_name: &str,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let algorithm = self.get_webhook_body_decoding_algorithm(request)?;

        let message = self
            .get_webhook_body_decoding_message(request)
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
        let secret = self
            .get_webhook_source_verification_merchant_secret(
                merchant_id,
                connector_name,
                connector_webhook_details,
            )
            .await
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;

        algorithm
            .decode_message(&secret.secret, message.into())
            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)
    }

    /// fn get_webhook_source_verification_algorithm
    fn get_webhook_source_verification_algorithm(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
        Ok(Box::new(crypto::NoAlgorithm))
    }

    /// fn get_webhook_source_verification_merchant_secret
    async fn get_webhook_source_verification_merchant_secret(
        &self,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_name: &str,
        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
    ) -> CustomResult<api_models::webhooks::ConnectorWebhookSecrets, errors::ConnectorError> {
        let debug_suffix =
            format!("For merchant_id: {merchant_id:?}, and connector_name: {connector_name}");
        let default_secret = "default_secret".to_string();
        let merchant_secret = match connector_webhook_details {
            Some(merchant_connector_webhook_details) => {
                let connector_webhook_details = merchant_connector_webhook_details
                    .parse_value::<api_models::admin::MerchantConnectorWebhookDetails>(
                        "MerchantConnectorWebhookDetails",
                    )
                    .change_context_lazy(|| errors::ConnectorError::WebhookSourceVerificationFailed)
                    .attach_printable_lazy(|| {
                        format!(
                            "Deserializing MerchantConnectorWebhookDetails failed {debug_suffix}",
                        )
                    })?;
                api_models::webhooks::ConnectorWebhookSecrets {
                    secret: connector_webhook_details
                        .merchant_secret
                        .expose()
                        .into_bytes(),
                    additional_secret: connector_webhook_details.additional_secret,
                }
            }

            None => api_models::webhooks::ConnectorWebhookSecrets {
                secret: default_secret.into_bytes(),
                additional_secret: None,
            },
        };

        //need to fetch merchant secret from config table with caching in future for enhanced performance

        //If merchant has not set the secret for webhook source verification, "default_secret" is returned.
        //So it will fail during verification step and goes to psync flow.
        Ok(merchant_secret)
    }

    /// fn get_webhook_source_verification_signature
    fn get_webhook_source_verification_signature(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        Ok(Vec::new())
    }

    /// fn get_webhook_source_verification_message
    fn get_webhook_source_verification_message(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
        _merchant_id: &common_utils::id_type::MerchantId,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        Ok(Vec::new())
    }

    /// fn verify_webhook_source
    async fn verify_webhook_source(
        &self,
        request: &IncomingWebhookRequestDetails<'_>,
        merchant_id: &common_utils::id_type::MerchantId,
        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
        _connector_account_details: crypto::Encryptable<Secret<serde_json::Value>>,
        connector_name: &str,
    ) -> CustomResult<bool, errors::ConnectorError> {
        let algorithm = self
            .get_webhook_source_verification_algorithm(request)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;

        let connector_webhook_secrets = self
            .get_webhook_source_verification_merchant_secret(
                merchant_id,
                connector_name,
                connector_webhook_details,
            )
            .await
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;

        let signature = self
            .get_webhook_source_verification_signature(request, &connector_webhook_secrets)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;

        let message = self
            .get_webhook_source_verification_message(
                request,
                merchant_id,
                &connector_webhook_secrets,
            )
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)?;

        algorithm
            .verify_signature(&connector_webhook_secrets.secret, &signature, &message)
            .change_context(errors::ConnectorError::WebhookSourceVerificationFailed)
    }

    /// fn get_webhook_object_reference_id
    fn get_webhook_object_reference_id(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError>;

    /// fn get_webhook_event_type
    fn get_webhook_event_type(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError>;

    /// fn get_webhook_resource_object
    fn get_webhook_resource_object(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError>;

    /// fn get_webhook_api_response
    fn get_webhook_api_response(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
        _error_kind: Option<IncomingWebhookFlowError>,
    ) -> CustomResult<ApplicationResponse<serde_json::Value>, errors::ConnectorError> {
        Ok(ApplicationResponse::StatusOk)
    }

    /// fn get_dispute_details
    fn get_dispute_details(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<crate::disputes::DisputePayload, errors::ConnectorError> {
        Err(errors::ConnectorError::NotImplemented("get_dispute_details method".to_string()).into())
    }

    /// fn get_external_authentication_details
    fn get_external_authentication_details(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<crate::authentication::ExternalAuthenticationPayload, errors::ConnectorError>
    {
        Err(errors::ConnectorError::NotImplemented(
            "get_external_authentication_details method".to_string(),
        )
        .into())
    }

    /// fn get_mandate_details
    fn get_mandate_details(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<
        Option<hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails>,
        errors::ConnectorError,
    > {
        Ok(None)
    }

    /// fn get_network_txn_id
    fn get_network_txn_id(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<
        Option<hyperswitch_domain_models::router_flow_types::ConnectorNetworkTxnId>,
        errors::ConnectorError,
    > {
        Ok(None)
    }

    #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
    /// get revenue recovery invoice details
    fn get_revenue_recovery_attempt_details(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<
        hyperswitch_domain_models::revenue_recovery::RevenueRecoveryAttemptData,
        errors::ConnectorError,
    > {
        Err(errors::ConnectorError::NotImplemented(
            "get_revenue_recovery_attempt_details method".to_string(),
        )
        .into())
    }
    #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
    /// get revenue recovery transaction details
    fn get_revenue_recovery_invoice_details(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<
        hyperswitch_domain_models::revenue_recovery::RevenueRecoveryInvoiceData,
        errors::ConnectorError,
    > {
        Err(errors::ConnectorError::NotImplemented(
            "get_revenue_recovery_invoice_details method".to_string(),
        )
        .into())
    }
}


impl RecoveryCodes {
    pub fn generate_new() -> Self {
        let mut rand = rand::thread_rng();
        let recovery_codes = (0..consts::user::RECOVERY_CODES_COUNT)
            .map(|_| {
                let code_part_1 =
                    Alphanumeric.sample_string(&mut rand, consts::user::RECOVERY_CODE_LENGTH / 2);
                let code_part_2 =
                    Alphanumeric.sample_string(&mut rand, consts::user::RECOVERY_CODE_LENGTH / 2);

                Secret::new(format!("{code_part_1}-{code_part_2}"))
            })
            .collect::<Vec<_>>();

        Self(recovery_codes)
    }

    pub fn get_hashed(&self) -> UserResult<Vec<Secret<String>>> {
        self.0
            .iter()
            .cloned()
            .map(password::generate_password_hash)
            .collect::<Result<Vec<_>, _>>()
    }

    pub fn into_inner(self) -> Vec<Secret<String>> {
        self.0
    }
}


pub async fn construct_relay_refund_router_data<F>(
    state: &SessionState,
    merchant_id: &id_type::MerchantId,
    connector_account: &domain::MerchantConnectorAccount,
    relay_record: &hyperswitch_domain_models::relay::Relay,
) -> RouterResult<types::RefundsRouterData<F>> {
    let connector_auth_type = connector_account
        .get_connector_account_details()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed while parsing value for ConnectorAuthType")?;

    #[cfg(feature = "v2")]
    let connector_name = &connector_account.connector_name.to_string();

    #[cfg(feature = "v1")]
    let connector_name = &connector_account.connector_name;

    let webhook_url = Some(payments::helpers::create_webhook_url(
        &state.base_url.clone(),
        merchant_id,
        connector_account.get_id().get_string_repr(),
    ));

    let supported_connector = &state
        .conf
        .multiple_api_version_supported_connectors
        .supported_connectors;

    let connector_enum = api_models::enums::Connector::from_str(connector_name)
        .change_context(errors::ConnectorError::InvalidConnectorName)
        .change_context(errors::ApiErrorResponse::InvalidDataValue {
            field_name: "connector",
        })
        .attach_printable_lazy(|| format!("unable to parse connector name {connector_name:?}"))?;

    let connector_api_version = if supported_connector.contains(&connector_enum) {
        state
            .store
            .find_config_by_key(&format!("connector_api_version_{connector_name}"))
            .await
            .map(|value| value.config)
            .ok()
    } else {
        None
    };

    let hyperswitch_domain_models::relay::RelayData::Refund(relay_refund_data) = relay_record
        .request_data
        .clone()
        .get_required_value("refund relay data")
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to obtain relay data to construct relay refund data")?;

    let relay_id_string = relay_record.id.get_string_repr().to_string();

    let router_data = hyperswitch_domain_models::router_data::RouterData {
        flow: std::marker::PhantomData,
        merchant_id: merchant_id.clone(),
        customer_id: None,
        tenant_id: state.tenant.tenant_id.clone(),
        connector: connector_name.to_string(),
        payment_id: IRRELEVANT_PAYMENT_INTENT_ID.to_string(),
        attempt_id: IRRELEVANT_PAYMENT_ATTEMPT_ID.to_string(),
        status: common_enums::AttemptStatus::Charged,
        payment_method: common_enums::PaymentMethod::default(),
        connector_auth_type,
        description: None,
        address: hyperswitch_domain_models::payment_address::PaymentAddress::default(),
        auth_type: common_enums::AuthenticationType::default(),
        connector_meta_data: connector_account.metadata.clone(),
        connector_wallets_details: None,
        amount_captured: None,
        payment_method_status: None,
        minor_amount_captured: None,
        request: hyperswitch_domain_models::router_request_types::RefundsData {
            refund_id: relay_id_string.clone(),
            connector_transaction_id: relay_record.connector_resource_id.clone(),
            refund_amount: relay_refund_data.amount.get_amount_as_i64(),
            minor_refund_amount: relay_refund_data.amount,
            currency: relay_refund_data.currency,
            payment_amount: relay_refund_data.amount.get_amount_as_i64(),
            minor_payment_amount: relay_refund_data.amount,
            webhook_url,
            connector_metadata: None,
            refund_connector_metadata: None,
            reason: relay_refund_data.reason,
            connector_refund_id: relay_record.connector_reference_id.clone(),
            browser_info: None,
            split_refunds: None,
            integrity_object: None,
            refund_status: common_enums::RefundStatus::from(relay_record.status),
            merchant_account_id: None,
            merchant_config_currency: None,
            capture_method: None,
            additional_payment_method_data: None,
        },

        response: Err(ErrorResponse::default()),
        access_token: None,
        session_token: None,
        reference_id: None,
        payment_method_token: None,
        connector_customer: None,
        recurring_mandate_payment_data: None,
        preprocessing_id: None,
        connector_request_reference_id: relay_id_string.clone(),
        #[cfg(feature = "payouts")]
        payout_method_data: None,
        #[cfg(feature = "payouts")]
        quote_id: None,
        test_mode: connector_account.get_connector_test_mode(),
        payment_method_balance: None,
        connector_api_version,
        connector_http_status_code: None,
        external_latency: None,
        apple_pay_flow: None,
        frm_metadata: None,
        refund_id: Some(relay_id_string),
        dispute_id: None,
        connector_response: None,
        integrity_check: Ok(()),
        additional_merchant_data: None,
        header_payload: None,
        connector_mandate_request_reference_id: None,
        authentication_id: None,
        psd2_sca_exemption_type: None,
        raw_connector_response: None,
        is_payment_id_from_merchant: None,
        l2_l3_data: None,
        minor_amount_capturable: None,
    };

    Ok(router_data)
}


pub struct CardMandateRequest {
    billing_address: Option<Address>,
    expiry: Option<Secret<String>>,
    name: Option<Secret<String>>,
    number: Option<cards::CardNumber>,
}


pub struct ZenGeneralPaymentData {
    #[serde(rename = "type")]
    payment_type: ZenPaymentTypes,
    return_url: String,
}


pub struct PostSessionTokens;


OpenAPI Block Path: components.schemas.CryptoData
{
  "type": "object",
  "properties": {
    "pay_currency": {
      "type": "string",
      "nullable": true
    },
    "network": {
      "type": "string",
      "nullable": true
    }
  }
}


OpenAPI Block Path: components.schemas.MobilePaymentData
{
  "oneOf": [
    {
      "type": "object",
      "required": [
        "direct_carrier_billing"
      ],
      "properties": {
        "direct_carrier_billing": {
          "type": "object",
          "required": [
            "msisdn"
          ],
          "properties": {
            "msisdn": {
              "type": "string",
              "description": "The phone number of the user",
              "example": "1234567890"
            },
            "client_uid": {
              "type": "string",
              "description": "Unique user id",
              "example": "02iacdYXGI9CnyJdoN8c7",
              "nullable": true
            }
          }
        }
      }
    }
  ]
}


pub struct Shipping {
    pub address: StripeAddressDetails,
    pub name: Option<masking::Secret<String>>,
    pub carrier: Option<String>,
    pub phone: Option<masking::Secret<String>>,
    pub tracking_number: Option<masking::Secret<String>>,
}


pub fn apply_changeset(self, source: MerchantAccount) -> MerchantAccount {
        let Self {
            merchant_name,
            merchant_details,
            return_url,
            webhook_details,
            sub_merchants_enabled,
            parent_merchant_id,
            enable_payment_response_hash,
            payment_response_hash_key,
            redirect_to_merchant_with_http_post,
            publishable_key,
            storage_scheme,
            locker_id,
            metadata,
            routing_algorithm,
            primary_business_details,
            modified_at,
            intent_fulfillment_time,
            frm_routing_algorithm,
            payout_routing_algorithm,
            organization_id,
            is_recon_enabled,
            default_profile,
            recon_status,
            payment_link_config,
            pm_collect_link_config,
            is_platform_account,
            product_type,
        } = self;

        MerchantAccount {
            merchant_id: source.merchant_id,
            return_url: return_url.or(source.return_url),
            enable_payment_response_hash: enable_payment_response_hash
                .unwrap_or(source.enable_payment_response_hash),
            payment_response_hash_key: payment_response_hash_key
                .or(source.payment_response_hash_key),
            redirect_to_merchant_with_http_post: redirect_to_merchant_with_http_post
                .unwrap_or(source.redirect_to_merchant_with_http_post),
            merchant_name: merchant_name.or(source.merchant_name),
            merchant_details: merchant_details.or(source.merchant_details),
            webhook_details: webhook_details.or(source.webhook_details),
            sub_merchants_enabled: sub_merchants_enabled.or(source.sub_merchants_enabled),
            parent_merchant_id: parent_merchant_id.or(source.parent_merchant_id),
            publishable_key: publishable_key.or(source.publishable_key),
            storage_scheme: storage_scheme.unwrap_or(source.storage_scheme),
            locker_id: locker_id.or(source.locker_id),
            metadata: metadata.or(source.metadata),
            routing_algorithm: routing_algorithm.or(source.routing_algorithm),
            primary_business_details: primary_business_details
                .unwrap_or(source.primary_business_details),
            intent_fulfillment_time: intent_fulfillment_time.or(source.intent_fulfillment_time),
            created_at: source.created_at,
            modified_at,
            frm_routing_algorithm: frm_routing_algorithm.or(source.frm_routing_algorithm),
            payout_routing_algorithm: payout_routing_algorithm.or(source.payout_routing_algorithm),
            organization_id: organization_id.unwrap_or(source.organization_id),
            is_recon_enabled: is_recon_enabled.unwrap_or(source.is_recon_enabled),
            default_profile: default_profile.unwrap_or(source.default_profile),
            recon_status: recon_status.unwrap_or(source.recon_status),
            payment_link_config: payment_link_config.or(source.payment_link_config),
            pm_collect_link_config: pm_collect_link_config.or(source.pm_collect_link_config),
            version: source.version,
            is_platform_account: is_platform_account.unwrap_or(source.is_platform_account),
            id: source.id,
            product_type: product_type.or(source.product_type),
            merchant_account_type: source.merchant_account_type,
        }
    }


impl LockerMockUpNew {
    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<LockerMockUp> {
        generics::generic_insert(conn, self).await
    }
}


File: crates/api_models/src/payments/trait_impls.rs

#[cfg(feature = "v1")]
use common_enums::enums;
#[cfg(feature = "v1")]
use common_utils::errors;

#[cfg(feature = "v1")]
use crate::payments;

#[cfg(feature = "v1")]
impl crate::ValidateFieldAndGet<payments::PaymentsRequest>
    for common_types::primitive_wrappers::RequestExtendedAuthorizationBool
{
    fn validate_field_and_get(
        &self,
        request: &payments::PaymentsRequest,
    ) -> errors::CustomResult<Self, errors::ValidationError>
    where
        Self: Sized,
    {
        match request.capture_method{
            Some(enums::CaptureMethod::Automatic)
            | Some(enums::CaptureMethod::Scheduled)
            | Some(enums::CaptureMethod::SequentialAutomatic)
            | None => Err(error_stack::report!(errors::ValidationError::InvalidValue { message: "request_extended_authorization must be sent only if capture method is manual or manual_multiple".to_string() })),
            Some(enums::CaptureMethod::Manual)
            | Some(enums::CaptureMethod::ManualMultiple) => Ok(*self)
        }
    }
}


impl PaymentMethodsState {
    pub async fn find_payment_method(
        &self,
        key_store: &merchant_key_store::MerchantKeyStore,
        merchant_account: &merchant_account::MerchantAccount,
        payment_method_id: String,
    ) -> CustomResult<pm_domain::PaymentMethod, errors::StorageError> {
        let db = &*self.store;
        let key_manager_state = &(self.key_manager_state).clone();

        match db
            .find_payment_method(
                key_manager_state,
                key_store,
                &payment_method_id,
                merchant_account.storage_scheme,
            )
            .await
        {
            Err(err) if err.current_context().is_db_not_found() => {
                db.find_payment_method_by_locker_id(
                    key_manager_state,
                    key_store,
                    &payment_method_id,
                    merchant_account.storage_scheme,
                )
                .await
            }
            Ok(pm) => Ok(pm),
            Err(err) => Err(err),
        }
    }
}


impl ConnectorValidation for Payone {}


pub fn apply_debit_routing_decision<F, D>(&self, payment_data: &mut D)


File: crates/router/src/services/authorization/roles.rs
 Public functions: 15
 Public structs: 1

#[cfg(feature = "recon")]
use std::collections::HashMap;
use std::collections::HashSet;

#[cfg(feature = "recon")]
use api_models::enums::ReconPermissionScope;
use common_enums::{EntityType, PermissionGroup, Resource, RoleScope};
use common_utils::{errors::CustomResult, id_type};

#[cfg(feature = "recon")]
use super::permission_groups::{RECON_OPS, RECON_REPORTS};
use super::{permission_groups::PermissionGroupExt, permissions::Permission};
use crate::{core::errors, routes::SessionState};

pub mod predefined_roles;

#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
pub struct RoleInfo {
    role_id: String,
    role_name: String,
    groups: Vec<PermissionGroup>,
    scope: RoleScope,
    entity_type: EntityType,
    is_invitable: bool,
    is_deletable: bool,
    is_updatable: bool,
    is_internal: bool,
}

impl RoleInfo {
    pub fn get_role_id(&self) -> &str {
        &self.role_id
    }

    pub fn get_role_name(&self) -> &str {
        &self.role_name
    }

    pub fn get_permission_groups(&self) -> Vec<PermissionGroup> {
        self.groups
            .iter()
            .flat_map(|group| group.accessible_groups())
            .collect::<HashSet<_>>()
            .into_iter()
            .collect()
    }

    pub fn get_scope(&self) -> RoleScope {
        self.scope
    }

    pub fn get_entity_type(&self) -> EntityType {
        self.entity_type
    }

    pub fn is_invitable(&self) -> bool {
        self.is_invitable
    }

    pub fn is_deletable(&self) -> bool {
        self.is_deletable
    }

    pub fn is_internal(&self) -> bool {
        self.is_internal
    }

    pub fn is_updatable(&self) -> bool {
        self.is_updatable
    }

    pub fn get_resources_set(&self) -> HashSet<Resource> {
        self.get_permission_groups()
            .iter()
            .flat_map(|group| group.resources())
            .collect()
    }

    pub fn check_permission_exists(&self, required_permission: Permission) -> bool {
        required_permission.entity_type() <= self.entity_type
            && self.get_permission_groups().iter().any(|group| {
                required_permission.scope() <= group.scope()
                    && group.resources().contains(&required_permission.resource())
            })
    }

    #[cfg(feature = "recon")]
    pub fn get_recon_acl(&self) -> HashMap<Resource, ReconPermissionScope> {
        let mut acl: HashMap<Resource, ReconPermissionScope> = HashMap::new();
        let mut recon_resources = RECON_OPS.to_vec();
        recon_resources.extend(RECON_REPORTS);
        let recon_internal_resources = [Resource::ReconToken];
        self.get_permission_groups()
            .iter()
            .for_each(|permission_group| {
                permission_group.resources().iter().for_each(|resource| {
                    if recon_resources.contains(resource)
                        && !recon_internal_resources.contains(resource)
                    {
                        let scope = match resource {
                            Resource::ReconAndSettlementAnalytics => ReconPermissionScope::Read,
                            _ => ReconPermissionScope::from(permission_group.scope()),
                        };
                        acl.entry(*resource)
                            .and_modify(|curr_scope| {
                                *curr_scope = if (*curr_scope) < scope {
                                    scope
                                } else {
                                    *curr_scope
                                }
                            })
                            .or_insert(scope);
                    }
                })
            });
        acl
    }

    pub fn from_predefined_roles(role_id: &str) -> Option<Self> {
        predefined_roles::PREDEFINED_ROLES.get(role_id).cloned()
    }

    pub async fn from_role_id_in_lineage(
        state: &SessionState,
        role_id: &str,
        merchant_id: &id_type::MerchantId,
        org_id: &id_type::OrganizationId,
        profile_id: &id_type::ProfileId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<Self, errors::StorageError> {
        if let Some(role) = predefined_roles::PREDEFINED_ROLES.get(role_id) {
            Ok(role.clone())
        } else {
            state
                .global_store
                .find_role_by_role_id_in_lineage(
                    role_id,
                    merchant_id,
                    org_id,
                    profile_id,
                    tenant_id,
                )
                .await
                .map(Self::from)
        }
    }

    // TODO: To evaluate whether we can omit org_id and tenant_id for this function
    pub async fn from_role_id_org_id_tenant_id(
        state: &SessionState,
        role_id: &str,
        org_id: &id_type::OrganizationId,
        tenant_id: &id_type::TenantId,
    ) -> CustomResult<Self, errors::StorageError> {
        if let Some(role) = predefined_roles::PREDEFINED_ROLES.get(role_id) {
            Ok(role.clone())
        } else {
            state
                .global_store
                .find_by_role_id_org_id_tenant_id(role_id, org_id, tenant_id)
                .await
                .map(Self::from)
        }
    }
}

impl From<diesel_models::role::Role> for RoleInfo {
    fn from(role: diesel_models::role::Role) -> Self {
        Self {
            role_id: role.role_id,
            role_name: role.role_name,
            groups: role.groups,
            scope: role.scope,
            entity_type: role.entity_type,
            is_invitable: true,
            is_deletable: true,
            is_updatable: true,
            is_internal: false,
        }
    }
}


impl common_utils::events::ApiEventMetric for TokenDataResponse {}

impl common_utils::events::ApiEventMetric for for TokenDataResponse


File: crates/router/src/db/user_key_store.rs

use common_utils::{
    errors::CustomResult,
    types::keymanager::{self, KeyManagerState},
};
use error_stack::{report, ResultExt};
use masking::Secret;
use router_env::{instrument, tracing};
use storage_impl::MockDb;

use crate::{
    connection,
    core::errors,
    services::Store,
    types::domain::{
        self,
        behaviour::{Conversion, ReverseConversion},
    },
};

#[async_trait::async_trait]
pub trait UserKeyStoreInterface {
    async fn insert_user_key_store(
        &self,
        state: &KeyManagerState,
        user_key_store: domain::UserKeyStore,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<domain::UserKeyStore, errors::StorageError>;

    async fn get_user_key_store_by_user_id(
        &self,
        state: &KeyManagerState,
        user_id: &str,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<domain::UserKeyStore, errors::StorageError>;

    async fn get_all_user_key_store(
        &self,
        state: &KeyManagerState,
        key: &Secret<Vec<u8>>,
        from: u32,
        limit: u32,
    ) -> CustomResult<Vec<domain::UserKeyStore>, errors::StorageError>;
}

#[async_trait::async_trait]
impl UserKeyStoreInterface for Store {
    #[instrument(skip_all)]
    async fn insert_user_key_store(
        &self,
        state: &KeyManagerState,
        user_key_store: domain::UserKeyStore,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<domain::UserKeyStore, errors::StorageError> {
        let conn = connection::pg_connection_write(self).await?;
        let user_id = user_key_store.user_id.clone();
        user_key_store
            .construct_new()
            .await
            .change_context(errors::StorageError::EncryptionError)?
            .insert(&conn)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))?
            .convert(state, key, keymanager::Identifier::User(user_id))
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    #[instrument(skip_all)]
    async fn get_user_key_store_by_user_id(
        &self,
        state: &KeyManagerState,
        user_id: &str,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<domain::UserKeyStore, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;

        diesel_models::user_key_store::UserKeyStore::find_by_user_id(&conn, user_id)
            .await
            .map_err(|error| report!(errors::StorageError::from(error)))?
            .convert(state, key, keymanager::Identifier::User(user_id.to_owned()))
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    async fn get_all_user_key_store(
        &self,
        state: &KeyManagerState,
        key: &Secret<Vec<u8>>,
        from: u32,
        limit: u32,
    ) -> CustomResult<Vec<domain::UserKeyStore>, errors::StorageError> {
        let conn = connection::pg_connection_read(self).await?;

        let key_stores = diesel_models::user_key_store::UserKeyStore::get_all_user_key_stores(
            &conn, from, limit,
        )
        .await
        .map_err(|err| report!(errors::StorageError::from(err)))?;
        futures::future::try_join_all(key_stores.into_iter().map(|key_store| async {
            let user_id = key_store.user_id.clone();
            key_store
                .convert(state, key, keymanager::Identifier::User(user_id))
                .await
                .change_context(errors::StorageError::DecryptionError)
        }))
        .await
    }
}

#[async_trait::async_trait]
impl UserKeyStoreInterface for MockDb {
    #[instrument(skip_all)]
    async fn insert_user_key_store(
        &self,
        state: &KeyManagerState,
        user_key_store: domain::UserKeyStore,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<domain::UserKeyStore, errors::StorageError> {
        let mut locked_user_key_store = self.user_key_store.lock().await;

        if locked_user_key_store
            .iter()
            .any(|user_key| user_key.user_id == user_key_store.user_id)
        {
            Err(errors::StorageError::DuplicateValue {
                entity: "user_key_store",
                key: Some(user_key_store.user_id.clone()),
            })?;
        }

        let user_key_store = Conversion::convert(user_key_store)
            .await
            .change_context(errors::StorageError::MockDbError)?;
        locked_user_key_store.push(user_key_store.clone());
        let user_id = user_key_store.user_id.clone();
        user_key_store
            .convert(state, key, keymanager::Identifier::User(user_id))
            .await
            .change_context(errors::StorageError::DecryptionError)
    }

    async fn get_all_user_key_store(
        &self,
        state: &KeyManagerState,
        key: &Secret<Vec<u8>>,
        _from: u32,
        _limit: u32,
    ) -> CustomResult<Vec<domain::UserKeyStore>, errors::StorageError> {
        let user_key_store = self.user_key_store.lock().await;

        futures::future::try_join_all(user_key_store.iter().map(|user_key| async {
            let user_id = user_key.user_id.clone();
            user_key
                .to_owned()
                .convert(state, key, keymanager::Identifier::User(user_id))
                .await
                .change_context(errors::StorageError::DecryptionError)
        }))
        .await
    }

    #[instrument(skip_all)]
    async fn get_user_key_store_by_user_id(
        &self,
        state: &KeyManagerState,
        user_id: &str,
        key: &Secret<Vec<u8>>,
    ) -> CustomResult<domain::UserKeyStore, errors::StorageError> {
        self.user_key_store
            .lock()
            .await
            .iter()
            .find(|user_key_store| user_key_store.user_id == user_id)
            .cloned()
            .ok_or(errors::StorageError::ValueNotFound(format!(
                "No user_key_store is found for user_id={user_id}",
            )))?
            .convert(state, key, keymanager::Identifier::User(user_id.to_owned()))
            .await
            .change_context(errors::StorageError::DecryptionError)
    }
}


pub struct DeutschebankReversalRequest {
    kind: DeutschebankTransactionKind,
}


impl EuclidParsable for DummyOutput {
    fn parse_output(input: &str) -> ParseResult<&str, Self> {
        let string_w = sequence::delimited(
            skip_ws(complete::tag("\"")),
            complete::take_while(|c| c != '"'),
            skip_ws(complete::tag("\"")),
        );
        let full_sequence = multi::many0(sequence::preceded(
            skip_ws(complete::tag(",")),
            sequence::delimited(
                skip_ws(complete::tag("\"")),
                complete::take_while(|c| c != '"'),
                skip_ws(complete::tag("\"")),
            ),
        ));
        let sequence = sequence::pair(string_w, full_sequence);
        error::context(
            "dummy_strings",
            combinator::map(
                sequence::delimited(
                    skip_ws(complete::tag("[")),
                    sequence,
                    skip_ws(complete::tag("]")),
                ),
                |out: (&str, Vec<&str>)| {
                    let mut first = out.1;
                    first.insert(0, out.0);
                    let v = first.iter().map(|s| s.to_string()).collect();
                    Self { outputs: v }
                },
            ),
        )(input)
    }
}


pub async fn refund_retrieve_core(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    profile_id: Option<id_type::ProfileId>,
    request: refunds::RefundsRetrieveRequest,
    refund: diesel_refund::Refund,
) -> errors::RouterResult<diesel_refund::Refund> {
    let db = &*state.store;

    let key_manager_state = &(&state).into();
    core_utils::validate_profile_id_from_auth_layer(profile_id, &refund)?;
    let payment_id = &refund.payment_id;
    let payment_intent = db
        .find_payment_intent_by_id(
            key_manager_state,
            payment_id,
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;

    let active_attempt_id = payment_intent
        .active_attempt_id
        .clone()
        .ok_or(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Active attempt id not found")?;

    let payment_attempt = db
        .find_payment_attempt_by_id(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            &active_attempt_id,
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::InternalServerError)?;

    let unified_translated_message = if let (Some(unified_code), Some(unified_message)) =
        (refund.unified_code.clone(), refund.unified_message.clone())
    {
        helpers::get_unified_translation(
            &state,
            unified_code,
            unified_message.clone(),
            state.locale.to_string(),
        )
        .await
        .or(Some(unified_message))
    } else {
        refund.unified_message
    };

    let refund = diesel_refund::Refund {
        unified_message: unified_translated_message,
        ..refund
    };

    let response = if should_call_refund(&refund, request.force_sync.unwrap_or(false)) {
        if state.conf.merchant_id_auth.merchant_id_auth_enabled {
            let merchant_connector_details = match request.merchant_connector_details {
                Some(details) => details,
                None => {
                    return Err(report!(errors::ApiErrorResponse::MissingRequiredField {
                        field_name: "merchant_connector_details"
                    }));
                }
            };
            Box::pin(internal_sync_refund_with_gateway(
                &state,
                &merchant_context,
                &payment_attempt,
                &payment_intent,
                &refund,
                merchant_connector_details,
            ))
            .await
        } else {
            Box::pin(sync_refund_with_gateway(
                &state,
                &merchant_context,
                &payment_attempt,
                &payment_intent,
                &refund,
            ))
            .await
        }
    } else {
        Ok(refund)
    }?;
    Ok(response)
}


pub async fn update(self, conn: &PgPooledConn, refund: RefundUpdate) -> StorageResult<Self> {
        match generics::generic_update_with_unique_predicate_get_result::<
            <Self as HasTable>::Table,
            _,
            _,
            _,
        >(
            conn,
            dsl::refund_id
                .eq(self.refund_id.to_owned())
                .and(dsl::merchant_id.eq(self.merchant_id.to_owned())),
            RefundUpdateInternal::from(refund),
        )
        .await
        {
            Err(error) => match error.current_context() {
                errors::DatabaseError::NoFieldsToUpdate => Ok(self),
                _ => Err(error),
            },
            result => result,
        }
    }


impl ConnectorInfo {
    pub fn new(gateway_name: String, gateway_id: Option<String>) -> Self {
        Self {
            gateway_name,
            gateway_id,
        }
    }
}


impl StorageInterface for KafkaStore {
    fn get_scheduler_db(&self) -> Box<dyn SchedulerInterface> {
        Box::new(self.clone())
    }

    fn get_payment_methods_store(&self) -> Box<dyn PaymentMethodsStorageInterface> {
        Box::new(self.clone())
    }

    fn get_cache_store(&self) -> Box<(dyn RedisConnInterface + Send + Sync + 'static)> {
        Box::new(self.clone())
    }
}

impl StorageInterface for for KafkaStore


impl api::PaymentCapture for Bluecode {}

impl api::PaymentCapture for for Bluecode


pub struct DeutschebankRouterData<T> {
    pub amount: MinorUnit,
    pub router_data: T,
}


pub fn payments_create_request_validation(
    req: &api::PaymentsRequest,
) -> RouterResult<(api::Amount, enums::Currency)> {
    let currency = req.currency.get_required_value("currency")?;
    let amount = req.amount.get_required_value("amount")?;
    Ok((amount, currency))
}


pub fn skip_ws<'a, F, O>(inner: F) -> impl FnMut(&'a str) -> ParseResult<&'a str, O>
where
    F: FnMut(&'a str) -> ParseResult<&'a str, O> + 'a,
{
    sequence::preceded(pchar::multispace0, inner)
}


impl PaymentSync for Threedsecureio {}


Documentation: api-reference/v2/payment-methods/payment-method--list-customer-saved-payment-methods.mdx
# Type: Doc File

---
openapi: get /v2/customers/{id}/saved-payment-methods
---


Documentation: api-reference/introduction.mdx
# Type: Doc File

---
tags: "Getting Started"
title: "👋 Welcome to Hyperswitch API Reference"
sidebarTitle: "Introduction"
stoplight-id: "3lmsk7ocvq21v"
icon: "rectangle-code"
iconType: "solid"
---

Hyperswitch provides a collection of APIs that enable you to process and manage payments. Our APIs accept and return JSON in the HTTP body and return standard HTTP response codes. You can consume the APIs directly using your favorite HTTP/REST library.

<CardGroup cols={2}>
  <Card title="Try a Payment" icon="money-bill" horizontal={false} href="https://api-reference.hyperswitch.io/v1/payments/payments--create">
    Create your first payment using Hyperswitch APIs.
  </Card>
  <Card title="Payment Flows" icon="receipt" horizontal={false} href="https://api-reference.hyperswitch.io/v1/payments/payment--flows">
    Discover how to process one-time and recurring payments, save payment methods, and more.
  </Card>
  <Card title="Save a payment method" icon="vault" iconType="regular" horizontal={false} href="https://api-reference.hyperswitch.io/v1/payment-methods/paymentmethods--create">
    Save customer payment methods securely for future transactions
  </Card>
  <Card title="Self Hosted?" icon="circle-down" horizontal={false} href="https://api-reference.hyperswitch.io/v1/organization/organization--create">
    Host Hyperswitch on-premise? Utilize our full API suite.
  </Card>
</CardGroup>

## Environment

We have a testing environment referred to <Tooltip tip="Testing environment!">"sandbox</Tooltip>," which you can set up to test API calls without affecting production data. You can sign up on our Dashboard to get API keys to access Hyperswitch API.

Use the following base URLs when making requests to the APIs:

| Environment | Base URL                       |
| ----------- | ------------------------------ |
| Sandbox     | https://sandbox.hyperswitch.io |
| Production  | https://api.hyperswitch.io     |

<Note>
  If you **do not hold a PCI certification** to collect and store card data on your servers, we recommend using [**Unified Checkout**](https://hyperswitch.io/docs/sdkIntegrations/unifiedCheckoutWeb/#unified-checkout) to accept card information from users.
</Note>

## Authentication and API keys

Hyperswitch authenticates your API requests using your account’s API keys. Each account has two API keys for authentication:

| Key                  | Example         | When to Use                                                                                |
| -------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Secret key (API-key) | `snd_c69***`    | Used to authenticate API requests from your merchant server. **Don’t expose this key** on a website or embed it in a mobile application. |
| Publishable key      | `pk_snd_3b3***` | Used to authenticate API requests from your app’s client. Can be publicly-accessible in your web or mobile app’s client-side code.       |

<Check>
  Get your [API key](https://app.hyperswitch.io/developers?tabIndex=1) and [Publishable Key](https://app.hyperswitch.io/home)
</Check>

<Check>
  [Postman Collection](https://www.postman.com/hyperswitch/workspace/hyperswitch-development/collection/25176162-630b5353-7002-44d1-8ba1-ead6c230f2e3)
</Check>

## Payment Status Lifecycle

Hyperswitch handles the complex functionality of a comprehensive payments flow through the Payments object that transitions through multiple states during its payments lifecycle. Given below are the various statuses a payment can have:

| Payment Status           | Description                                                                                |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| requires_payment_method  | Once you create a payment through payments/create endpoint with no payment method attached to it, the payments object transitions to ‘requires_payment_method’.                                             |
| requires_confirmation    | After attaching a payment method through payments/update endpoint, the payments object requires you to confirm the payment.                                                                                |
| requires_customer_action | Once the payment is confirmed through payments/confirm endpoint, if additional authentication is required, the payments object transitions to this state.                                                   |
| requires_capture         | If you want to do separate authorize and capture, setting capture field to ‘manual’ during payments/create or confirm call will transition the payment object to this state after customer action succeeds. |
| processing               | In case of automatic capture, the payments object transitions to processing state post confirm call and subsequent customer authentication if available.                                                    |
| succeeded                | The payments object reaches success state post confirmation of successful processing from the payment processor.                                                                                |
| failed                   | The payments object transitions to a failed state when the payment processor confirms the processing failure.                                                                                |
| expired                  | You can expire the payments object while it is in any state except when it is under ‘processing’ or ‘succeeded’ state.                                                                                |

## Redirect URL

This is what a url looks like after redirection

`https://app.hyperswitch.io?status=succeeded&payment_intent_client_secret=pay_NCv9vc19f8aa75OpFxH8_secret_V4zAc7V0C8WAw6FECMKM&amount=10000&manual_retry_allowed=false&signature=4fae0cfa775e4551db9356563d4b98b55662fe3c1c945fe215d90ccf3541282c535909ae901d82174d6b1e46ba1684aa0aa4c8861be0e2a9ef6f950a975d5014&signature_algorithm=HMAC-SHA512`

The available parameters are as follows:

- **status** - can have values of `succeeded`, `processing`and `failed`.
- **payment_intent_client_secret** - This is the client secret associated with the payment. This can be used to retrieve the payment status from hyperswitch.
- **manual_retry_allowed** - whether this payment can be retried or not.
- **signature** - A HMAC signature of the payload, this can be verified using the `payment_response_hash_key`.
- **signature_algorithm** - The HMAC algorithm used to calculate the signature.


pub struct RoutableConnectors(Vec<routing_types::RoutableConnectorChoice>);


impl Responder {
    use hyperswitch_domain_models::payments::PaymentStatusData;

    let flow = match payload.force_sync {
        true => Flow::PaymentsRetrieveForceSync,
        false => Flow::PaymentsRetrieve,
    };
    tracing::Span::current().record("flow", flow.to_string());

    let global_payment_id = path.into_inner();
    tracing::Span::current().record("payment_id", global_payment_id.get_string_repr());

    let internal_payload = internal_payload_types::PaymentsGenericRequestWithResourceId {
        global_payment_id,
        payload: payload.into_inner(),
    };

    let header_payload = match HeaderPayload::foreign_try_from(req.headers()) {
        Ok(headers) => headers,
        Err(err) => {
            return api::log_and_return_error_response(err);
        }
    };

    let locking_action = internal_payload.get_locking_input(flow.clone());

    let auth_type = if state.conf.merchant_id_auth.merchant_id_auth_enabled {
        &auth::MerchantIdAuth
    } else {
        match env::which() {
            env::Env::Production => &auth::V2ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            },
            _ => auth::auth_type(
                &auth::V2ApiKeyAuth {
                    is_connected_allowed: false,
                    is_platform_allowed: false,
                },
                &auth::JWTAuth {
                    permission: Permission::ProfilePaymentWrite,
                },
                req.headers(),
            ),
        }
    };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        internal_payload,
        |state, auth: auth::AuthenticationData, req, req_state| async {
            let payment_id = req.global_payment_id;
            let request = req.payload;

            let operation = payments::operations::PaymentGet;

            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            Box::pin(payments::payments_core::<
                api_types::PSync,
                api_models::payments::PaymentsResponse,
                _,
                _,
                _,
                PaymentStatusData<api_types::PSync>,
            >(
                state,
                req_state,
                merchant_context,
                auth.profile,
                operation,
                request,
                payment_id,
                payments::CallConnectorAction::Trigger,
                header_payload.clone(),
            ))
            .await
        },
        auth_type,
        locking_action,
    ))
    .await
}


pub async fn api_key_create(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<api_types::CreateApiKeyRequest>,
) -> impl Responder {
    let flow = Flow::ApiKeyCreate;
    let payload = json_payload.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth::AuthenticationDataWithoutProfile { key_store, .. }, payload, _| async {
            api_keys::create_api_key(state, payload, key_store).await
        },
        auth::auth_type(
            &auth::AdminApiAuthWithMerchantIdFromHeader,
            &auth::JWTAuthMerchantFromHeader {
                required_permission: Permission::MerchantApiKeyWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub fn server(state: AppState) -> Scope {
        web::scope("/files")
            .app_data(web::Data::new(state))
            .service(web::resource("").route(web::post().to(files::files_create)))
            .service(
                web::resource("/{file_id}")
                    .route(web::delete().to(files::files_delete))
                    .route(web::get().to(files::files_retrieve)),
            )
    }


pub trait SdkEventMetricAnalytics: LoadRow<SdkEventMetricRow> {}


pub async fn get_total_saved_payment_methods_for_merchant(
    state: SessionState,
    merchant_context: domain::MerchantContext,
) -> RouterResponse<api::TotalPaymentMethodCountResponse> {
    let total_payment_method_count =
        get_total_payment_method_count_core(&state, &merchant_context).await?;

    Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
        total_payment_method_count,
    ))
}


/// Trait defining the states of a secret
pub trait SecretState {}


impl api::MandateSetup for Mollie {}


OpenAPI Block Path: components.schemas.PaymentsSessionRequest
{
  "type": "object",
  "required": [
    "payment_id",
    "client_secret",
    "wallets"
  ],
  "properties": {
    "payment_id": {
      "type": "string",
      "description": "The identifier for the payment"
    },
    "client_secret": {
      "type": "string",
      "description": "This is a token which expires after 15 minutes, used from the client to authenticate and create sessions from the SDK"
    },
    "wallets": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/PaymentMethodType"
      },
      "description": "The list of the supported wallets"
    },
    "merchant_connector_details": {
      "allOf": [
        {
          "$ref": "#/components/schemas/MerchantConnectorDetailsWrap"
        }
      ],
      "nullable": true
    }
  }
}