        } else {
            None
        }
        .map(|data| {
            serde_json::to_value(types::AdditionalMerchantData::OpenBankingRecipientData(
                data,
            ))
        })
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to serialize MerchantRecipientData")?;

        let encrypted_data = domain_types::crypto_operation(
            key_manager_state,
            type_name!(domain::MerchantConnectorAccount),
            domain_types::CryptoOperation::BatchEncrypt(
                FromRequestEncryptableMerchantConnectorAccount::to_encryptable(
                    FromRequestEncryptableMerchantConnectorAccount {
                        connector_account_details: self.connector_account_details.ok_or(
                            errors::ApiErrorResponse::MissingRequiredField {
                                field_name: "connector_account_details",
                            },
                        )?,
                        connector_wallets_details:
                            helpers::get_connector_wallets_details_with_apple_pay_certificates(
                                &self.metadata,
                                &self.connector_wallets_details,
                            )
                            .await?,
                        additional_merchant_data: merchant_recipient_data.map(Secret::new),
                    },
                ),
            ),
            identifier.clone(),
            key_store.key.peek(),
        )
        .await
        .and_then(|val| val.try_into_batchoperation())
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed while decrypting connector account details".to_string())?;

        let encrypted_data =
            FromRequestEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data)
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed while decrypting connector account details")?;

        let feature_metadata = self
            .feature_metadata
            .as_ref()
            .map(ForeignTryFrom::foreign_try_from)
            .transpose()?;
        Ok(domain::MerchantConnectorAccount {
            merchant_id: business_profile.merchant_id.clone(),
            connector_type: self.connector_type,
            connector_name: self.connector_name,
            connector_account_details: encrypted_data.connector_account_details,
            payment_methods_enabled,
            disabled,
            metadata: self.metadata.clone(),
            frm_configs,
            connector_label: Some(connector_label.clone()),
            created_at: date_time::now(),
            modified_at: date_time::now(),
            id: common_utils::generate_merchant_connector_account_id_of_default_length(),
            connector_webhook_details: match self.connector_webhook_details {
                Some(connector_webhook_details) => {
                    connector_webhook_details.encode_to_value(
                    )
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable(format!("Failed to serialize api_models::admin::MerchantConnectorWebhookDetails for Merchant: {:?}", business_profile.merchant_id))
                    .map(Some)?
                    .map(Secret::new)
                }
                None => None,
            },
            profile_id: business_profile.get_id().to_owned(),
            applepay_verified_domains: None,
            pm_auth_config: self.pm_auth_config.clone(),
            status: connector_status,
            connector_wallets_details: encrypted_data.connector_wallets_details,
            additional_merchant_data: encrypted_data.additional_merchant_data,
            version: common_types::consts::API_VERSION,
            feature_metadata,
        })
    }

    async fn validate_and_get_business_profile(
        self,
        merchant_context: &domain::MerchantContext,
        db: &dyn StorageInterface,
        key_manager_state: &KeyManagerState,
    ) -> RouterResult<domain::Profile> {
        let profile_id = self.profile_id;
        // Check whether this profile belongs to the merchant

        let business_profile = core_utils::validate_and_get_business_profile(
            db,
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            Some(&profile_id),
            merchant_context.get_merchant_account().get_id(),
        )
        .await?
        .get_required_value("Profile")
        .change_context(errors::ApiErrorResponse::ProfileNotFound {
            id: profile_id.get_string_repr().to_owned(),
        })?;

        Ok(business_profile)
    }
}

#[cfg(feature = "v1")]
struct PaymentMethodsEnabled<'a> {
    payment_methods_enabled: &'a Option<Vec<api_models::admin::PaymentMethodsEnabled>>,
}

#[cfg(feature = "v1")]
impl PaymentMethodsEnabled<'_> {
    fn get_payment_methods_enabled(&self) -> RouterResult<Option<Vec<pii::SecretSerdeValue>>> {
        let mut vec = Vec::new();
        let payment_methods_enabled = match self.payment_methods_enabled.clone() {
            Some(val) => {
                for pm in val.into_iter() {
                    let pm_value = pm
                        .encode_to_value()
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable(
                            "Failed while encoding to serde_json::Value, PaymentMethod",
                        )?;
                    vec.push(Secret::new(pm_value))
                }
                Some(vec)
            }
            None => None,
        };
        Ok(payment_methods_enabled)
    }
}

#[cfg(all(feature = "v1", feature = "olap"))]
#[async_trait::async_trait]
impl MerchantConnectorAccountCreateBridge for api::MerchantConnectorCreate {
    async fn create_domain_model_from_request(
        self,
        state: &SessionState,
        key_store: domain::MerchantKeyStore,
        business_profile: &domain::Profile,
        key_manager_state: &KeyManagerState,
    ) -> RouterResult<domain::MerchantConnectorAccount> {
        // If connector label is not passed in the request, generate one
        let connector_label = self
            .connector_label
            .clone()
            .or(core_utils::get_connector_label(
                self.business_country,
                self.business_label.as_ref(),
                self.business_sub_label.as_ref(),
                &self.connector_name.to_string(),
            ))
            .unwrap_or(format!(
                "{}_{}",
                self.connector_name, business_profile.profile_name
            ));
        let payment_methods_enabled = PaymentMethodsEnabled {
            payment_methods_enabled: &self.payment_methods_enabled,
        };
        let payment_methods_enabled = payment_methods_enabled.get_payment_methods_enabled()?;
        let frm_configs = self.get_frm_config_as_secret();
        // Validate Merchant api details and return error if not in correct format
        let auth = types::ConnectorAuthType::from_option_secret_value(
            self.connector_account_details.clone(),
        )
        .change_context(errors::ApiErrorResponse::InvalidDataFormat {
            field_name: "connector_account_details".to_string(),
            expected_format: "auth_type and api_key".to_string(),
        })?;

        let connector_auth_type_and_metadata_validation = ConnectorAuthTypeAndMetadataValidation {
            connector_name: &self.connector_name,
            auth_type: &auth,
            connector_meta_data: &self.metadata,
        };
        connector_auth_type_and_metadata_validation.validate_auth_and_metadata_type()?;
        let connector_status_and_disabled_validation = ConnectorStatusAndDisabledValidation {
            status: &self.status,
            disabled: &self.disabled,
            auth: &auth,
            current_status: &api_enums::ConnectorStatus::Active,
        };
        let (connector_status, disabled) =
            connector_status_and_disabled_validation.validate_status_and_disabled()?;
        let identifier = km_types::Identifier::Merchant(business_profile.merchant_id.clone());
        let merchant_recipient_data = if let Some(data) = &self.additional_merchant_data {
            Some(
                process_open_banking_connectors(
                    state,
                    &business_profile.merchant_id,
                    &auth,
                    &self.connector_type,
                    &self.connector_name,
                    types::AdditionalMerchantData::foreign_from(data.clone()),
                    &key_store,
                )
                .await?,
            )
        } else {
            None
        }
        .map(|data| {
            serde_json::to_value(types::AdditionalMerchantData::OpenBankingRecipientData(
                data,
            ))
        })
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed to serialize MerchantRecipientData")?;

        let encrypted_data = domain_types::crypto_operation(
            key_manager_state,
            type_name!(domain::MerchantConnectorAccount),
            domain_types::CryptoOperation::BatchEncrypt(
                FromRequestEncryptableMerchantConnectorAccount::to_encryptable(
                    FromRequestEncryptableMerchantConnectorAccount {
                        connector_account_details: self.connector_account_details.ok_or(
                            errors::ApiErrorResponse::MissingRequiredField {
                                field_name: "connector_account_details",
                            },
                        )?,
                        connector_wallets_details:
                            helpers::get_connector_wallets_details_with_apple_pay_certificates(
                                &self.metadata,
                                &self.connector_wallets_details,
                            )
                            .await?,
                        additional_merchant_data: merchant_recipient_data.map(Secret::new),
                    },
                ),
            ),
            identifier.clone(),
            key_store.key.peek(),
        )
        .await
        .and_then(|val| val.try_into_batchoperation())
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Failed while decrypting connector account details".to_string())?;

        let encrypted_data =
            FromRequestEncryptableMerchantConnectorAccount::from_encryptable(encrypted_data)
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed while decrypting connector account details")?;

        Ok(domain::MerchantConnectorAccount {
            merchant_id: business_profile.merchant_id.clone(),
            connector_type: self.connector_type,
            connector_name: self.connector_name.to_string(),
            merchant_connector_id: common_utils::generate_merchant_connector_account_id_of_default_length(),
            connector_account_details: encrypted_data.connector_account_details,
            payment_methods_enabled,
            disabled,
            metadata: self.metadata.clone(),
            frm_configs,
            connector_label: Some(connector_label.clone()),
            created_at: date_time::now(),
            modified_at: date_time::now(),
            connector_webhook_details: match self.connector_webhook_details {
                Some(connector_webhook_details) => {
                    connector_webhook_details.encode_to_value(
                    )
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable(format!("Failed to serialize api_models::admin::MerchantConnectorWebhookDetails for Merchant: {:?}", business_profile.merchant_id))
                    .map(Some)?
                    .map(Secret::new)
                }
                None => None,
            },
            profile_id: business_profile.get_id().to_owned(),
            applepay_verified_domains: None,
            pm_auth_config: self.pm_auth_config.clone(),
            status: connector_status,
            connector_wallets_details: encrypted_data.connector_wallets_details,
            test_mode: self.test_mode,
            business_country: self.business_country,
            business_label: self.business_label.clone(),
            business_sub_label: self.business_sub_label.clone(),
            additional_merchant_data: encrypted_data.additional_merchant_data,
            version: common_types::consts::API_VERSION,
        })
    }

    /// If profile_id is not passed, use default profile if available, or
    /// If business_details (business_country and business_label) are passed, get the business_profile
    /// or return a `MissingRequiredField` error
    async fn validate_and_get_business_profile(
        self,
        merchant_context: &domain::MerchantContext,
        db: &dyn StorageInterface,
        key_manager_state: &KeyManagerState,
    ) -> RouterResult<domain::Profile> {
        match self.profile_id.or(merchant_context
            .get_merchant_account()
            .default_profile
            .clone())
        {
            Some(profile_id) => {
                // Check whether this business profile belongs to the merchant

                let business_profile = core_utils::validate_and_get_business_profile(
                    db,
                    key_manager_state,
                    merchant_context.get_merchant_key_store(),
                    Some(&profile_id),
                    merchant_context.get_merchant_account().get_id(),
                )
                .await?
                .get_required_value("Profile")
                .change_context(errors::ApiErrorResponse::ProfileNotFound {
                    id: profile_id.get_string_repr().to_owned(),
                })?;

                Ok(business_profile)
            }
            None => match self.business_country.zip(self.business_label) {
                Some((business_country, business_label)) => {
                    let profile_name = format!("{business_country}_{business_label}");
                    let business_profile = db
                        .find_business_profile_by_profile_name_merchant_id(
                            key_manager_state,
                            merchant_context.get_merchant_key_store(),
                            &profile_name,
                            merchant_context.get_merchant_account().get_id(),
                        )
                        .await
                        .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound {
                            id: profile_name,
                        })?;

                    Ok(business_profile)
                }
                _ => Err(report!(errors::ApiErrorResponse::MissingRequiredField {
                    field_name: "profile_id or business_country, business_label"
                })),
            },
        }
    }
}

pub async fn create_connector(
    state: SessionState,
    req: api::MerchantConnectorCreate,
    merchant_context: domain::MerchantContext,
    auth_profile_id: Option<id_type::ProfileId>,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
    let store = state.store.as_ref();
    let key_manager_state = &(&state).into();
    #[cfg(feature = "dummy_connector")]
    fp_utils::when(
        req.connector_name
            .validate_dummy_connector_create(state.conf.dummy_connector.enabled),
        || {
            Err(errors::ApiErrorResponse::InvalidRequestData {
                message: "Invalid connector name".to_string(),
            })
        },
    )?;

    let connector_metadata = ConnectorMetadata {
        connector_metadata: &req.metadata,
    };

    let merchant_id = merchant_context.get_merchant_account().get_id();

    connector_metadata.validate_apple_pay_certificates_in_mca_metadata()?;

    #[cfg(feature = "v1")]
    helpers::validate_business_details(
        req.business_country,
        req.business_label.as_ref(),
        &merchant_context,
    )?;

    let business_profile = req
        .clone()
        .validate_and_get_business_profile(&merchant_context, store, key_manager_state)
        .await?;

    #[cfg(feature = "v2")]
    if req.connector_type == common_enums::ConnectorType::BillingProcessor {
        let profile_wrapper = ProfileWrapper::new(business_profile.clone());
        profile_wrapper
            .update_revenue_recovery_algorithm_under_profile(
                store,
                key_manager_state,
                merchant_context.get_merchant_key_store(),
                common_enums::RevenueRecoveryAlgorithmType::Monitoring,
            )
            .await?;
    }
    core_utils::validate_profile_id_from_auth_layer(auth_profile_id, &business_profile)?;

    let pm_auth_config_validation = PMAuthConfigValidation {
        connector_type: &req.connector_type,
        pm_auth_config: &req.pm_auth_config,
        db: store,
        merchant_id,
        profile_id: business_profile.get_id(),
        key_store: merchant_context.get_merchant_key_store(),
        key_manager_state,
    };
    pm_auth_config_validation.validate_pm_auth_config().await?;

    let connector_type_and_connector_enum = ConnectorTypeAndConnectorName {
        connector_type: &req.connector_type,
        connector_name: &req.connector_name,
    };
    let routable_connector = connector_type_and_connector_enum.get_routable_connector()?;

    // The purpose of this merchant account update is just to update the
    // merchant account `modified_at` field for KGraph cache invalidation
    state
        .store
        .update_specific_fields_in_merchant(
            key_manager_state,
            merchant_id,
            storage::MerchantAccountUpdate::ModifiedAtUpdate,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("error updating the merchant account when creating payment connector")?;

    let merchant_connector_account = req
        .clone()
        .create_domain_model_from_request(
            &state,
            merchant_context.get_merchant_key_store().clone(),
            &business_profile,
            key_manager_state,
        )
        .await?;

    let mca = state
        .store
        .insert_merchant_connector_account(
            key_manager_state,
            merchant_connector_account.clone(),
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_duplicate_response(
            errors::ApiErrorResponse::DuplicateMerchantConnectorAccount {
                profile_id: business_profile.get_id().get_string_repr().to_owned(),
                connector_label: merchant_connector_account
                    .connector_label
                    .unwrap_or_default(),
            },
        )?;

    #[cfg(feature = "v1")]
    disputes::schedule_dispute_sync_task(&state, &business_profile, &mca).await?;

    #[cfg(feature = "v1")]
    //update merchant default config
    let merchant_default_config_update = MerchantDefaultConfigUpdate {
        routable_connector: &routable_connector,
        merchant_connector_id: &mca.get_id(),
        store,
        merchant_id,
        profile_id: business_profile.get_id(),
        transaction_type: &req.get_transaction_type(),
    };

    #[cfg(feature = "v2")]
    //update merchant default config
    let merchant_default_config_update = DefaultFallbackRoutingConfigUpdate {
        routable_connector: &routable_connector,
        merchant_connector_id: &mca.get_id(),
        store,
        business_profile,
        key_store: merchant_context.get_merchant_key_store().to_owned(),
        key_manager_state,
    };

    merchant_default_config_update
        .retrieve_and_update_default_fallback_routing_algorithm_if_routable_connector_exists()
        .await?;

    metrics::MCA_CREATE.add(
        1,
        router_env::metric_attributes!(
            ("connector", req.connector_name.to_string()),
            ("merchant", merchant_id.clone()),
        ),
    );

    let mca_response = mca.foreign_try_into()?;
    Ok(service_api::ApplicationResponse::Json(mca_response))
}

#[cfg(feature = "v1")]
async fn validate_pm_auth(
    val: pii::SecretSerdeValue,
    state: &SessionState,
    merchant_id: &id_type::MerchantId,
    merchant_context: domain::MerchantContext,
    profile_id: &id_type::ProfileId,
) -> RouterResponse<()> {
    let config =
        serde_json::from_value::<api_models::pm_auth::PaymentMethodAuthConfig>(val.expose())
            .change_context(errors::ApiErrorResponse::InvalidRequestData {
                message: "invalid data received for payment method auth config".to_string(),
            })
            .attach_printable("Failed to deserialize Payment Method Auth config")?;

    let all_mcas = state
        .store
        .find_merchant_connector_account_by_merchant_id_and_disabled_list(
            &state.into(),
            merchant_id,
            true,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .change_context(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: merchant_context
                .get_merchant_account()
                .get_id()
                .get_string_repr()
                .to_owned(),
        })?;

    for conn_choice in config.enabled_payment_methods {
        let pm_auth_mca = all_mcas
            .iter()
            .find(|mca| mca.get_id() == conn_choice.mca_id)
            .ok_or(errors::ApiErrorResponse::GenericNotFoundError {
                message: "payment method auth connector account not found".to_string(),
            })?;

        if &pm_auth_mca.profile_id != profile_id {
            return Err(errors::ApiErrorResponse::GenericNotFoundError {
                message: "payment method auth profile_id differs from connector profile_id"
                    .to_string(),
            }
            .into());
        }
    }

    Ok(services::ApplicationResponse::StatusOk)
}

#[cfg(feature = "v1")]
pub async fn retrieve_connector(
    state: SessionState,
    merchant_id: id_type::MerchantId,
    profile_id: Option<id_type::ProfileId>,
    merchant_connector_id: id_type::MerchantConnectorAccountId,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
    let store = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = store
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &store.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let _merchant_account = store
        .find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let mca = store
        .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
            key_manager_state,
            &merchant_id,
            &merchant_connector_id,
            &key_store,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: merchant_connector_id.get_string_repr().to_string(),
        })?;
    core_utils::validate_profile_id_from_auth_layer(profile_id, &mca)?;

    Ok(service_api::ApplicationResponse::Json(
        mca.foreign_try_into()?,
    ))
}

#[cfg(feature = "v2")]
pub async fn retrieve_connector(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    id: id_type::MerchantConnectorAccountId,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
    let store = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let merchant_id = merchant_context.get_merchant_account().get_id();

    let mca = store
        .find_merchant_connector_account_by_id(
            key_manager_state,
            &id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: id.clone().get_string_repr().to_string(),
        })?;

    // Validate if the merchant_id sent in the request is valid
    if mca.merchant_id != *merchant_id {
        return Err(errors::ApiErrorResponse::InvalidRequestData {
            message: format!(
                "Invalid merchant_id {} provided for merchant_connector_account {:?}",
                merchant_id.get_string_repr(),
                id
            ),
        }
        .into());
    }

    Ok(service_api::ApplicationResponse::Json(
        mca.foreign_try_into()?,
    ))
}

#[cfg(all(feature = "olap", feature = "v2"))]
pub async fn list_connectors_for_a_profile(
    state: SessionState,
    key_store: domain::MerchantKeyStore,
    profile_id: id_type::ProfileId,
) -> RouterResponse<Vec<api_models::admin::MerchantConnectorListResponse>> {
    let store = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let merchant_connector_accounts = store
        .list_connector_account_by_profile_id(key_manager_state, &profile_id, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::InternalServerError)?;
    let mut response = vec![];

    for mca in merchant_connector_accounts.into_iter() {
        response.push(mca.foreign_try_into()?);
    }

    Ok(service_api::ApplicationResponse::Json(response))
}

pub async fn list_payment_connectors(
    state: SessionState,
    merchant_id: id_type::MerchantId,
    profile_id_list: Option<Vec<id_type::ProfileId>>,
) -> RouterResponse<Vec<api_models::admin::MerchantConnectorListResponse>> {
    let store = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = store
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &store.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    // Validate merchant account
    store
        .find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let merchant_connector_accounts = store
        .find_merchant_connector_account_by_merchant_id_and_disabled_list(
            key_manager_state,
            &merchant_id,
            true,
            &key_store,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::InternalServerError)?;
    let merchant_connector_accounts = core_utils::filter_objects_based_on_profile_id_list(
        profile_id_list,
        merchant_connector_accounts,
    );
    let mut response = vec![];

    // The can be eliminated once [#79711](https://github.com/rust-lang/rust/issues/79711) is stabilized
    for mca in merchant_connector_accounts.into_iter() {
        response.push(mca.foreign_try_into()?);
    }

    Ok(service_api::ApplicationResponse::Json(response))
}

pub async fn update_connector(
    state: SessionState,
    merchant_id: &id_type::MerchantId,
    profile_id: Option<id_type::ProfileId>,
    merchant_connector_id: &id_type::MerchantConnectorAccountId,
    req: api_models::admin::MerchantConnectorUpdate,
) -> RouterResponse<api_models::admin::MerchantConnectorResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = db
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            merchant_id,
            &db.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, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let mca = req
        .clone()
        .get_merchant_connector_account_from_id(
            db,
            merchant_id,
            merchant_connector_id,
            &key_store,
            key_manager_state,
        )
        .await?;
    core_utils::validate_profile_id_from_auth_layer(profile_id, &mca)?;

    let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(domain::Context(
        merchant_account.clone(),
        key_store.clone(),
    )));
    let payment_connector = req
        .clone()
        .create_domain_model_from_request(&state, &mca, key_manager_state, &merchant_context)
        .await?;

    // Profile id should always be present
    let profile_id = mca.profile_id.clone();

    let request_connector_label = req.connector_label;

    let updated_mca = db
        .update_merchant_connector_account(
            key_manager_state,
            mca,
            payment_connector.into(),
            &key_store,
        )
        .await
        .change_context(
            errors::ApiErrorResponse::DuplicateMerchantConnectorAccount {
                profile_id: profile_id.get_string_repr().to_owned(),
                connector_label: request_connector_label.unwrap_or_default(),
            },
        )
        .attach_printable_lazy(|| {
            format!(
                "Failed while updating MerchantConnectorAccount: id: {merchant_connector_id:?}",

            )
        })?;

    let response = updated_mca.foreign_try_into()?;

    Ok(service_api::ApplicationResponse::Json(response))
}

#[cfg(feature = "v1")]
pub async fn delete_connector(
    state: SessionState,
    merchant_id: id_type::MerchantId,
    merchant_connector_id: id_type::MerchantConnectorAccountId,
) -> RouterResponse<api::MerchantConnectorDeleteResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = db
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &db.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, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let mca = db
        .find_by_merchant_connector_account_merchant_id_merchant_connector_id(
            key_manager_state,
            &merchant_id,
            &merchant_connector_id,
            &key_store,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: merchant_connector_id.get_string_repr().to_string(),
        })?;

    let is_deleted = db
        .delete_merchant_connector_account_by_merchant_id_merchant_connector_id(
            &merchant_id,
            &merchant_connector_id,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: merchant_connector_id.get_string_repr().to_string(),
        })?;

    // delete the mca from the config as well
    let merchant_default_config_delete = MerchantDefaultConfigUpdate {
        routable_connector: &Some(
            common_enums::RoutableConnectors::from_str(&mca.connector_name).map_err(|_| {
                errors::ApiErrorResponse::InvalidDataValue {
                    field_name: "connector_name",
                }
            })?,
        ),
        merchant_connector_id: &mca.get_id(),
        store: db,
        merchant_id: &merchant_id,
        profile_id: &mca.profile_id,
        transaction_type: &mca.connector_type.into(),
    };

    merchant_default_config_delete
        .retrieve_and_delete_from_default_fallback_routing_algorithm_if_routable_connector_exists()
        .await?;

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

#[cfg(feature = "v2")]
pub async fn delete_connector(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    id: id_type::MerchantConnectorAccountId,
) -> RouterResponse<api::MerchantConnectorDeleteResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();

    let merchant_id = merchant_context.get_merchant_account().get_id();

    let mca = db
        .find_merchant_connector_account_by_id(
            key_manager_state,
            &id,
            merchant_context.get_merchant_key_store(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: id.clone().get_string_repr().to_string(),
        })?;

    // Validate if the merchant_id sent in the request is valid
    if mca.merchant_id != *merchant_id {
        return Err(errors::ApiErrorResponse::InvalidRequestData {
            message: format!(
                "Invalid merchant_id {} provided for merchant_connector_account {:?}",
                merchant_id.get_string_repr(),
                id
            ),
        }
        .into());
    }

    let is_deleted = db
        .delete_merchant_connector_account_by_id(&id)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantConnectorAccountNotFound {
            id: id.clone().get_string_repr().to_string(),
        })?;

    let business_profile = db
        .find_business_profile_by_profile_id(
            key_manager_state,
            merchant_context.get_merchant_key_store(),
            &mca.profile_id,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::ProfileNotFound {
            id: mca.profile_id.get_string_repr().to_owned(),
        })?;

    let merchant_default_config_delete = DefaultFallbackRoutingConfigUpdate {
        routable_connector: &Some(
            common_enums::RoutableConnectors::from_str(&mca.connector_name.to_string()).map_err(
                |_| errors::ApiErrorResponse::InvalidDataValue {
                    field_name: "connector_name",
                },
            )?,
        ),
        merchant_connector_id: &mca.get_id(),
        store: db,
        business_profile,
        key_store: merchant_context.get_merchant_key_store().to_owned(),
        key_manager_state,
    };

    merchant_default_config_delete
        .retrieve_and_delete_from_default_fallback_routing_algorithm_if_routable_connector_exists()
        .await?;

    let response = api::MerchantConnectorDeleteResponse {
        merchant_id: merchant_id.clone(),
        id,
        deleted: is_deleted,
    };
    Ok(service_api::ApplicationResponse::Json(response))
}

pub async fn kv_for_merchant(
    state: SessionState,
    merchant_id: id_type::MerchantId,
    enable: bool,
) -> RouterResponse<api_models::admin::ToggleKVResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = db
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &db.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    // check if the merchant account exists
    let merchant_account = db
        .find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let updated_merchant_account = match (enable, merchant_account.storage_scheme) {
        (true, MerchantStorageScheme::RedisKv) | (false, MerchantStorageScheme::PostgresOnly) => {
            Ok(merchant_account)
        }
        (true, MerchantStorageScheme::PostgresOnly) => {
            if state.conf.as_ref().is_kv_soft_kill_mode() {
                Err(errors::ApiErrorResponse::InvalidRequestData {
                    message: "Kv cannot be enabled when application is in soft_kill_mode"
                        .to_owned(),
                })?
            }

            db.update_merchant(
                key_manager_state,
                merchant_account,
                storage::MerchantAccountUpdate::StorageSchemeUpdate {
                    storage_scheme: MerchantStorageScheme::RedisKv,
                },
                &key_store,
            )
            .await
        }
        (false, MerchantStorageScheme::RedisKv) => {
            db.update_merchant(
                key_manager_state,
                merchant_account,
                storage::MerchantAccountUpdate::StorageSchemeUpdate {
                    storage_scheme: MerchantStorageScheme::PostgresOnly,
                },
                &key_store,
            )
            .await
        }
    }
    .map_err(|error| {
        error
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("failed to switch merchant_storage_scheme")
    })?;
    let kv_status = matches!(
        updated_merchant_account.storage_scheme,
        MerchantStorageScheme::RedisKv
    );

    Ok(service_api::ApplicationResponse::Json(
        api_models::admin::ToggleKVResponse {
            merchant_id: updated_merchant_account.get_id().to_owned(),
            kv_enabled: kv_status,
        },
    ))
}

pub async fn toggle_kv_for_all_merchants(
    state: SessionState,
    enable: bool,
) -> RouterResponse<api_models::admin::ToggleAllKVResponse> {
    let db = state.store.as_ref();
    let storage_scheme = if enable {
        MerchantStorageScheme::RedisKv
    } else {
        MerchantStorageScheme::PostgresOnly
    };

    let total_update = db
        .update_all_merchant_account(storage::MerchantAccountUpdate::StorageSchemeUpdate {
            storage_scheme,
        })
        .await
        .map_err(|error| {
            error
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to switch merchant_storage_scheme for all merchants")
        })?;

    Ok(service_api::ApplicationResponse::Json(
        api_models::admin::ToggleAllKVResponse {
            total_updated: total_update,
            kv_enabled: enable,
        },
    ))
}

pub async fn check_merchant_account_kv_status(
    state: SessionState,
    merchant_id: id_type::MerchantId,
) -> RouterResponse<api_models::admin::ToggleKVResponse> {
    let db = state.store.as_ref();
    let key_manager_state = &(&state).into();
    let key_store = db
        .get_merchant_key_store_by_merchant_id(
            key_manager_state,
            &merchant_id,
            &db.get_master_key().to_vec().into(),
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    // check if the merchant account exists
    let merchant_account = db
        .find_merchant_account_by_merchant_id(key_manager_state, &merchant_id, &key_store)
        .await
        .to_not_found_response(errors::ApiErrorResponse::MerchantAccountNotFound)?;

    let kv_status = matches!(
        merchant_account.storage_scheme,
        MerchantStorageScheme::RedisKv
    );

    Ok(service_api::ApplicationResponse::Json(
        api_models::admin::ToggleKVResponse {
            merchant_id: merchant_account.get_id().to_owned(),
            kv_enabled: kv_status,
        },
    ))
}

pub fn get_frm_config_as_secret(
    frm_configs: Option<Vec<api_models::admin::FrmConfigs>>,
) -> Option<Vec<Secret<serde_json::Value>>> {
    match frm_configs.as_ref() {
        Some(frm_value) => {
            let configs_for_frm_value: Vec<Secret<serde_json::Value>> = frm_value
                .iter()
                .map(|config| {
                    config
                        .encode_to_value()
                        .change_context(errors::ApiErrorResponse::ConfigNotFound)
                        .map(Secret::new)
                })
                .collect::<Result<Vec<_>, _>>()
                .ok()?;
            Some(configs_for_frm_value)
        }
        None => None,
    }
}

#[cfg(feature = "v1")]
pub async fn create_and_insert_business_profile(
    state: &SessionState,
    request: api::ProfileCreate,
    merchant_account: domain::MerchantAccount,
    key_store: &domain::MerchantKeyStore,
) -> RouterResult<domain::Profile> {
    let business_profile_new =
        admin::create_profile_from_merchant_account(state, merchant_account, request, key_store)
            .await?;

    let profile_name = business_profile_new.profile_name.clone();

    state
        .store
        .insert_business_profile(&state.into(), key_store, business_profile_new)
        .await
        .to_duplicate_response(errors::ApiErrorResponse::GenericDuplicateError {
            message: format!(
                "Business Profile with the profile_name {profile_name} already exists"
            ),
        })
        .attach_printable("Failed to insert Business profile because of duplication error")
}

#[cfg(feature = "olap")]
#[async_trait::async_trait]


pub async fn delete_merchant_account() {}


pub struct Frequency {
    unit: String,
    value: String,
}


pub struct Noon {
    amount_converter: &'static (dyn AmountConvertor<Output = StringMajorUnit> + Sync),
}


pub async fn frm_fulfillment_core(
    state: SessionState,
    merchant_context: domain::MerchantContext,
    req: frm_core_types::FrmFulfillmentRequest,
) -> RouterResponse<frm_types::FraudCheckResponseData> {
    let db = &*state.clone().store;
    let payment_intent = db
        .find_payment_intent_by_payment_id_merchant_id(
            &(&state).into(),
            &req.payment_id.clone(),
            merchant_context.get_merchant_account().get_id(),
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .change_context(errors::ApiErrorResponse::PaymentNotFound)?;
    match payment_intent.status {
        IntentStatus::Succeeded => {
            let invalid_request_error = errors::ApiErrorResponse::InvalidRequestData {
                message: "no fraud check entry found for this payment_id".to_string(),
            };
            let existing_fraud_check = db
                .find_fraud_check_by_payment_id_if_present(
                    req.payment_id.clone(),
                    merchant_context.get_merchant_account().get_id().clone(),
                )
                .await
                .change_context(invalid_request_error.to_owned())?;
            match existing_fraud_check {
                Some(fraud_check) => {
                    if (matches!(fraud_check.frm_transaction_type, FraudCheckType::PreFrm)
                        && fraud_check.last_step == FraudCheckLastStep::TransactionOrRecordRefund)
                        || (matches!(fraud_check.frm_transaction_type, FraudCheckType::PostFrm)
                            && fraud_check.last_step == FraudCheckLastStep::CheckoutOrSale)
                    {
                        Box::pin(make_fulfillment_api_call(
                            db,
                            fraud_check,
                            payment_intent,
                            state,
                            merchant_context,
                            req,
                        ))
                        .await
                    } else {
                        Err(errors::ApiErrorResponse::PreconditionFailed {message:"Frm pre/post flow hasn't terminated yet, so fulfillment cannot be called".to_string(),}.into())
                    }
                }
                None => Err(invalid_request_error.into()),
            }
        }
        _ => Err(errors::ApiErrorResponse::PreconditionFailed {
            message: "Fulfillment can be performed only for succeeded payment".to_string(),
        }
        .into()),
    }
}


pub struct FortePaymentsRequest {
    action: ForteAction,
    authorization_amount: FloatMajorUnit,
    billing_address: BillingAddress,
    card: Card,
}


pub async fn find_by_publishable_key(
        conn: &PgPooledConn,
        publishable_key: &str,
    ) -> StorageResult<Self> {
        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
            conn,
            dsl::publishable_key.eq(publishable_key.to_owned()),
        )
        .await
    }


File: crates/hyperswitch_connectors/src/connectors/authorizedotnet.rs
 Public functions: 1
 Public structs: 1

pub mod transformers;
use std::sync::LazyLock;

use common_enums::{enums, PaymentAction};
use common_utils::{
    crypto,
    errors::CustomResult,
    ext_traits::ByteSliceExt,
    request::{Method, Request, RequestBuilder, RequestContent},
    types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector},
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    payment_method_data::PaymentMethodData,
    router_data::{AccessToken, ErrorResponse, RouterData},
    router_flow_types::{
        access_token_auth::AccessTokenAuth,
        payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
        refunds::{Execute, RSync},
        CompleteAuthorize, CreateConnectorCustomer,
    },
    router_request_types::{
        AccessTokenRequestData, CompleteAuthorizeData, ConnectorCustomerData,
        PaymentMethodTokenizationData, PaymentsAuthorizeData, PaymentsCancelData,
        PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData, RefundsData,
        SetupMandateRequestData,
    },
    router_response_types::{
        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
        SupportedPaymentMethods, SupportedPaymentMethodsExt,
    },
    types::{
        ConnectorCustomerRouterData, PaymentsAuthorizeRouterData, PaymentsCancelRouterData,
        PaymentsCaptureRouterData, PaymentsCompleteAuthorizeRouterData, PaymentsSyncRouterData,
        RefundsRouterData, SetupMandateRouterData,
    },
};
use hyperswitch_interfaces::{
    api::{
        self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorSpecifications,
        ConnectorValidation, MandateSetup,
    },
    configs::Connectors,
    consts, errors,
    events::connector_api_logs::ConnectorEvent,
    types::{
        ConnectorCustomerType, PaymentsAuthorizeType, PaymentsCaptureType,
        PaymentsCompleteAuthorizeType, PaymentsSyncType, PaymentsVoidType, RefundExecuteType,
        RefundSyncType, Response, SetupMandateType,
    },
    webhooks,
};
use masking::Maskable;
use transformers as authorizedotnet;

use crate::{
    connectors::authorizedotnet::transformers::AuthorizedotnetRouterData,
    constants::headers,
    types::ResponseRouterData,
    utils::{
        self as connector_utils, convert_amount, ForeignTryFrom, PaymentMethodDataType,
        PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData,
    },
};

#[derive(Clone)]
pub struct Authorizedotnet {
    amount_convertor: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
}

impl Authorizedotnet {
    pub fn new() -> &'static Self {
        &Self {
            amount_convertor: &FloatMajorUnitForConnector,
        }
    }
}

impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Authorizedotnet
where
    Self: ConnectorIntegration<Flow, Request, Response>,
{
    fn build_headers(
        &self,
        _req: &RouterData<Flow, Request, Response>,
        _connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        Ok(vec![(
            headers::CONTENT_TYPE.to_string(),
            self.get_content_type().to_string().into(),
        )])
    }
}

impl ConnectorCommon for Authorizedotnet {
    fn id(&self) -> &'static str {
        "authorizedotnet"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.authorizedotnet.base_url.as_ref()
    }
}

impl ConnectorValidation for Authorizedotnet {
    fn validate_mandate_payment(
        &self,
        pm_type: Option<enums::PaymentMethodType>,
        pm_data: PaymentMethodData,
    ) -> CustomResult<(), errors::ConnectorError> {
        let mandate_supported_pmd = std::collections::HashSet::from([
            PaymentMethodDataType::Card,
            PaymentMethodDataType::GooglePay,
            PaymentMethodDataType::ApplePay,
        ]);
        connector_utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
    }
}

impl api::Payment for Authorizedotnet {}
impl api::PaymentAuthorize for Authorizedotnet {}
impl api::PaymentSync for Authorizedotnet {}
impl api::PaymentVoid for Authorizedotnet {}
impl api::PaymentCapture for Authorizedotnet {}
impl api::PaymentSession for Authorizedotnet {}
impl api::ConnectorAccessToken for Authorizedotnet {}
impl api::PaymentToken for Authorizedotnet {}

impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
    for Authorizedotnet
{
    // Not Implemented (R)
}

impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Authorizedotnet {
    // Not Implemented (R)
}

impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken>
    for Authorizedotnet
{
    // Not Implemented (R)
}

impl api::ConnectorCustomer for Authorizedotnet {}

impl ConnectorIntegration<CreateConnectorCustomer, ConnectorCustomerData, PaymentsResponseData>
    for Authorizedotnet
{
    fn get_headers(
        &self,
        req: &ConnectorCustomerRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &ConnectorCustomerRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }

    fn get_request_body(
        &self,
        req: &ConnectorCustomerRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = authorizedotnet::CustomerRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &ConnectorCustomerRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&ConnectorCustomerType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(ConnectorCustomerType::get_headers(self, req, connectors)?)
                .set_body(ConnectorCustomerType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &ConnectorCustomerRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<ConnectorCustomerRouterData, errors::ConnectorError>
    where
        PaymentsResponseData: Clone,
    {
        use bytes::Buf;
        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());
        let response: authorizedotnet::AuthorizedotnetCustomerResponse = intermediate_response
            .parse_struct("AuthorizedotnetCustomerResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
        .change_context(errors::ConnectorError::ResponseHandlingFailed)
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        use bytes::Buf;
        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());
        let response: authorizedotnet::AuthorizedotnetErrorResponse = intermediate_response
            .parse_struct("AuthorizedotnetErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_error_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response
                .error
                .code
                .clone()
                .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
            message: response
                .error
                .message
                .clone()
                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
            reason: response.error.message,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}

impl MandateSetup for Authorizedotnet {}

impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData>
    for Authorizedotnet
{
    fn get_headers(
        &self,
        req: &SetupMandateRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        // This connector does not require an auth header, the authentication details are sent in the request body
        self.build_headers(req, connectors)
    }
    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }
    fn get_url(
        &self,
        _req: &SetupMandateRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }
    fn get_request_body(
        &self,
        req: &SetupMandateRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = authorizedotnet::CreateCustomerPaymentProfileRequest::try_from(req)?;
        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &SetupMandateRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&SetupMandateType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(SetupMandateType::get_headers(self, req, connectors)?)
                .set_body(SetupMandateType::get_request_body(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &SetupMandateRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<SetupMandateRouterData, errors::ConnectorError> {
        use bytes::Buf;
        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());
        let response: authorizedotnet::AuthorizedotnetSetupMandateResponse = intermediate_response
            .parse_struct("AuthorizedotnetPaymentsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        get_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Authorizedotnet {
    fn get_headers(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }
    fn get_request_body(
        &self,
        req: &PaymentsCaptureRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_convertor,
            req.request.minor_amount_to_capture,
            req.request.currency,
        )?;

        let connector_router_data = AuthorizedotnetRouterData::try_from((amount, req))?;
        let connector_req =
            authorizedotnet::CancelOrCaptureTransactionRequest::try_from(&connector_router_data)?;

        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCaptureRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsCaptureType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsCaptureType::get_headers(self, req, connectors)?)
                .set_body(PaymentsCaptureType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCaptureRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
        use bytes::Buf;

        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());

        let response: authorizedotnet::AuthorizedotnetPaymentsResponse = intermediate_response
            .parse_struct("AuthorizedotnetPaymentsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        RouterData::foreign_try_from((
            ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            },
            true,
        ))
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        get_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Authorizedotnet {
    fn get_headers(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        // This connector does not require an auth header, the authentication details are sent in the request body
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }

    fn get_request_body(
        &self,
        req: &PaymentsSyncRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = authorizedotnet::AuthorizedotnetCreateSyncRequest::try_from(req)?;

        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsSyncRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&PaymentsSyncType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(PaymentsSyncType::get_headers(self, req, connectors)?)
            .set_body(PaymentsSyncType::get_request_body(self, req, connectors)?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &PaymentsSyncRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
        use bytes::Buf;

        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());

        let response: authorizedotnet::AuthorizedotnetSyncResponse = intermediate_response
            .parse_struct("AuthorizedotnetSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        get_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData>
    for Authorizedotnet
{
    fn get_headers(
        &self,
        req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        // This connector does not require an auth header, the authentication details are sent in the request body
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }

    fn get_request_body(
        &self,
        req: &PaymentsAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_convertor,
            req.request.minor_amount,
            req.request.currency,
        )?;

        let connector_router_data = AuthorizedotnetRouterData::try_from((amount, req))?;
        let connector_req =
            authorizedotnet::CreateTransactionRequest::try_from(&connector_router_data)?;

        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?)
                .set_body(PaymentsAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
        use bytes::Buf;

        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());

        let response: authorizedotnet::AuthorizedotnetPaymentsResponse = intermediate_response
            .parse_struct("AuthorizedotnetPaymentsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        RouterData::foreign_try_from((
            ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            },
            data.request.is_auto_capture()?,
        ))
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        get_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Authorizedotnet {
    fn get_headers(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }

    fn get_request_body(
        &self,
        req: &PaymentsCancelRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let connector_req = authorizedotnet::CancelOrCaptureTransactionRequest::try_from(req)?;

        Ok(RequestContent::Json(Box::new(connector_req)))
    }
    fn build_request(
        &self,
        req: &PaymentsCancelRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsVoidType::get_url(self, req, connectors)?)
                .attach_default_headers()
                .headers(PaymentsVoidType::get_headers(self, req, connectors)?)
                .set_body(PaymentsVoidType::get_request_body(self, req, connectors)?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCancelRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCancelRouterData, errors::ConnectorError> {
        use bytes::Buf;

        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());

        let response: authorizedotnet::AuthorizedotnetVoidResponse = intermediate_response
            .parse_struct("AuthorizedotnetPaymentsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        get_error_response(res, event_builder)
    }
}

impl api::Refund for Authorizedotnet {}
impl api::RefundExecute for Authorizedotnet {}
impl api::RefundSync for Authorizedotnet {}

impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Authorizedotnet {
    fn get_headers(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        // This connector does not require an auth header, the authentication details are sent in the request body
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<Execute>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_convertor,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;

        let connector_router_data = AuthorizedotnetRouterData::try_from((amount, req))?;
        let connector_req = authorizedotnet::CreateRefundRequest::try_from(&connector_router_data)?;

        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<Execute>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&RefundExecuteType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(RefundExecuteType::get_headers(self, req, connectors)?)
            .set_body(RefundExecuteType::get_request_body(self, req, connectors)?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &RefundsRouterData<Execute>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
        use bytes::Buf;

        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());

        let response: authorizedotnet::AuthorizedotnetRefundResponse = intermediate_response
            .parse_struct("AuthorizedotnetRefundResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        get_error_response(res, event_builder)
    }
}

impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Authorizedotnet {
    fn get_headers(
        &self,
        req: &RefundsRouterData<RSync>,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        // This connector does not require an auth header, the authentication details are sent in the request body
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &RefundsRouterData<RSync>,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }

    fn get_request_body(
        &self,
        req: &RefundsRouterData<RSync>,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_convertor,
            req.request.minor_refund_amount,
            req.request.currency,
        )?;

        let connector_router_data = AuthorizedotnetRouterData::try_from((amount, req))?;
        let connector_req =
            authorizedotnet::AuthorizedotnetCreateSyncRequest::try_from(&connector_router_data)?;

        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &RefundsRouterData<RSync>,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        let request = RequestBuilder::new()
            .method(Method::Post)
            .url(&RefundSyncType::get_url(self, req, connectors)?)
            .attach_default_headers()
            .headers(RefundSyncType::get_headers(self, req, connectors)?)
            .set_body(RefundSyncType::get_request_body(self, req, connectors)?)
            .build();
        Ok(Some(request))
    }

    fn handle_response(
        &self,
        data: &RefundsRouterData<RSync>,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<RefundsRouterData<RSync>, errors::ConnectorError> {
        use bytes::Buf;

        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());

        let response: authorizedotnet::AuthorizedotnetRSyncResponse = intermediate_response
            .parse_struct("AuthorizedotnetRSyncResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::try_from(ResponseRouterData {
            response,
            data: data.clone(),
            http_code: res.status_code,
        })
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        get_error_response(res, event_builder)
    }
}

impl api::PaymentsCompleteAuthorize for Authorizedotnet {}

impl ConnectorIntegration<CompleteAuthorize, CompleteAuthorizeData, PaymentsResponseData>
    for Authorizedotnet
{
    fn get_headers(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Vec<(String, Maskable<String>)>, errors::ConnectorError> {
        self.build_headers(req, connectors)
    }

    fn get_content_type(&self) -> &'static str {
        self.common_get_content_type()
    }

    fn get_url(
        &self,
        _req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<String, errors::ConnectorError> {
        Ok(self.base_url(connectors).to_string())
    }
    fn get_request_body(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        _connectors: &Connectors,
    ) -> CustomResult<RequestContent, errors::ConnectorError> {
        let amount = convert_amount(
            self.amount_convertor,
            req.request.minor_amount,
            req.request.currency,
        )?;

        let connector_router_data = AuthorizedotnetRouterData::try_from((amount, req))?;

        let connector_req =
            authorizedotnet::PaypalConfirmRequest::try_from(&connector_router_data)?;

        Ok(RequestContent::Json(Box::new(connector_req)))
    }

    fn build_request(
        &self,
        req: &PaymentsCompleteAuthorizeRouterData,
        connectors: &Connectors,
    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
        Ok(Some(
            RequestBuilder::new()
                .method(Method::Post)
                .url(&PaymentsCompleteAuthorizeType::get_url(
                    self, req, connectors,
                )?)
                .attach_default_headers()
                .headers(PaymentsCompleteAuthorizeType::get_headers(
                    self, req, connectors,
                )?)
                .set_body(PaymentsCompleteAuthorizeType::get_request_body(
                    self, req, connectors,
                )?)
                .build(),
        ))
    }

    fn handle_response(
        &self,
        data: &PaymentsCompleteAuthorizeRouterData,
        event_builder: Option<&mut ConnectorEvent>,
        res: Response,
    ) -> CustomResult<PaymentsCompleteAuthorizeRouterData, errors::ConnectorError> {
        use bytes::Buf;

        // Handle the case where response bytes contains U+FEFF (BOM) character sent by connector
        let encoding = encoding_rs::UTF_8;
        let intermediate_response = encoding.decode_with_bom_removal(res.response.chunk());
        let intermediate_response =
            bytes::Bytes::copy_from_slice(intermediate_response.0.as_bytes());

        let response: authorizedotnet::AuthorizedotnetPaymentsResponse = intermediate_response
            .parse_struct("AuthorizedotnetPaymentsResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
        event_builder.map(|i| i.set_response_body(&response));
        router_env::logger::info!(connector_response=?response);
        RouterData::foreign_try_from((
            ResponseRouterData {
                response,
                data: data.clone(),
                http_code: res.status_code,
            },
            data.request.is_auto_capture()?,
        ))
    }

    fn get_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        get_error_response(res, event_builder)
    }
}

#[async_trait::async_trait]
impl webhooks::IncomingWebhook for Authorizedotnet {
    fn get_webhook_source_verification_algorithm(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
        Ok(Box::new(crypto::HmacSha512))
    }

    fn get_webhook_source_verification_signature(
        &self,
        request: &webhooks::IncomingWebhookRequestDetails<'_>,
        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
        let security_header = request
            .headers
            .get("X-ANET-Signature")
            .map(|header_value| {
                header_value
                    .to_str()
                    .map(String::from)
                    .map_err(|_| errors::ConnectorError::WebhookSignatureNotFound)
            })
            .ok_or(errors::ConnectorError::WebhookSignatureNotFound)??
            .to_lowercase();
        let (_, sig_value) = security_header
            .split_once('=')
            .ok_or(errors::ConnectorError::WebhookSourceVerificationFailed)?;
        hex::decode(sig_value).change_context(errors::ConnectorError::WebhookSignatureNotFound)
    }

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

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


OpenAPI Block Path: components.schemas.PaymentMethodCreate
{
  "type": "object",
  "required": [
    "payment_method"
  ],
  "properties": {
    "payment_method": {
      "$ref": "#/components/schemas/PaymentMethod"
    },
    "payment_method_type": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentMethodType"
        }
      ],
      "nullable": true
    },
    "payment_method_issuer": {
      "type": "string",
      "description": "The name of the bank/ provider issuing the payment method to the end user",
      "example": "Citibank",
      "nullable": true
    },
    "payment_method_issuer_code": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentMethodIssuerCode"
        }
      ],
      "nullable": true
    },
    "card": {
      "allOf": [
        {
          "$ref": "#/components/schemas/CardDetail"
        }
      ],
      "nullable": true
    },
    "metadata": {
      "type": "object",
      "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
      "nullable": true
    },
    "customer_id": {
      "type": "string",
      "description": "The unique identifier of the customer.",
      "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44",
      "nullable": true,
      "maxLength": 64,
      "minLength": 1
    },
    "card_network": {
      "type": "string",
      "description": "The card network",
      "example": "Visa",
      "nullable": true
    },
    "bank_transfer": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Bank"
        }
      ],
      "nullable": true
    },
    "wallet": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Wallet"
        }
      ],
      "nullable": true
    },
    "client_secret": {
      "type": "string",
      "description": "For Client based calls, SDK will use the client_secret\nin order to call /payment_methods\nClient secret will be generated whenever a new\npayment method is created",
      "nullable": true
    },
    "payment_method_data": {
      "allOf": [
        {
          "$ref": "#/components/schemas/PaymentMethodCreateData"
        }
      ],
      "nullable": true
    },
    "billing": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Address"
        }
      ],
      "nullable": true
    }
  },
  "additionalProperties": false
}


impl DummyConnector {
    pub fn server(state: AppState) -> Scope {
        let mut routes_with_restricted_access = web::scope("");
        #[cfg(not(feature = "external_access_dc"))]
        {
            routes_with_restricted_access =
                routes_with_restricted_access.guard(actix_web::guard::Host("localhost"));
        }
        routes_with_restricted_access = routes_with_restricted_access
            .service(web::resource("/payment").route(web::post().to(dummy_connector_payment)))
            .service(
                web::resource("/payments/{payment_id}")
                    .route(web::get().to(dummy_connector_payment_data)),
            )
            .service(
                web::resource("/{payment_id}/refund").route(web::post().to(dummy_connector_refund)),
            )
            .service(
                web::resource("/refunds/{refund_id}")
                    .route(web::get().to(dummy_connector_refund_data)),
            );
        web::scope("/dummy-connector")
            .app_data(web::Data::new(state))
            .service(
                web::resource("/authorize/{attempt_id}")
                    .route(web::get().to(dummy_connector_authorize_payment)),
            )
            .service(
                web::resource("/complete/{attempt_id}")
                    .route(web::get().to(dummy_connector_complete_payment)),
            )
            .service(routes_with_restricted_access)
    }
}


pub trait EuclidBackend<O>: Sized {
    type Error: serde::Serialize;

    fn with_program(program: ast::Program<O>) -> Result<Self, Self::Error>;

    fn execute(&self, input: BackendInput) -> Result<BackendOutput<O>, Self::Error>;
}


pub struct SantanderTime {
    #[serde(rename = "solicitacao")]
    pub request: Option<String>,
    #[serde(rename = "liquidacao")]
    pub liquidation: Option<String>,
}


pub struct OpensearchSuccess {
    pub hits: OpensearchHits,
}


File: crates/common_utils/src/id_type/customer.rs

crate::id_type!(
    CustomerId,
    "A type for customer_id that can be used for customer ids"
);
crate::impl_id_type_methods!(CustomerId, "customer_id");

// This is to display the `CustomerId` as CustomerId(abcd)
crate::impl_debug_id_type!(CustomerId);
crate::impl_default_id_type!(CustomerId, "cus");
crate::impl_try_from_cow_str_id_type!(CustomerId, "customer_id");

crate::impl_generate_id_id_type!(CustomerId, "cus");
crate::impl_serializable_secret_id_type!(CustomerId);
crate::impl_queryable_id_type!(CustomerId);
crate::impl_to_sql_from_sql_id_type!(CustomerId);

#[cfg(feature = "v1")]
impl crate::events::ApiEventMetric for CustomerId {
    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
        Some(crate::events::ApiEventsType::Customer {
            customer_id: self.clone(),
        })
    }
}


pub struct AdyenInvalidField {
    pub name: Option<String>,
    pub value: Option<String>,
    pub message: Option<String>,
}


pub async fn update_user_authentication_method(
        conn: &PgPooledConn,
        id: &str,
        user_authentication_method_update: UserAuthenticationMethodUpdate,
    ) -> StorageResult<Self> {
        generics::generic_update_with_unique_predicate_get_result::<
            <Self as HasTable>::Table,
            _,
            _,
            _,
        >(
            conn,
            dsl::id.eq(id.to_owned()),
            OrgAuthenticationMethodUpdateInternal::from(user_authentication_method_update),
        )
        .await
    }


impl api::Payment for Archipel {}


File: crates/common_utils/src/access_token.rs
 Public functions: 1

//! Commonly used utilities for access token

use std::fmt::Display;

use crate::id_type;

/// Create a key for fetching the access token from redis
pub fn create_access_token_key(
    merchant_id: &id_type::MerchantId,
    merchant_connector_id_or_connector_name: impl Display,
) -> String {
    merchant_id.get_access_token_key(merchant_connector_id_or_connector_name)
}


pub struct OutgoingWebhookResponseContent {
    /// The response body received for the webhook sent.
    #[schema(value_type = Option<String>)]
    #[serde(alias = "payload")]
    pub body: Option<Secret<String>>,

    /// The response headers received for the webhook sent.
    #[schema(
        value_type = Option<Vec<(String, String)>>,
        example = json!([["content-type", "application/json"], ["content-length", "1024"]]))
    ]
    pub headers: Option<Vec<(String, Secret<String>)>>,

    /// The HTTP status code for the webhook sent.
    #[schema(example = 200)]
    pub status_code: Option<u16>,

    /// Error message in case any error occurred when trying to deliver the webhook.
    #[schema(example = 200)]
    pub error_message: Option<String>,
}


pub struct BlackhawknetworkPaymentsResponse {
    pub id: String,
    #[serde(rename = "transactionStatus")]
    pub status: BlackhawknetworkAttemptStatus,
}


pub struct Response {
    pub headers: Option<http::HeaderMap>,
    pub response: bytes::Bytes,
    pub status_code: u16,
}


impl api::PaymentAuthorize for Taxjar {}

impl api::PaymentAuthorize for for Taxjar


File: crates/pm_auth/src/core/errors.rs

#[derive(Debug, thiserror::Error, PartialEq)]
pub enum ConnectorError {
    #[error("Failed to obtain authentication type")]
    FailedToObtainAuthType,
    #[error("Missing required field: {field_name}")]
    MissingRequiredField { field_name: &'static str },
    #[error("Failed to execute a processing step: {0:?}")]
    ProcessingStepFailed(Option<bytes::Bytes>),
    #[error("Failed to deserialize connector response")]
    ResponseDeserializationFailed,
    #[error("Failed to encode connector request")]
    RequestEncodingFailed,
    #[error("Invalid connector configuration: {config}")]
    InvalidConnectorConfig { config: &'static str },
}
pub type CustomResult<T, E> = error_stack::Result<T, E>;

#[derive(Debug, thiserror::Error)]
pub enum ParsingError {
    #[error("Failed to parse enum: {0}")]
    EnumParseFailure(&'static str),
    #[error("Failed to parse struct: {0}")]
    StructParseFailure(&'static str),
    #[error("Failed to serialize to {0} format")]
    EncodeError(&'static str),
    #[error("Unknown error while parsing")]
    UnknownError,
}


OpenAPI Block Path: components.schemas.IfStatement
{
  "type": "object",
  "description": "Represents an IF statement with conditions and optional nested IF statements\n\n```text\npayment.method = card {\npayment.method.cardtype = (credit, debit) {\npayment.method.network = (amex, rupay, diners)\n}\n}\n```",
  "required": [
    "condition"
  ],
  "properties": {
    "condition": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/Comparison"
      }
    },
    "nested": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/IfStatement"
      },
      "nullable": true
    }
  }
}


pub struct BokuMetaData {
    pub(super) country: String,
}


pub struct ApiEventFiltersResponse {
    pub query_data: Vec<ApiEventFilterValue>,
}


/// Get the attempt id for the payment id based on the attempt count
    pub fn get_attempt_id(&self, attempt_count: i16) -> String {
        format!("{}_{attempt_count}", self.get_string_repr())
    }


pub struct SchedulerHealthCheckResponse {
    pub database: bool,
    pub redis: bool,
    pub outgoing_request: bool,
}


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


Documentation: api-reference/v1/3ds-decision-rule/execute-a-3ds-decision-rule-based-on-the-provided-input.mdx
# Type: Doc File

---
openapi: post /three_ds_decision/execute
---


pub struct CardsInfoRequestParams {
    #[schema(example = "pay_OSERgeV9qAy7tlK7aKpc_secret_TuDUoh11Msxh12sXn3Yp")]
    pub client_secret: Option<String>,
}


pub struct Amount {
    value: MinorUnit,
    currency: String,
}


File: crates/router/tests/health_check.rs

mod utils;

use utils::{mk_service, AppClient};

#[actix_web::test]
async fn health_check() {
    let server = Box::pin(mk_service()).await;
    let client = AppClient::guest();

    assert_eq!(client.health(&server).await, "health is good");
}


pub struct CardInfoMigrateExecutor<'a> {
    state: &'a routes::SessionState,
    record: &'a cards_info_api_types::CardInfoUpdateRequest,
}


pub async fn delete_network_token_from_tokenization_service(
    state: &routes::SessionState,
    network_token_requestor_reference_id: String,
    customer_id: &id_type::CustomerId,
    tokenization_service: &settings::NetworkTokenizationService,
) -> CustomResult<bool, errors::NetworkTokenizationError> {
    let mut request = services::Request::new(
        services::Method::Post,
        tokenization_service.delete_token_url.as_str(),
    );
    let payload = pm_types::DeleteCardToken {
        card_reference: network_token_requestor_reference_id,
        customer_id: customer_id.clone(),
    };

    request.add_header(headers::CONTENT_TYPE, "application/json".into());
    request.add_header(
        headers::AUTHORIZATION,
        tokenization_service
            .token_service_api_key
            .clone()
            .peek()
            .clone()
            .into_masked(),
    );
    request.add_default_headers();
    request.set_body(RequestContent::Json(Box::new(payload)));

    logger::info!("Request to delete network token: {:?}", request);

    // Send the request using `call_connector_api`
    let response = services::call_connector_api(state, request, "delete network token")
        .await
        .change_context(errors::NetworkTokenizationError::ApiError);
    let res = response
        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)
        .attach_printable("Error while receiving response")
        .and_then(|inner| match inner {
            Err(err_res) => {
                let parsed_error: pm_types::NetworkTokenErrorResponse = err_res
                    .response
                    .parse_struct("Delete Network Tokenization Response")
                    .change_context(
                        errors::NetworkTokenizationError::ResponseDeserializationFailed,
                    )?;
                logger::error!(
                    error_code = %parsed_error.error_info.code,
                    developer_message = %parsed_error.error_info.developer_message,
                    "Network tokenization error: {}",
                    parsed_error.error_message
                );
                Err(errors::NetworkTokenizationError::ResponseDeserializationFailed)
                    .attach_printable(format!("Response Deserialization Failed: {err_res:?}"))
            }
            Ok(res) => Ok(res),
        })
        .inspect_err(|err| {
            logger::error!("Error while deserializing response: {:?}", err);
        })?;

    let delete_token_response: pm_types::DeleteNetworkTokenResponse = res
        .response
        .parse_struct("Delete Network Tokenization Response")
        .change_context(errors::NetworkTokenizationError::ResponseDeserializationFailed)?;

    logger::info!("Delete Network Token Response: {:?}", delete_token_response);

    if delete_token_response.status == pm_types::DeleteNetworkTokenStatus::Success {
        Ok(true)
    } else {
        Err(errors::NetworkTokenizationError::DeleteNetworkTokenFailed)
            .attach_printable("Delete Token at Token service failed")
    }
}


pub async fn payouts_list_available_filters_for_merchant(
    state: web::Data<AppState>,
    req: HttpRequest,
    json_payload: web::Json<common_utils::types::TimeRange>,
) -> HttpResponse {
    let flow = Flow::PayoutsFilter;
    let payload = json_payload.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payouts_list_available_filters_core(state, merchant_context, None, req)
        },
        auth::auth_type(
            &auth::HeaderAuth(auth::ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            }),
            &auth::JWTAuth {
                permission: Permission::MerchantPayoutRead,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}