        if customer.default_payment_method_id.as_ref() == Some(&pm_id.payment_method_id) {
            let customer_update = CustomerUpdate::UpdateDefaultPaymentMethod {
                default_payment_method_id: Some(None),
            };
            db.update_customer_by_customer_id_merchant_id(
                key_manager_state,
                key.customer_id,
                key.merchant_id,
                customer,
                customer_update,
                self.merchant_context.get_merchant_key_store(),
                self.merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to update the default payment method id for the customer")?;
        };

        Ok(services::ApplicationResponse::Json(
            api::PaymentMethodDeleteResponse {
                payment_method_id: key.payment_method_id.clone(),
                deleted: true,
            },
        ))
    }

    #[cfg(feature = "v1")]
    #[instrument(skip_all)]
    async fn add_payment_method(
        &self,
        req: &api::PaymentMethodCreate,
    ) -> errors::RouterResponse<api::PaymentMethodResponse> {
        req.validate()?;
        let db = &*self.state.store;
        let merchant_id = self.merchant_context.get_merchant_account().get_id();
        let customer_id = req.customer_id.clone().get_required_value("customer_id")?;
        let payment_method = req.payment_method.get_required_value("payment_method")?;
        let key_manager_state = self.state.into();
        let payment_method_billing_address: Option<Encryptable<Secret<serde_json::Value>>> = req
            .billing
            .clone()
            .async_map(|billing| {
                create_encrypted_data(
                    &key_manager_state,
                    self.merchant_context.get_merchant_key_store(),
                    billing,
                )
            })
            .await
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Unable to encrypt Payment method billing address")?;

        let connector_mandate_details = req
            .connector_mandate_details
            .clone()
            .map(serde_json::to_value)
            .transpose()
            .change_context(errors::ApiErrorResponse::InternalServerError)?;
        let response = match payment_method {
            #[cfg(feature = "payouts")]
            api_enums::PaymentMethod::BankTransfer => match req.bank_transfer.clone() {
                Some(bank) => self
                    .add_bank_to_locker(
                        req.clone(),
                        self.merchant_context.get_merchant_key_store(),
                        &bank,
                        &customer_id,
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Add PaymentMethod Failed"),
                _ => Ok(self.store_default_payment_method(req, &customer_id, merchant_id)),
            },
            api_enums::PaymentMethod::Card => match req.card.clone() {
                Some(card) => {
                    let mut card_details = card;
                    card_details = helpers::populate_bin_details_for_payment_method_create(
                        card_details.clone(),
                        db.get_payment_methods_store(),
                    )
                    .await;
                    helpers::validate_card_expiry(
                        &card_details.card_exp_month,
                        &card_details.card_exp_year,
                    )?;
                    Box::pin(self.add_card_to_locker(
                        req.clone(),
                        &card_details,
                        &customer_id,
                        None,
                    ))
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Add Card Failed")
                }
                _ => Ok(self.store_default_payment_method(req, &customer_id, merchant_id)),
            },
            _ => Ok(self.store_default_payment_method(req, &customer_id, merchant_id)),
        };

        let (mut resp, duplication_check) = response?;

        match duplication_check {
            Some(duplication_check) => match duplication_check {
                payment_methods::DataDuplicationCheck::Duplicated => {
                    let existing_pm = self
                        .get_or_insert_payment_method(
                            req.clone(),
                            &mut resp,
                            &customer_id,
                            self.merchant_context.get_merchant_key_store(),
                        )
                        .await?;

                    resp.client_secret = existing_pm.client_secret;
                }
                payment_methods::DataDuplicationCheck::MetaDataChanged => {
                    if let Some(card) = req.card.clone() {
                        let existing_pm = self
                            .get_or_insert_payment_method(
                                req.clone(),
                                &mut resp,
                                &customer_id,
                                self.merchant_context.get_merchant_key_store(),
                            )
                            .await?;

                        let client_secret = existing_pm.client_secret.clone();

                        self.delete_card_from_locker(
                            &customer_id,
                            merchant_id,
                            existing_pm
                                .locker_id
                                .as_ref()
                                .unwrap_or(&existing_pm.payment_method_id),
                        )
                        .await?;

                        let add_card_resp = self
                            .add_card_hs(
                                req.clone(),
                                &card,
                                &customer_id,
                                api::enums::LockerChoice::HyperswitchCardVault,
                                Some(
                                    existing_pm
                                        .locker_id
                                        .as_ref()
                                        .unwrap_or(&existing_pm.payment_method_id),
                                ),
                            )
                            .await;

                        if let Err(err) = add_card_resp {
                            logger::error!(vault_err=?err);
                            db.delete_payment_method_by_merchant_id_payment_method_id(
                                &(self.state.into()),
                                self.merchant_context.get_merchant_key_store(),
                                merchant_id,
                                &resp.payment_method_id,
                            )
                            .await
                            .to_not_found_response(
                                errors::ApiErrorResponse::PaymentMethodNotFound,
                            )?;

                            Err(report!(errors::ApiErrorResponse::InternalServerError)
                                .attach_printable("Failed while updating card metadata changes"))?
                        };

                        let existing_pm_data = self
                            .get_card_details_without_locker_fallback(&existing_pm)
                            .await?;

                        let updated_card = Some(api::CardDetailFromLocker {
                            scheme: existing_pm.scheme.clone(),
                            last4_digits: Some(card.card_number.get_last4()),
                            issuer_country: card
                                .card_issuing_country
                                .or(existing_pm_data.issuer_country),
                            card_isin: Some(card.card_number.get_card_isin()),
                            card_number: Some(card.card_number),
                            expiry_month: Some(card.card_exp_month),
                            expiry_year: Some(card.card_exp_year),
                            card_token: None,
                            card_fingerprint: None,
                            card_holder_name: card
                                .card_holder_name
                                .or(existing_pm_data.card_holder_name),
                            nick_name: card.nick_name.or(existing_pm_data.nick_name),
                            card_network: card.card_network.or(existing_pm_data.card_network),
                            card_issuer: card.card_issuer.or(existing_pm_data.card_issuer),
                            card_type: card.card_type.or(existing_pm_data.card_type),
                            saved_to_locker: true,
                        });

                        let updated_pmd = updated_card.as_ref().map(|card| {
                            PaymentMethodsData::Card(CardDetailsPaymentMethod::from((
                                card.clone(),
                                None,
                            )))
                        });
                        let pm_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> =
                            updated_pmd
                                .async_map(|updated_pmd| {
                                    create_encrypted_data(
                                        &key_manager_state,
                                        self.merchant_context.get_merchant_key_store(),
                                        updated_pmd,
                                    )
                                })
                                .await
                                .transpose()
                                .change_context(errors::ApiErrorResponse::InternalServerError)
                                .attach_printable("Unable to encrypt payment method data")?;

                        let pm_update = storage::PaymentMethodUpdate::PaymentMethodDataUpdate {
                            payment_method_data: pm_data_encrypted.map(Into::into),
                        };

                        db.update_payment_method(
                            &(self.state.into()),
                            self.merchant_context.get_merchant_key_store(),
                            existing_pm,
                            pm_update,
                            self.merchant_context.get_merchant_account().storage_scheme,
                        )
                        .await
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed to add payment method in db")?;

                        resp.client_secret = client_secret;
                    }
                }
            },
            None => {
                let pm_metadata = resp.metadata.as_ref().map(|data| data.peek());

                let locker_id = if resp.payment_method == Some(api_enums::PaymentMethod::Card)
                    || resp.payment_method == Some(api_enums::PaymentMethod::BankTransfer)
                {
                    Some(resp.payment_method_id)
                } else {
                    None
                };
                resp.payment_method_id = generate_id(consts::ID_LENGTH, "pm");
                let pm = self
                    .insert_payment_method(
                        &resp,
                        req,
                        self.merchant_context.get_merchant_key_store(),
                        merchant_id,
                        &customer_id,
                        pm_metadata.cloned(),
                        None,
                        locker_id,
                        connector_mandate_details,
                        req.network_transaction_id.clone(),
                        payment_method_billing_address,
                        None,
                        None,
                        None,
                    )
                    .await?;

                resp.client_secret = pm.client_secret;
            }
        }

        Ok(services::ApplicationResponse::Json(resp))
    }
}

#[cfg(feature = "v1")]
#[instrument(skip_all)]
pub async fn get_client_secret_or_add_payment_method(
    state: &routes::SessionState,
    req: api::PaymentMethodCreate,
    merchant_context: &domain::MerchantContext,
) -> errors::RouterResponse<api::PaymentMethodResponse> {
    let merchant_id = merchant_context.get_merchant_account().get_id();
    let customer_id = req.customer_id.clone().get_required_value("customer_id")?;
    let cards = PmCards {
        state,
        merchant_context,
    };
    #[cfg(not(feature = "payouts"))]
    let condition = req.card.is_some();
    #[cfg(feature = "payouts")]
    let condition = req.card.is_some() || req.bank_transfer.is_some() || req.wallet.is_some();
    let key_manager_state = state.into();
    let payment_method_billing_address: Option<Encryptable<Secret<serde_json::Value>>> = req
        .billing
        .clone()
        .async_map(|billing| {
            create_encrypted_data(
                &key_manager_state,
                merchant_context.get_merchant_key_store(),
                billing,
            )
        })
        .await
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)
        .attach_printable("Unable to encrypt Payment method billing address")?;

    let connector_mandate_details = req
        .connector_mandate_details
        .clone()
        .map(serde_json::to_value)
        .transpose()
        .change_context(errors::ApiErrorResponse::InternalServerError)?;

    if condition {
        Box::pin(cards.add_payment_method(&req)).await
    } else {
        let payment_method_id = generate_id(consts::ID_LENGTH, "pm");

        let res = cards
            .create_payment_method(
                &req,
                &customer_id,
                payment_method_id.as_str(),
                None,
                merchant_id,
                None,
                None,
                None,
                connector_mandate_details,
                Some(enums::PaymentMethodStatus::AwaitingData),
                None,
                payment_method_billing_address,
                None,
                None,
                None,
                None,
            )
            .await?;

        if res.status == enums::PaymentMethodStatus::AwaitingData {
            add_payment_method_status_update_task(
                &*state.store,
                &res,
                enums::PaymentMethodStatus::AwaitingData,
                enums::PaymentMethodStatus::Inactive,
                merchant_id,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable(
                "Failed to add payment method status update task in process tracker",
            )?;
        }

        Ok(services::api::ApplicationResponse::Json(
            api::PaymentMethodResponse::foreign_from((None, res)),
        ))
    }
}

#[instrument(skip_all)]
pub fn authenticate_pm_client_secret_and_check_expiry(
    req_client_secret: &String,
    payment_method: &domain::PaymentMethod,
) -> errors::CustomResult<bool, errors::ApiErrorResponse> {
    let stored_client_secret = payment_method
        .client_secret
        .clone()
        .get_required_value("client_secret")
        .change_context(errors::ApiErrorResponse::MissingRequiredField {
            field_name: "client_secret",
        })
        .attach_printable("client secret not found in db")?;

    if req_client_secret != &stored_client_secret {
        Err((errors::ApiErrorResponse::ClientSecretInvalid).into())
    } else {
        let current_timestamp = common_utils::date_time::now();
        let session_expiry = payment_method
            .created_at
            .saturating_add(time::Duration::seconds(consts::DEFAULT_SESSION_EXPIRY));

        let expired = current_timestamp > session_expiry;

        Ok(expired)
    }
}

#[cfg(feature = "v1")]
#[instrument(skip_all)]
pub async fn add_payment_method_data(
    state: routes::SessionState,
    req: api::PaymentMethodCreate,
    merchant_context: domain::MerchantContext,
    pm_id: String,
) -> errors::RouterResponse<api::PaymentMethodResponse> {
    let db = &*state.store;
    let cards = PmCards {
        state: &state,
        merchant_context: &merchant_context,
    };

    let pmd = req
        .payment_method_data
        .clone()
        .get_required_value("payment_method_data")?;
    req.payment_method.get_required_value("payment_method")?;
    let client_secret = req
        .client_secret
        .clone()
        .get_required_value("client_secret")?;
    let payment_method = db
        .find_payment_method(
            &((&state).into()),
            merchant_context.get_merchant_key_store(),
            pm_id.as_str(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .change_context(errors::ApiErrorResponse::PaymentMethodNotFound)
        .attach_printable("Unable to find payment method")?;

    if payment_method.status != enums::PaymentMethodStatus::AwaitingData {
        return Err((errors::ApiErrorResponse::ClientSecretExpired).into());
    }

    let customer_id = payment_method.customer_id.clone();

    let customer = db
        .find_customer_by_customer_id_merchant_id(
            &(&state).into(),
            &customer_id,
            merchant_context.get_merchant_account().get_id(),
            merchant_context.get_merchant_key_store(),
            merchant_context.get_merchant_account().storage_scheme,
        )
        .await
        .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;

    let client_secret_expired =
        authenticate_pm_client_secret_and_check_expiry(&client_secret, &payment_method)?;

    if client_secret_expired {
        return Err((errors::ApiErrorResponse::ClientSecretExpired).into());
    };
    let key_manager_state = (&state).into();
    match pmd {
        api_models::payment_methods::PaymentMethodCreateData::Card(card) => {
            helpers::validate_card_expiry(&card.card_exp_month, &card.card_exp_year)?;
            let resp = Box::pin(cards.add_card_to_locker(req.clone(), &card, &customer_id, None))
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError);

            match resp {
                Ok((mut pm_resp, duplication_check)) => {
                    if duplication_check.is_some() {
                        let pm_update = storage::PaymentMethodUpdate::StatusUpdate {
                            status: Some(enums::PaymentMethodStatus::Inactive),
                        };

                        db.update_payment_method(
                            &((&state).into()),
                            merchant_context.get_merchant_key_store(),
                            payment_method,
                            pm_update,
                            merchant_context.get_merchant_account().storage_scheme,
                        )
                        .await
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed to add payment method in db")?;

                        cards
                            .get_or_insert_payment_method(
                                req.clone(),
                                &mut pm_resp,
                                &customer_id,
                                merchant_context.get_merchant_key_store(),
                            )
                            .await?;

                        return Ok(services::ApplicationResponse::Json(pm_resp));
                    } else {
                        let locker_id = pm_resp.payment_method_id.clone();
                        pm_resp.payment_method_id.clone_from(&pm_id);
                        pm_resp.client_secret = Some(client_secret.clone());

                        let card_isin = card.card_number.get_card_isin();

                        let card_info = db
                            .get_card_info(card_isin.as_str())
                            .await
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("Failed to get card info")?;

                        let updated_card = CardDetailsPaymentMethod {
                            issuer_country: card_info
                                .as_ref()
                                .and_then(|ci| ci.card_issuing_country.clone()),
                            last4_digits: Some(card.card_number.get_last4()),
                            expiry_month: Some(card.card_exp_month),
                            expiry_year: Some(card.card_exp_year),
                            nick_name: card.nick_name,
                            card_holder_name: card.card_holder_name,
                            card_network: card_info.as_ref().and_then(|ci| ci.card_network.clone()),
                            card_isin: Some(card_isin),
                            card_issuer: card_info.as_ref().and_then(|ci| ci.card_issuer.clone()),
                            card_type: card_info.as_ref().and_then(|ci| ci.card_type.clone()),
                            saved_to_locker: true,
                            co_badged_card_data: None,
                        };
                        let pm_data_encrypted: Encryptable<Secret<serde_json::Value>> =
                            create_encrypted_data(
                                &key_manager_state,
                                merchant_context.get_merchant_key_store(),
                                PaymentMethodsData::Card(updated_card),
                            )
                            .await
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("Unable to encrypt payment method data")?;

                        let pm_update = storage::PaymentMethodUpdate::AdditionalDataUpdate {
                            payment_method_data: Some(pm_data_encrypted.into()),
                            status: Some(enums::PaymentMethodStatus::Active),
                            locker_id: Some(locker_id),
                            network_token_requestor_reference_id: None,
                            payment_method: req.payment_method,
                            payment_method_issuer: req.payment_method_issuer,
                            payment_method_type: req.payment_method_type,
                            network_token_locker_id: None,
                            network_token_payment_method_data: None,
                        };

                        db.update_payment_method(
                            &((&state).into()),
                            merchant_context.get_merchant_key_store(),
                            payment_method,
                            pm_update,
                            merchant_context.get_merchant_account().storage_scheme,
                        )
                        .await
                        .change_context(errors::ApiErrorResponse::InternalServerError)
                        .attach_printable("Failed to add payment method in db")?;

                        if customer.default_payment_method_id.is_none() {
                            let _ = cards
                                .set_default_payment_method(
                                    merchant_context.get_merchant_account().get_id(),
                                    &customer_id,
                                    pm_id,
                                )
                                .await
                                .map_err(|error| {
                                    logger::error!(
                                        ?error,
                                        "Failed to set the payment method as default"
                                    )
                                });
                        }

                        return Ok(services::ApplicationResponse::Json(pm_resp));
                    }
                }
                Err(e) => {
                    let pm_update = storage::PaymentMethodUpdate::StatusUpdate {
                        status: Some(enums::PaymentMethodStatus::Inactive),
                    };

                    db.update_payment_method(
                        &((&state).into()),
                        merchant_context.get_merchant_key_store(),
                        payment_method,
                        pm_update,
                        merchant_context.get_merchant_account().storage_scheme,
                    )
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to update payment method in db")?;

                    return Err(e.attach_printable("Failed to add card to locker"));
                }
            }
        }
    }
}

#[cfg(feature = "v1")]
#[instrument(skip_all)]
pub async fn update_customer_payment_method(
    state: routes::SessionState,
    merchant_context: domain::MerchantContext,
    req: api::PaymentMethodUpdate,
    payment_method_id: &str,
) -> errors::RouterResponse<api::PaymentMethodResponse> {
    // Currently update is supported only for cards
    if let Some(card_update) = req.card.clone() {
        let db = state.store.as_ref();

        let pm = db
            .find_payment_method(
                &((&state).into()),
                merchant_context.get_merchant_key_store(),
                payment_method_id,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;

        if let Some(cs) = &req.client_secret {
            let is_client_secret_expired = authenticate_pm_client_secret_and_check_expiry(cs, &pm)?;

            if is_client_secret_expired {
                return Err((errors::ApiErrorResponse::ClientSecretExpired).into());
            };
        };

        if pm.status == enums::PaymentMethodStatus::AwaitingData {
            return Err(report!(errors::ApiErrorResponse::NotSupported {
                message: "Payment method is awaiting data so it cannot be updated".into()
            }));
        }

        if pm.payment_method_data.is_none() {
            return Err(report!(errors::ApiErrorResponse::GenericNotFoundError {
                message: "payment_method_data not found".to_string()
            }));
        }

        // Fetch the existing payment method data from db
        let existing_card_data =
            pm.payment_method_data
                .clone()
                .map(|x| x.into_inner().expose())
                .map(
                    |value| -> Result<
                        PaymentMethodsData,
                        error_stack::Report<errors::ApiErrorResponse>,
                    > {
                        value
                            .parse_value::<PaymentMethodsData>("PaymentMethodsData")
                            .change_context(errors::ApiErrorResponse::InternalServerError)
                            .attach_printable("Failed to deserialize payment methods data")
                    },
                )
                .transpose()?
                .and_then(|pmd| match pmd {
                    PaymentMethodsData::Card(crd) => Some(api::CardDetailFromLocker::from(crd)),
                    _ => None,
                })
                .ok_or(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Failed to obtain decrypted card object from db")?;

        let is_card_updation_required =
            validate_payment_method_update(card_update.clone(), existing_card_data.clone());

        let response = if is_card_updation_required {
            // Fetch the existing card data from locker for getting card number
            let card_data_from_locker = get_card_from_locker(
                &state,
                &pm.customer_id,
                &pm.merchant_id,
                pm.locker_id.as_ref().unwrap_or(&pm.payment_method_id),
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Error getting card from locker")?;

            if card_update.card_exp_month.is_some() || card_update.card_exp_year.is_some() {
                helpers::validate_card_expiry(
                    card_update
                        .card_exp_month
                        .as_ref()
                        .unwrap_or(&card_data_from_locker.card_exp_month),
                    card_update
                        .card_exp_year
                        .as_ref()
                        .unwrap_or(&card_data_from_locker.card_exp_year),
                )?;
            }

            let updated_card_details = card_update.apply(card_data_from_locker.clone());

            // Construct new payment method object from request
            let new_pm = api::PaymentMethodCreate {
                payment_method: pm.get_payment_method_type(),
                payment_method_type: pm.get_payment_method_subtype(),
                payment_method_issuer: pm.payment_method_issuer.clone(),
                payment_method_issuer_code: pm.payment_method_issuer_code,
                #[cfg(feature = "payouts")]
                bank_transfer: None,
                card: Some(updated_card_details.clone()),
                #[cfg(feature = "payouts")]
                wallet: None,
                metadata: None,
                customer_id: Some(pm.customer_id.clone()),
                client_secret: pm.client_secret.clone(),
                payment_method_data: None,
                card_network: None,
                billing: None,
                connector_mandate_details: None,
                network_transaction_id: None,
            };
            new_pm.validate()?;
            let cards = PmCards {
                state: &state,
                merchant_context: &merchant_context,
            };
            // Delete old payment method from locker
            cards
                .delete_card_from_locker(
                    &pm.customer_id,
                    &pm.merchant_id,
                    pm.locker_id.as_ref().unwrap_or(&pm.payment_method_id),
                )
                .await?;

            // Add the updated payment method data to locker
            let (mut add_card_resp, _) = Box::pin(cards.add_card_to_locker(
                new_pm.clone(),
                &updated_card_details,
                &pm.customer_id,
                Some(pm.locker_id.as_ref().unwrap_or(&pm.payment_method_id)),
            ))
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to add updated payment method to locker")?;

            // Construct new updated card object. Consider a field if passed in request or else populate it with the existing value from existing_card_data
            let updated_card = Some(api::CardDetailFromLocker {
                scheme: existing_card_data.scheme,
                last4_digits: Some(card_data_from_locker.card_number.get_last4()),
                issuer_country: existing_card_data.issuer_country,
                card_number: existing_card_data.card_number,
                expiry_month: card_update
                    .card_exp_month
                    .or(existing_card_data.expiry_month),
                expiry_year: card_update.card_exp_year.or(existing_card_data.expiry_year),
                card_token: existing_card_data.card_token,
                card_fingerprint: existing_card_data.card_fingerprint,
                card_holder_name: card_update
                    .card_holder_name
                    .or(existing_card_data.card_holder_name),
                nick_name: card_update.nick_name.or(existing_card_data.nick_name),
                card_network: existing_card_data.card_network,
                card_isin: existing_card_data.card_isin,
                card_issuer: existing_card_data.card_issuer,
                card_type: existing_card_data.card_type,
                saved_to_locker: true,
            });

            let updated_pmd = updated_card.as_ref().map(|card| {
                PaymentMethodsData::Card(CardDetailsPaymentMethod::from((card.clone(), None)))
            });
            let key_manager_state = (&state).into();
            let pm_data_encrypted: Option<Encryptable<Secret<serde_json::Value>>> = updated_pmd
                .async_map(|updated_pmd| {
                    create_encrypted_data(
                        &key_manager_state,
                        merchant_context.get_merchant_key_store(),
                        updated_pmd,
                    )
                })
                .await
                .transpose()
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Unable to encrypt payment method data")?;

            let pm_update = storage::PaymentMethodUpdate::PaymentMethodDataUpdate {
                payment_method_data: pm_data_encrypted.map(Into::into),
            };

            add_card_resp
                .payment_method_id
                .clone_from(&pm.payment_method_id);

            db.update_payment_method(
                &((&state).into()),
                merchant_context.get_merchant_key_store(),
                pm,
                pm_update,
                merchant_context.get_merchant_account().storage_scheme,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed to update payment method in db")?;

            add_card_resp
        } else {
            // Return existing payment method data as response without any changes
            api::PaymentMethodResponse {
                merchant_id: pm.merchant_id.to_owned(),
                customer_id: Some(pm.customer_id.clone()),
                payment_method_id: pm.payment_method_id.clone(),
                payment_method: pm.get_payment_method_type(),
                payment_method_type: pm.get_payment_method_subtype(),
                #[cfg(feature = "payouts")]
                bank_transfer: None,
                card: Some(existing_card_data),
                metadata: pm.metadata,
                created: Some(pm.created_at),
                recurring_enabled: Some(false),
                installment_payment_enabled: Some(false),
                payment_experience: Some(vec![api_models::enums::PaymentExperience::RedirectToUrl]),
                last_used_at: Some(common_utils::date_time::now()),
                client_secret: pm.client_secret.clone(),
            }
        };

        Ok(services::ApplicationResponse::Json(response))
    } else {
        Err(report!(errors::ApiErrorResponse::NotSupported {
            message: "Payment method update for the given payment method is not supported".into()
        }))
    }
}

#[cfg(feature = "v1")]
pub fn validate_payment_method_update(
    card_updation_obj: CardDetailUpdate,
    existing_card_data: api::CardDetailFromLocker,
) -> bool {
    // Return true If any one of the below condition returns true,
    // If a field is not passed in the update request, return false.
    // If the field is present, it depends on the existing field data:
    // - If existing field data is not present, or if it is present and doesn't match
    //   the update request data, then return true.
    // - Or else return false
    card_updation_obj
        .card_exp_month
        .map(|exp_month| exp_month.expose())
        .is_some_and(|new_exp_month| {
            existing_card_data
                .expiry_month
                .map(|exp_month| exp_month.expose())
                != Some(new_exp_month)
        })
        || card_updation_obj
            .card_exp_year
            .map(|exp_year| exp_year.expose())
            .is_some_and(|new_exp_year| {
                existing_card_data
                    .expiry_year
                    .map(|exp_year| exp_year.expose())
                    != Some(new_exp_year)
            })
        || card_updation_obj
            .card_holder_name
            .map(|name| name.expose())
            .is_some_and(|new_card_holder_name| {
                existing_card_data
                    .card_holder_name
                    .map(|name| name.expose())
                    != Some(new_card_holder_name)
            })
        || card_updation_obj
            .nick_name
            .map(|nick_name| nick_name.expose())
            .is_some_and(|new_nick_name| {
                existing_card_data
                    .nick_name
                    .map(|nick_name| nick_name.expose())
                    != Some(new_nick_name)
            })
}

#[cfg(feature = "v2")]
pub fn validate_payment_method_update(
    _card_updation_obj: CardDetailUpdate,
    _existing_card_data: api::CardDetailFromLocker,
) -> bool {
    todo!()
}

// Wrapper function to switch lockers

pub async fn get_card_from_locker(
    state: &routes::SessionState,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    card_reference: &str,
) -> errors::RouterResult<Card> {
    metrics::GET_FROM_LOCKER.add(1, &[]);

    let get_card_from_rs_locker_resp = common_utils::metrics::utils::record_operation_time(
        async {
            get_card_from_hs_locker(
                state,
                customer_id,
                merchant_id,
                card_reference,
                api_enums::LockerChoice::HyperswitchCardVault,
            )
            .await
            .change_context(errors::ApiErrorResponse::InternalServerError)
            .attach_printable("Failed while getting card from hyperswitch card vault")
            .inspect_err(|_| {
                metrics::CARD_LOCKER_FAILURES.add(
                    1,
                    router_env::metric_attributes!(("locker", "rust"), ("operation", "get")),
                );
            })
        },
        &metrics::CARD_GET_TIME,
        router_env::metric_attributes!(("locker", "rust")),
    )
    .await?;

    logger::debug!("card retrieved from rust locker");
    Ok(get_card_from_rs_locker_resp)
}

#[cfg(feature = "v2")]
pub async fn delete_card_by_locker_id(
    state: &routes::SessionState,
    id: &id_type::GlobalCustomerId,
    merchant_id: &id_type::MerchantId,
) -> errors::RouterResult<payment_methods::DeleteCardResp> {
    todo!()
}

#[instrument(skip_all)]
pub async fn decode_and_decrypt_locker_data(
    state: &routes::SessionState,
    key_store: &domain::MerchantKeyStore,
    enc_card_data: String,
) -> errors::CustomResult<Secret<String>, errors::VaultError> {
    let key = key_store.key.get_inner().peek();
    let decoded_bytes = hex::decode(&enc_card_data)
        .change_context(errors::VaultError::ResponseDeserializationFailed)
        .attach_printable("Failed to decode hex string into bytes")?;
    // Decrypt
    domain::types::crypto_operation(
        &state.into(),
        type_name!(payment_method::PaymentMethod),
        domain::types::CryptoOperation::DecryptOptional(Some(Encryption::new(
            decoded_bytes.into(),
        ))),
        Identifier::Merchant(key_store.merchant_id.clone()),
        key,
    )
    .await
    .and_then(|val| val.try_into_optionaloperation())
    .change_context(errors::VaultError::FetchPaymentMethodFailed)?
    .map_or(
        Err(report!(errors::VaultError::FetchPaymentMethodFailed)),
        |d| Ok(d.into_inner()),
    )
}

#[instrument(skip_all)]
pub async fn get_payment_method_from_hs_locker<'a>(
    state: &'a routes::SessionState,
    key_store: &domain::MerchantKeyStore,
    customer_id: &id_type::CustomerId,
    merchant_id: &id_type::MerchantId,
    payment_method_reference: &'a str,
    locker_choice: Option<api_enums::LockerChoice>,
) -> errors::CustomResult<Secret<String>, errors::VaultError> {
    let locker = &state.conf.locker;
    let jwekey = state.conf.jwekey.get_inner();

    let payment_method_data = if !locker.mock_locker {
        let request = payment_methods::mk_get_card_request_hs(
            jwekey,
            locker,
            customer_id,
            merchant_id,
            payment_method_reference,
            locker_choice,
            state.tenant.tenant_id.clone(),
            state.request_id,
        )
        .await
        .change_context(errors::VaultError::FetchPaymentMethodFailed)
        .attach_printable("Making get payment method request failed")?;

        let get_card_resp = call_locker_api::<payment_methods::RetrieveCardResp>(
            state,
            request,
            "get_pm_from_locker",
            locker_choice,
        )
        .await
        .change_context(errors::VaultError::FetchPaymentMethodFailed)?;

        let retrieve_card_resp = get_card_resp
            .payload
            .get_required_value("RetrieveCardRespPayload")
            .change_context(errors::VaultError::FetchPaymentMethodFailed)
            .attach_printable("Failed to retrieve field - payload from RetrieveCardResp")?;
        let enc_card_data = retrieve_card_resp
            .enc_card_data
            .get_required_value("enc_card_data")
            .change_context(errors::VaultError::FetchPaymentMethodFailed)
            .attach_printable(
                "Failed to retrieve field - enc_card_data from RetrieveCardRespPayload",
            )?;
        decode_and_decrypt_locker_data(state, key_store, enc_card_data.peek().to_string()).await?
    } else {
        mock_get_payment_method(state, key_store, payment_method_reference)
            .await?
            .payment_method
            .payment_method_data
    };
    Ok(payment_method_data)
}

#[instrument(skip_all)]
pub async fn add_card_to_hs_locker(
    state: &routes::SessionState,
    payload: &payment_methods::StoreLockerReq,
    customer_id: &id_type::CustomerId,
    locker_choice: api_enums::LockerChoice,
) -> errors::CustomResult<payment_methods::StoreCardRespPayload, errors::VaultError> {
    let locker = &state.conf.locker;
    let jwekey = state.conf.jwekey.get_inner();
    let db = &*state.store;
    let stored_card_response = if !locker.mock_locker {
        let request = payment_methods::mk_add_locker_request_hs(
            jwekey,
            locker,
            payload,
            locker_choice,
            state.tenant.tenant_id.clone(),
            state.request_id,
        )
        .await?;
        call_locker_api::<payment_methods::StoreCardResp>(
            state,
            request,
            "add_card_to_hs_locker",
            Some(locker_choice),
        )
        .await
        .change_context(errors::VaultError::SaveCardFailed)?
    } else {
        let card_id = generate_id(consts::ID_LENGTH, "card");
        mock_call_to_locker_hs(db, &card_id, payload, None, None, Some(customer_id)).await?
    };

    let stored_card = stored_card_response
        .payload
        .get_required_value("StoreCardRespPayload")
        .change_context(errors::VaultError::SaveCardFailed)?;
    Ok(stored_card)
}

#[instrument(skip_all)]
pub async fn call_locker_api<T>(
    state: &routes::SessionState,
    request: Request,
    flow_name: &str,
    locker_choice: Option<api_enums::LockerChoice>,
) -> errors::CustomResult<T, errors::VaultError>
where
    T: serde::de::DeserializeOwned,
{
    let locker = &state.conf.locker;
    let jwekey = state.conf.jwekey.get_inner();
    let response_type_name = type_name!(T);

    let response = services::call_connector_api(state, request, flow_name)
        .await
        .change_context(errors::VaultError::ApiError)?;

    let is_locker_call_succeeded = response.is_ok();

    let jwe_body = response
        .unwrap_or_else(|err| err)
        .response
        .parse_struct::<services::JweBody>("JweBody")
        .change_context(errors::VaultError::ResponseDeserializationFailed)
        .attach_printable("Failed while parsing locker response into JweBody")?;

    let decrypted_payload = payment_methods::get_decrypted_response_payload(
        jwekey,
        jwe_body,
        locker_choice,
        locker.decryption_scheme.clone(),
    )
    .await
    .change_context(errors::VaultError::ResponseDeserializationFailed)
    .attach_printable("Failed while decrypting locker payload response")?;

    // Irrespective of locker's response status, payload is JWE + JWS decrypted. But based on locker's status,
    // if Ok, deserialize the decrypted payload into given type T
    // if Err, raise an error including locker error message too


impl Responder {
    let card_iin = path.into_inner();
    let request_params = payload.into_inner();

    let payload = api_models::cards_info::CardsInfoRequest {
        client_secret: request_params.client_secret,
        card_iin,
    };

    let api_auth = auth::ApiKeyAuth::default();

    let (auth, _) = match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth)
    {
        Ok((auth, _auth_flow)) => (auth, _auth_flow),
        Err(e) => return api::log_and_return_error_response(e),
    };

    Box::pin(api::server_wrap(
        Flow::CardsInfo,
        state,
        &req,
        payload,
        |state, auth, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            cards_info::retrieve_card_info(state, merchant_context, req)
        },
        &*auth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct TokenizedBankTransferValue2 {
    pub customer_id: Option<id_type::CustomerId>,
}


File: crates/router/src/types/storage/gsm.rs

pub use diesel_models::gsm::{
    GatewayStatusMap, GatewayStatusMapperUpdateInternal, GatewayStatusMappingNew,
    GatewayStatusMappingUpdate,
};


pub async fn log_payout(
        &self,
        payout: &KafkaPayout<'_>,
        old_payout: Option<KafkaPayout<'_>>,
        tenant_id: TenantID,
    ) -> MQResult<()> {
        if let Some(negative_event) = old_payout {
            self.log_event(&KafkaEvent::old(
                &negative_event,
                tenant_id.clone(),
                self.ckh_database_name.clone(),
            ))
            .attach_printable_lazy(|| {
                format!("Failed to add negative payout event {negative_event:?}")
            })?;
        };
        self.log_event(&KafkaEvent::new(
            payout,
            tenant_id.clone(),
            self.ckh_database_name.clone(),
        ))
        .attach_printable_lazy(|| format!("Failed to add positive payout event {payout:?}"))
    }


pub fn update_straight_through_routing<F, D>(
    payment_data: &mut D,
    request_straight_through: serde_json::Value,
) -> CustomResult<(), errors::ParsingError>
where
    F: Send + Clone,
    D: OperationSessionGetters<F> + OperationSessionSetters<F> + Send + Sync + Clone,
{
    let _: api_models::routing::StaticRoutingAlgorithm = request_straight_through
        .clone()
        .parse_value("RoutingAlgorithm")
        .attach_printable("Invalid straight through routing rules format")?;

    payment_data.set_straight_through_algorithm_in_payment_attempt(request_straight_through);

    Ok(())
}


pub struct AuthorizedotnetErrorResponse {
    pub error: ErrorDetails,
}


/// Get gateway response (like Fiserv's gateway_response)
    pub fn gateway_response(&self) -> AuthipayGatewayResponse {
        AuthipayGatewayResponse {
            transaction_state: self.get_transaction_status(),
            transaction_processing_details: AuthipayTransactionProcessingDetails {
                order_id: self.order_id.clone(),
                transaction_id: self.ipg_transaction_id.clone(),
            },
        }
    }


pub fn payments_to_payments_response<Op, F: Clone, D>(
    _payment_data: D,
    _captures: Option<Vec<storage::Capture>>,
    _customer: Option<domain::Customer>,
    _auth_flow: services::AuthFlow,
    _base_url: &str,
    _operation: &Op,
    _connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig,
    _connector_http_status_code: Option<u16>,
    _external_latency: Option<u128>,
    _is_latency_header_enabled: Option<bool>,
) -> RouterResponse<api_models::payments::PaymentsResponse>
where
    Op: Debug,
    D: OperationSessionGetters<F>,
{
    todo!()
}


pub struct NetworkSubField {
    #[serde(rename = "@fieldNumber")]
    pub field_number: String,
    pub field_value: String,
}


File: crates/pm_auth/src/connector/plaid/transformers.rs
 Public structs: 21

use std::collections::HashMap;

use common_enums::{PaymentMethod, PaymentMethodType};
use common_utils::{id_type, types as util_types};
use masking::{PeekInterface, Secret};
use serde::{Deserialize, Serialize};

use crate::{core::errors, types};

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct PlaidLinkTokenRequest {
    client_name: String,
    country_codes: Vec<String>,
    language: String,
    products: Vec<String>,
    user: User,
    android_package_name: Option<String>,
    redirect_uri: Option<String>,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
pub struct User {
    pub client_user_id: id_type::CustomerId,
}

impl TryFrom<&types::LinkTokenRouterData> for PlaidLinkTokenRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::LinkTokenRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            client_name: item.request.client_name.clone(),
            country_codes: item.request.country_codes.clone().ok_or(
                errors::ConnectorError::MissingRequiredField {
                    field_name: "country_codes",
                },
            )?,
            language: item.request.language.clone().unwrap_or("en".to_string()),
            products: vec!["auth".to_string()],
            user: User {
                client_user_id: item.request.user_info.clone().ok_or(
                    errors::ConnectorError::MissingRequiredField {
                        field_name: "country_codes",
                    },
                )?,
            },
            android_package_name: match item.request.client_platform {
                Some(api_models::enums::ClientPlatform::Android) => {
                    item.request.android_package_name.clone()
                }
                Some(api_models::enums::ClientPlatform::Ios)
                | Some(api_models::enums::ClientPlatform::Web)
                | Some(api_models::enums::ClientPlatform::Unknown)
                | None => None,
            },
            redirect_uri: match item.request.client_platform {
                Some(api_models::enums::ClientPlatform::Ios) => item.request.redirect_uri.clone(),
                Some(api_models::enums::ClientPlatform::Android)
                | Some(api_models::enums::ClientPlatform::Web)
                | Some(api_models::enums::ClientPlatform::Unknown)
                | None => None,
            },
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct PlaidLinkTokenResponse {
    link_token: String,
}

impl<F, T>
    TryFrom<types::ResponseRouterData<F, PlaidLinkTokenResponse, T, types::LinkTokenResponse>>
    for types::PaymentAuthRouterData<F, T, types::LinkTokenResponse>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: types::ResponseRouterData<F, PlaidLinkTokenResponse, T, types::LinkTokenResponse>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(types::LinkTokenResponse {
                link_token: item.response.link_token,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct PlaidExchangeTokenRequest {
    public_token: String,
}

#[derive(Debug, Deserialize, Eq, PartialEq)]
pub struct PlaidExchangeTokenResponse {
    pub access_token: String,
}

impl<F, T>
    TryFrom<
        types::ResponseRouterData<F, PlaidExchangeTokenResponse, T, types::ExchangeTokenResponse>,
    > for types::PaymentAuthRouterData<F, T, types::ExchangeTokenResponse>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: types::ResponseRouterData<
            F,
            PlaidExchangeTokenResponse,
            T,
            types::ExchangeTokenResponse,
        >,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            response: Ok(types::ExchangeTokenResponse {
                access_token: item.response.access_token,
            }),
            ..item.data
        })
    }
}

impl TryFrom<&types::ExchangeTokenRouterData> for PlaidExchangeTokenRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::ExchangeTokenRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            public_token: item.request.public_token.clone(),
        })
    }
}

#[derive(Debug, Serialize, Eq, PartialEq)]
pub struct PlaidRecipientCreateRequest {
    pub name: String,
    #[serde(flatten)]
    pub account_data: PlaidRecipientAccountData,
    pub address: Option<PlaidRecipientCreateAddress>,
}

#[derive(Debug, Deserialize, Eq, PartialEq)]
pub struct PlaidRecipientCreateResponse {
    pub recipient_id: String,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum PlaidRecipientAccountData {
    Iban(Secret<String>),
    Bacs {
        sort_code: Secret<String>,
        account: Secret<String>,
    },
}

impl TryFrom<&types::RecipientAccountData> for PlaidRecipientAccountData {
    type Error = errors::ConnectorError;

    fn try_from(item: &types::RecipientAccountData) -> Result<Self, Self::Error> {
        match item {
            types::RecipientAccountData::Iban(iban) => Ok(Self::Iban(iban.clone())),
            types::RecipientAccountData::Bacs {
                sort_code,
                account_number,
            } => Ok(Self::Bacs {
                sort_code: sort_code.clone(),
                account: account_number.clone(),
            }),
            types::RecipientAccountData::FasterPayments { .. }
            | types::RecipientAccountData::Sepa(_)
            | types::RecipientAccountData::SepaInstant(_)
            | types::RecipientAccountData::Elixir { .. }
            | types::RecipientAccountData::Bankgiro(_)
            | types::RecipientAccountData::Plusgiro(_) => {
                Err(errors::ConnectorError::InvalidConnectorConfig {
                    config: "Invalid payment method selected. Only Iban, Bacs Supported",
                })
            }
        }
    }
}
#[derive(Debug, Serialize, Eq, PartialEq)]
pub struct PlaidRecipientCreateAddress {
    pub street: String,
    pub city: String,
    pub postal_code: String,
    pub country: String,
}

impl From<&types::RecipientCreateAddress> for PlaidRecipientCreateAddress {
    fn from(item: &types::RecipientCreateAddress) -> Self {
        Self {
            street: item.street.clone(),
            city: item.city.clone(),
            postal_code: item.postal_code.clone(),
            country: common_enums::CountryAlpha2::to_string(&item.country),
        }
    }
}

impl TryFrom<&types::RecipientCreateRouterData> for PlaidRecipientCreateRequest {
    type Error = errors::ConnectorError;

    fn try_from(item: &types::RecipientCreateRouterData) -> Result<Self, Self::Error> {
        Ok(Self {
            name: item.request.name.clone(),
            account_data: PlaidRecipientAccountData::try_from(&item.request.account_data)?,
            address: item
                .request
                .address
                .as_ref()
                .map(PlaidRecipientCreateAddress::from),
        })
    }
}

impl<F, T>
    From<
        types::ResponseRouterData<
            F,
            PlaidRecipientCreateResponse,
            T,
            types::RecipientCreateResponse,
        >,
    > for types::PaymentAuthRouterData<F, T, types::RecipientCreateResponse>
{
    fn from(
        item: types::ResponseRouterData<
            F,
            PlaidRecipientCreateResponse,
            T,
            types::RecipientCreateResponse,
        >,
    ) -> Self {
        Self {
            response: Ok(types::RecipientCreateResponse {
                recipient_id: item.response.recipient_id,
            }),
            ..item.data
        }
    }
}
#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct PlaidBankAccountCredentialsRequest {
    access_token: String,
    options: Option<BankAccountCredentialsOptions>,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct PlaidBankAccountCredentialsResponse {
    pub accounts: Vec<PlaidBankAccountCredentialsAccounts>,
    pub numbers: PlaidBankAccountCredentialsNumbers,
    // pub item: PlaidBankAccountCredentialsItem,
    pub request_id: String,
}

#[derive(Debug, Serialize, Eq, PartialEq)]
#[serde(rename_all = "snake_case")]
pub struct BankAccountCredentialsOptions {
    account_ids: Vec<String>,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct PlaidBankAccountCredentialsAccounts {
    pub account_id: String,
    pub name: String,
    pub subtype: Option<String>,
    pub balances: Option<PlaidBankAccountCredentialsBalances>,
}

#[derive(Debug, Deserialize, PartialEq)]
pub struct PlaidBankAccountCredentialsBalances {
    pub available: Option<util_types::FloatMajorUnit>,
    pub current: Option<util_types::FloatMajorUnit>,
    pub limit: Option<util_types::FloatMajorUnit>,
    pub iso_currency_code: Option<String>,
    pub unofficial_currency_code: Option<String>,
    pub last_updated_datetime: Option<String>,
}

#[derive(Debug, Deserialize, Eq, PartialEq)]
pub struct PlaidBankAccountCredentialsNumbers {
    pub ach: Vec<PlaidBankAccountCredentialsACH>,
    pub eft: Vec<PlaidBankAccountCredentialsEFT>,
    pub international: Vec<PlaidBankAccountCredentialsInternational>,
    pub bacs: Vec<PlaidBankAccountCredentialsBacs>,
}

#[derive(Debug, Deserialize, Eq, PartialEq)]
pub struct PlaidBankAccountCredentialsItem {
    pub item_id: String,
    pub institution_id: Option<String>,
    pub webhook: Option<String>,
    pub error: Option<PlaidErrorResponse>,
}
#[derive(Debug, Deserialize, Eq, PartialEq)]
pub struct PlaidBankAccountCredentialsACH {
    pub account_id: String,
    pub account: String,
    pub routing: String,
    pub wire_routing: Option<String>,
}

#[derive(Debug, Deserialize, Eq, PartialEq)]
pub struct PlaidBankAccountCredentialsEFT {
    pub account_id: String,
    pub account: String,
    pub institution: String,
    pub branch: String,
}

#[derive(Debug, Deserialize, Eq, PartialEq)]
pub struct PlaidBankAccountCredentialsInternational {
    pub account_id: String,
    pub iban: String,
    pub bic: String,
}

#[derive(Debug, Deserialize, Eq, PartialEq)]
pub struct PlaidBankAccountCredentialsBacs {
    pub account_id: String,
    pub account: String,
    pub sort_code: String,
}

impl TryFrom<&types::BankDetailsRouterData> for PlaidBankAccountCredentialsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(item: &types::BankDetailsRouterData) -> Result<Self, Self::Error> {
        let options = item.request.optional_ids.as_ref().map(|bank_account_ids| {
            let ids = bank_account_ids
                .ids
                .iter()
                .map(|id| id.peek().to_string())
                .collect::<Vec<_>>();

            BankAccountCredentialsOptions { account_ids: ids }
        });

        Ok(Self {
            access_token: item.request.access_token.peek().to_string(),
            options,
        })
    }
}

impl<F, T>
    TryFrom<
        types::ResponseRouterData<
            F,
            PlaidBankAccountCredentialsResponse,
            T,
            types::BankAccountCredentialsResponse,
        >,
    > for types::PaymentAuthRouterData<F, T, types::BankAccountCredentialsResponse>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: types::ResponseRouterData<
            F,
            PlaidBankAccountCredentialsResponse,
            T,
            types::BankAccountCredentialsResponse,
        >,
    ) -> Result<Self, Self::Error> {
        let (account_numbers, accounts_info) = (item.response.numbers, item.response.accounts);
        let mut bank_account_vec = Vec::new();
        let mut id_to_subtype = HashMap::new();

        accounts_info.into_iter().for_each(|acc| {
            id_to_subtype.insert(
                acc.account_id,
                (
                    acc.subtype,
                    acc.name,
                    acc.balances.and_then(|balance| balance.available),
                ),
            );
        });

        account_numbers.ach.into_iter().for_each(|ach| {
            let (acc_type, acc_name, available_balance) = if let Some((
                _type,
                name,
                available_balance,
            )) = id_to_subtype.get(&ach.account_id)
            {
                (_type.to_owned(), Some(name.clone()), *available_balance)
            } else {
                (None, None, None)
            };

            let account_details =
                types::PaymentMethodTypeDetails::Ach(types::BankAccountDetailsAch {
                    account_number: Secret::new(ach.account),
                    routing_number: Secret::new(ach.routing),
                });

            let bank_details_new = types::BankAccountDetails {
                account_name: acc_name,
                account_details,
                payment_method_type: PaymentMethodType::Ach,
                payment_method: PaymentMethod::BankDebit,
                account_id: ach.account_id.into(),
                account_type: acc_type,
                balance: available_balance,
            };

            bank_account_vec.push(bank_details_new);
        });

        account_numbers.bacs.into_iter().for_each(|bacs| {
            let (acc_type, acc_name, available_balance) =
                if let Some((_type, name, available_balance)) = id_to_subtype.get(&bacs.account_id)
                {
                    (_type.to_owned(), Some(name.clone()), *available_balance)
                } else {
                    (None, None, None)
                };

            let account_details =
                types::PaymentMethodTypeDetails::Bacs(types::BankAccountDetailsBacs {
                    account_number: Secret::new(bacs.account),
                    sort_code: Secret::new(bacs.sort_code),
                });

            let bank_details_new = types::BankAccountDetails {
                account_name: acc_name,
                account_details,
                payment_method_type: PaymentMethodType::Bacs,
                payment_method: PaymentMethod::BankDebit,
                account_id: bacs.account_id.into(),
                account_type: acc_type,
                balance: available_balance,
            };

            bank_account_vec.push(bank_details_new);
        });

        account_numbers.international.into_iter().for_each(|sepa| {
            let (acc_type, acc_name, available_balance) =
                if let Some((_type, name, available_balance)) = id_to_subtype.get(&sepa.account_id)
                {
                    (_type.to_owned(), Some(name.clone()), *available_balance)
                } else {
                    (None, None, None)
                };

            let account_details =
                types::PaymentMethodTypeDetails::Sepa(types::BankAccountDetailsSepa {
                    iban: Secret::new(sepa.iban),
                    bic: Secret::new(sepa.bic),
                });

            let bank_details_new = types::BankAccountDetails {
                account_name: acc_name,
                account_details,
                payment_method_type: PaymentMethodType::Sepa,
                payment_method: PaymentMethod::BankDebit,
                account_id: sepa.account_id.into(),
                account_type: acc_type,
                balance: available_balance,
            };

            bank_account_vec.push(bank_details_new);
        });

        Ok(Self {
            response: Ok(types::BankAccountCredentialsResponse {
                credentials: bank_account_vec,
            }),
            ..item.data
        })
    }
}
pub struct PlaidAuthType {
    pub client_id: Secret<String>,
    pub secret: Secret<String>,
}

impl TryFrom<&types::ConnectorAuthType> for PlaidAuthType {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            types::ConnectorAuthType::BodyKey { client_id, secret } => Ok(Self {
                client_id: client_id.to_owned(),
                secret: secret.to_owned(),
            }),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

#[derive(Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct PlaidErrorResponse {
    pub display_message: Option<String>,
    pub error_code: Option<String>,
    pub error_message: String,
    pub error_type: Option<String>,
}


OpenAPI Block Path: paths."/routing"
{
  "post": {
    "tags": [
      "Routing"
    ],
    "summary": "Routing - Create",
    "description": "Create a routing config",
    "operationId": "Create a routing config",
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/RoutingConfigRequest"
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "Routing config created",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RoutingDictionaryRecord"
            }
          }
        }
      },
      "400": {
        "description": "Request body is malformed"
      },
      "403": {
        "description": "Forbidden"
      },
      "404": {
        "description": "Resource missing"
      },
      "422": {
        "description": "Unprocessable request"
      },
      "500": {
        "description": "Internal server error"
      }
    },
    "security": [
      {
        "api_key": []
      },
      {
        "jwt_key": []
      }
    ]
  },
  "get": {
    "tags": [
      "Routing"
    ],
    "summary": "Routing - List",
    "description": "List all routing configs",
    "operationId": "List routing configs",
    "parameters": [
      {
        "name": "limit",
        "in": "query",
        "description": "The number of records to be returned",
        "required": false,
        "schema": {
          "type": "integer",
          "format": "int32",
          "nullable": true,
          "minimum": 0
        }
      },
      {
        "name": "offset",
        "in": "query",
        "description": "The record offset from which to start gathering of results",
        "required": false,
        "schema": {
          "type": "integer",
          "format": "int32",
          "nullable": true,
          "minimum": 0
        }
      },
      {
        "name": "profile_id",
        "in": "query",
        "description": "The unique identifier for a merchant profile",
        "required": false,
        "schema": {
          "type": "string",
          "nullable": true
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Successfully fetched routing configs",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RoutingKind"
            }
          }
        }
      },
      "404": {
        "description": "Resource missing"
      },
      "500": {
        "description": "Internal server error"
      }
    },
    "security": [
      {
        "api_key": []
      },
      {
        "jwt_key": []
      }
    ]
  }
}


pub struct SamsungPayFluidDataValue {
    public_key_hash: Secret<String>,
    version: String,
    data: Secret<String>,
}


/// Extract merchant_tax_registration_id from merchant_details
    pub fn get_merchant_tax_registration_id(&self) -> Option<Secret<String>> {
        self.merchant_details.as_ref().and_then(|details| {
            details
                .get_inner()
                .peek()
                .get("merchant_tax_registration_id")
                .and_then(|id| id.as_str().map(|s| Secret::new(s.to_string())))
        })
    }


pub struct BreadpayCartOptions {
    order_ref: Option<String>,
    complete_url: String,
    callback_url: String,
    // billing_contact: Option<BillingContact>,
}


File: crates/kgraph_utils/src/error.rs

#[cfg(feature = "v2")]
use common_enums::connector_enums;
use euclid::{dssa::types::AnalysisErrorType, frontend::dir};
#[derive(Debug, thiserror::Error, serde::Serialize)]
#[serde(tag = "type", content = "info", rename_all = "snake_case")]
pub enum KgraphError {
    #[error("Invalid connector name encountered: '{0}'")]
    InvalidConnectorName(
        #[cfg(feature = "v1")] String,
        #[cfg(feature = "v2")] connector_enums::Connector,
    ),
    #[error("Error in domain creation")]
    DomainCreationError,
    #[error("There was an error constructing the graph: {0}")]
    GraphConstructionError(hyperswitch_constraint_graph::GraphError<dir::DirValue>),
    #[error("There was an error constructing the context")]
    ContextConstructionError(Box<AnalysisErrorType>),
    #[error("there was an unprecedented indexing error")]
    IndexingError,
}


impl api::PaymentToken for Klarna {}


impl api::Refund for Prophetpay {}


pub struct Destination {
    full_name: Secret<String>,
    organization: Option<String>,
    email: Option<Email>,
    address: Address,
}


File: crates/hyperswitch_connectors/src/connectors/globalpay/response.rs
 Public structs: 9

use common_enums::Currency;
use common_utils::types::StringMinorUnit;
use masking::Secret;
use serde::{Deserialize, Serialize};

use crate::utils::deserialize_optional_currency;

#[derive(Debug, Serialize, Deserialize)]
pub struct GlobalpayPaymentsResponse {
    pub status: GlobalpayPaymentStatus,
    pub payment_method: Option<PaymentMethod>,
    pub id: String,
    pub amount: Option<StringMinorUnit>,
    #[serde(deserialize_with = "deserialize_optional_currency")]
    pub currency: Option<Currency>,
    pub reference: Option<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct GlobalpayRefreshTokenResponse {
    pub token: Secret<String>,
    pub seconds_to_expire: i64,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct GlobalpayRefreshTokenErrorResponse {
    pub error_code: String,
    pub detailed_error_description: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PaymentMethod {
    pub apm: Option<Apm>,
    pub card: Option<Card>,
    pub id: Option<Secret<String>>,
    pub message: Option<String>,
    pub result: Option<String>,
}

/// Data associated with the response of an APM transaction.
#[derive(Debug, Serialize, Deserialize)]
pub struct Apm {
    #[serde(alias = "provider_redirect_url")]
    pub redirect_url: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Card {
    pub brand_reference: Option<Secret<String>>,
}

/// A string used to identify the payment method provider being used to execute this
/// transaction.
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ApmProvider {
    Giropay,
    Ideal,
    Paypal,
    Sofort,
    Eps,
    Testpay,
}

/// Indicates where a transaction is in its lifecycle.
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GlobalpayPaymentStatus {
    /// A Transaction has been successfully authorized and captured. The funding
    /// process will commence once the transaction remains in this status.
    Captured,
    /// A Transaction where the payment method provider declined the transfer of
    /// funds between the payer and the merchant.
    Declined,
    /// A Transaction where the funds have transferred between payer and merchant as
    /// expected.
    Funded,
    /// A Transaction has been successfully initiated. An update on its status is
    /// expected via a separate asynchronous notification to a webhook.
    Initiated,
    /// A Transaction has been sent to the payment method provider and are waiting
    /// for a result.
    Pending,
    /// A Transaction has been approved but a capture request is required to
    /// commence the movement of funds.
    Preauthorized,
    /// A Transaction where the funds were expected to transfer between payer and
    /// merchant but the transfer was rejected during the funding process. This rarely happens
    /// but when it does it is usually addressed by Global Payments operations.
    Rejected,
    /// A Transaction that had a status of PENDING, PREAUTHORIZED or CAPTURED has
    /// subsequently been reversed which voids/cancels a transaction before it is funded.
    Reversed,
}

#[derive(Debug, Deserialize)]
pub struct GlobalpayWebhookObjectId {
    pub id: String,
}

#[derive(Debug, Deserialize)]
pub struct GlobalpayWebhookObjectEventType {
    pub status: GlobalpayWebhookStatus,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GlobalpayWebhookStatus {
    Declined,
    Captured,
    #[serde(other)]
    Unknown,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum GlobalpayPaymentMethodStatus {
    /// The entity is ACTIVE and can be used.
    Active,
    /// The entity is INACTIVE and cannot be used.
    Inactive,
    /// The status is DELETED. Once returned in an action response for a resource.
    /// The resource has been removed from the platform.
    Delete,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct GlobalpayPaymentMethodsResponse {
    #[serde(rename = "id")]
    pub payment_method_token_id: Option<Secret<String>>,
    pub card: Card,
}


File: crates/hyperswitch_connectors/src/connectors/cashtocode/transformers.rs
 Public structs: 8

use std::collections::HashMap;

use common_enums::enums;
pub use common_utils::request::Method;
use common_utils::{
    errors::CustomResult, ext_traits::ValueExt, id_type, pii::Email, types::FloatMajorUnit,
};
use error_stack::ResultExt;
use hyperswitch_domain_models::{
    router_data::{ConnectorAuthType, ErrorResponse, RouterData},
    router_request_types::{PaymentsAuthorizeData, ResponseId},
    router_response_types::{PaymentsResponseData, RedirectForm},
    types::PaymentsAuthorizeRouterData,
};
use hyperswitch_interfaces::errors;
use masking::Secret;
use serde::{Deserialize, Serialize};

use crate::{
    types::ResponseRouterData,
    utils::{self, PaymentsAuthorizeRequestData, RouterData as OtherRouterData},
};

#[derive(Default, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CashtocodePaymentsRequest {
    amount: FloatMajorUnit,
    transaction_id: String,
    user_id: Secret<id_type::CustomerId>,
    currency: enums::Currency,
    first_name: Option<Secret<String>>,
    last_name: Option<Secret<String>>,
    user_alias: Secret<id_type::CustomerId>,
    requested_url: String,
    cancel_url: String,
    email: Option<Email>,
    mid: Secret<String>,
}

fn get_mid(
    connector_auth_type: &ConnectorAuthType,
    payment_method_type: Option<enums::PaymentMethodType>,
    currency: enums::Currency,
) -> Result<Secret<String>, errors::ConnectorError> {
    match CashtocodeAuth::try_from((connector_auth_type, &currency)) {
        Ok(cashtocode_auth) => match payment_method_type {
            Some(enums::PaymentMethodType::ClassicReward) => Ok(cashtocode_auth
                .merchant_id_classic
                .ok_or(errors::ConnectorError::FailedToObtainAuthType)?),
            Some(enums::PaymentMethodType::Evoucher) => Ok(cashtocode_auth
                .merchant_id_evoucher
                .ok_or(errors::ConnectorError::FailedToObtainAuthType)?),
            _ => Err(errors::ConnectorError::FailedToObtainAuthType),
        },
        Err(_) => Err(errors::ConnectorError::FailedToObtainAuthType)?,
    }
}

impl TryFrom<(&PaymentsAuthorizeRouterData, FloatMajorUnit)> for CashtocodePaymentsRequest {
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        (item, amount): (&PaymentsAuthorizeRouterData, FloatMajorUnit),
    ) -> Result<Self, Self::Error> {
        let customer_id = item.get_customer_id()?;
        let url = item.request.get_router_return_url()?;
        let mid = get_mid(
            &item.connector_auth_type,
            item.request.payment_method_type,
            item.request.currency,
        )?;
        match item.payment_method {
            enums::PaymentMethod::Reward => Ok(Self {
                amount,
                transaction_id: item.attempt_id.clone(),
                currency: item.request.currency,
                user_id: Secret::new(customer_id.to_owned()),
                first_name: None,
                last_name: None,
                user_alias: Secret::new(customer_id),
                requested_url: url.to_owned(),
                cancel_url: url,
                email: item.request.email.clone(),
                mid,
            }),
            _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
        }
    }
}

#[derive(Default, Debug, Deserialize)]
pub struct CashtocodeAuthType {
    pub auths: HashMap<enums::Currency, CashtocodeAuth>,
}

#[derive(Default, Debug, Deserialize)]
pub struct CashtocodeAuth {
    pub password_classic: Option<Secret<String>>,
    pub password_evoucher: Option<Secret<String>>,
    pub username_classic: Option<Secret<String>>,
    pub username_evoucher: Option<Secret<String>>,
    pub merchant_id_classic: Option<Secret<String>>,
    pub merchant_id_evoucher: Option<Secret<String>>,
}

impl TryFrom<&ConnectorAuthType> for CashtocodeAuthType {
    type Error = error_stack::Report<errors::ConnectorError>; // Assuming ErrorStack is the appropriate error type

    fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
        match auth_type {
            ConnectorAuthType::CurrencyAuthKey { auth_key_map } => {
                let transformed_auths = auth_key_map
                    .iter()
                    .map(|(currency, identity_auth_key)| {
                        let cashtocode_auth = identity_auth_key
                            .to_owned()
                            .parse_value::<CashtocodeAuth>("CashtocodeAuth")
                            .change_context(errors::ConnectorError::InvalidDataFormat {
                                field_name: "auth_key_map",
                            })?;

                        Ok((currency.to_owned(), cashtocode_auth))
                    })
                    .collect::<Result<_, Self::Error>>()?;

                Ok(Self {
                    auths: transformed_auths,
                })
            }
            _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
        }
    }
}

impl TryFrom<(&ConnectorAuthType, &enums::Currency)> for CashtocodeAuth {
    type Error = error_stack::Report<errors::ConnectorError>;

    fn try_from(value: (&ConnectorAuthType, &enums::Currency)) -> Result<Self, Self::Error> {
        let (auth_type, currency) = value;

        if let ConnectorAuthType::CurrencyAuthKey { auth_key_map } = auth_type {
            if let Some(identity_auth_key) = auth_key_map.get(currency) {
                let cashtocode_auth: Self = identity_auth_key
                    .to_owned()
                    .parse_value("CashtocodeAuth")
                    .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
                Ok(cashtocode_auth)
            } else {
                Err(errors::ConnectorError::CurrencyNotSupported {
                    message: currency.to_string(),
                    connector: "CashToCode",
                }
                .into())
            }
        } else {
            Err(errors::ConnectorError::FailedToObtainAuthType.into())
        }
    }
}

#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum CashtocodePaymentStatus {
    Succeeded,
    #[default]
    Processing,
}

impl From<CashtocodePaymentStatus> for enums::AttemptStatus {
    fn from(item: CashtocodePaymentStatus) -> Self {
        match item {
            CashtocodePaymentStatus::Succeeded => Self::Charged,
            CashtocodePaymentStatus::Processing => Self::AuthenticationPending,
        }
    }
}

#[derive(Debug, Deserialize, Clone, Serialize)]
pub struct CashtocodeErrors {
    pub message: String,
    pub path: String,
    #[serde(rename = "type")]
    pub event_type: String,
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum CashtocodePaymentsResponse {
    CashtoCodeError(CashtocodeErrorResponse),
    CashtoCodeData(CashtocodePaymentsResponseData),
}

#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CashtocodePaymentsResponseData {
    pub pay_url: url::Url,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CashtocodePaymentsSyncResponse {
    pub transaction_id: String,
    pub amount: FloatMajorUnit,
}

fn get_redirect_form_data(
    payment_method_type: enums::PaymentMethodType,
    response_data: CashtocodePaymentsResponseData,
) -> CustomResult<RedirectForm, errors::ConnectorError> {
    match payment_method_type {
        enums::PaymentMethodType::ClassicReward => Ok(RedirectForm::Form {
            //redirect form is manually constructed because the connector for this pm type expects query params in the url
            endpoint: response_data.pay_url.to_string(),
            method: Method::Post,
            form_fields: Default::default(),
        }),
        enums::PaymentMethodType::Evoucher => Ok(RedirectForm::from((
            //here the pay url gets parsed, and query params are sent as formfields as the connector expects
            response_data.pay_url,
            Method::Get,
        ))),
        _ => Err(errors::ConnectorError::NotImplemented(
            utils::get_unimplemented_payment_method_error_message("CashToCode"),
        ))?,
    }
}

impl<F>
    TryFrom<
        ResponseRouterData<
            F,
            CashtocodePaymentsResponse,
            PaymentsAuthorizeData,
            PaymentsResponseData,
        >,
    > for RouterData<F, PaymentsAuthorizeData, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<
            F,
            CashtocodePaymentsResponse,
            PaymentsAuthorizeData,
            PaymentsResponseData,
        >,
    ) -> Result<Self, Self::Error> {
        let (status, response) = match item.response {
            CashtocodePaymentsResponse::CashtoCodeError(error_data) => (
                enums::AttemptStatus::Failure,
                Err(ErrorResponse {
                    code: error_data.error.to_string(),
                    status_code: item.http_code,
                    message: error_data.error_description.clone(),
                    reason: Some(error_data.error_description),
                    attempt_status: None,
                    connector_transaction_id: None,
                    network_advice_code: None,
                    network_decline_code: None,
                    network_error_message: None,
                    connector_metadata: None,
                }),
            ),
            CashtocodePaymentsResponse::CashtoCodeData(response_data) => {
                let payment_method_type = item
                    .data
                    .request
                    .payment_method_type
                    .ok_or(errors::ConnectorError::MissingPaymentMethodType)?;
                let redirection_data = get_redirect_form_data(payment_method_type, response_data)?;
                (
                    enums::AttemptStatus::AuthenticationPending,
                    Ok(PaymentsResponseData::TransactionResponse {
                        resource_id: ResponseId::ConnectorTransactionId(
                            item.data.attempt_id.clone(),
                        ),
                        redirection_data: Box::new(Some(redirection_data)),
                        mandate_reference: Box::new(None),
                        connector_metadata: None,
                        network_txn_id: None,
                        connector_response_reference_id: None,
                        incremental_authorization_allowed: None,
                        charges: None,
                    }),
                )
            }
        };

        Ok(Self {
            status,
            response,
            ..item.data
        })
    }
}

impl<F, T> TryFrom<ResponseRouterData<F, CashtocodePaymentsSyncResponse, T, PaymentsResponseData>>
    for RouterData<F, T, PaymentsResponseData>
{
    type Error = error_stack::Report<errors::ConnectorError>;
    fn try_from(
        item: ResponseRouterData<F, CashtocodePaymentsSyncResponse, T, PaymentsResponseData>,
    ) -> Result<Self, Self::Error> {
        Ok(Self {
            status: enums::AttemptStatus::Charged, // Charged status is hardcoded because cashtocode do not support Psync, and we only receive webhooks when payment is succeeded, this tryFrom is used for CallConnectorAction.
            response: Ok(PaymentsResponseData::TransactionResponse {
                resource_id: ResponseId::ConnectorTransactionId(
                    item.data.attempt_id.clone(), //in response they only send PayUrl, so we use attempt_id as connector_transaction_id
                ),
                redirection_data: Box::new(None),
                mandate_reference: Box::new(None),
                connector_metadata: None,
                network_txn_id: None,
                connector_response_reference_id: None,
                incremental_authorization_allowed: None,
                charges: None,
            }),
            ..item.data
        })
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct CashtocodeErrorResponse {
    pub error: serde_json::Value,
    pub error_description: String,
    pub errors: Option<Vec<CashtocodeErrors>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CashtocodeIncomingWebhook {
    pub amount: FloatMajorUnit,
    pub currency: String,
    pub foreign_transaction_id: String,
    #[serde(rename = "type")]
    pub event_type: String,
    pub transaction_id: String,
}


impl api::Refund for Airwallex {}


pub struct WorldpayXmlErrorResponse {
    #[serde(rename = "@code")]
    pub code: String,
    #[serde(rename = "$value")]
    pub message: String,
}


pub async fn payment_confirm_intent(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    json_payload: web::Json<api_models::payments::PaymentsConfirmIntentRequest>,
    path: web::Path<common_utils::id_type::GlobalPaymentId>,
) -> impl Responder {
    use hyperswitch_domain_models::payments::PaymentConfirmData;

    let flow = Flow::PaymentsConfirmIntent;

    // TODO: Populate browser information into the payload
    // if let Err(err) = helpers::populate_ip_into_browser_info(&req, &mut payload) {
    //     return api::log_and_return_error_response(err);
    // }

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

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

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

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

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

            let operation = payments::operations::PaymentIntentConfirm;
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));

            Box::pin(payments::payments_core::<
                api_types::Authorize,
                api_models::payments::PaymentsResponse,
                _,
                _,
                _,
                PaymentConfirmData<api_types::Authorize>,
            >(
                state,
                req_state,
                merchant_context,
                auth.profile,
                operation,
                request,
                payment_id,
                payments::CallConnectorAction::Trigger,
                header_payload.clone(),
            ))
            .await
        },
        auth::api_or_client_auth(
            &auth::V2ApiKeyAuth {
                is_connected_allowed: false,
                is_platform_allowed: false,
            },
            &auth::V2ClientAuth(common_utils::types::authentication::ResourceId::Payment(
                global_payment_id,
            )),
            req.headers(),
        ),
        locking_action,
    ))
    .await
}


pub async fn retrieve_extended_card_info(
    state: web::Data<app::AppState>,
    req: actix_web::HttpRequest,
    path: web::Path<common_utils::id_type::PaymentId>,
) -> impl Responder {
    let flow = Flow::GetExtendedCardInfo;
    let payment_id = path.into_inner();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payment_id,
        |state, auth: auth::AuthenticationData, payment_id, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            payments::get_extended_card_info(
                state,
                merchant_context.get_merchant_account().get_id().to_owned(),
                payment_id,
            )
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: true,
        }),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


File: crates/router/src/core/payments/flows/capture_flow.rs

use async_trait::async_trait;

use super::ConstructFlowSpecificData;
use crate::{
    core::{
        errors::{ConnectorErrorExt, RouterResult},
        payments::{self, access_token, helpers, transformers, Feature, PaymentData},
    },
    routes::SessionState,
    services,
    types::{self, api, domain},
};

#[cfg(feature = "v1")]
#[async_trait]
impl
    ConstructFlowSpecificData<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
    for PaymentData<api::Capture>
{
    async fn construct_router_data<'a>(
        &self,
        state: &SessionState,
        connector_id: &str,
        merchant_context: &domain::MerchantContext,
        customer: &Option<domain::Customer>,
        merchant_connector_account: &helpers::MerchantConnectorAccountType,
        merchant_recipient_data: Option<types::MerchantRecipientData>,
        header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
    ) -> RouterResult<types::PaymentsCaptureRouterData> {
        Box::pin(transformers::construct_payment_router_data::<
            api::Capture,
            types::PaymentsCaptureData,
        >(
            state,
            self.clone(),
            connector_id,
            merchant_context,
            customer,
            merchant_connector_account,
            merchant_recipient_data,
            header_payload,
        ))
        .await
    }
}

#[cfg(feature = "v2")]
#[async_trait]
impl
    ConstructFlowSpecificData<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
    for hyperswitch_domain_models::payments::PaymentCaptureData<api::Capture>
{
    async fn construct_router_data<'a>(
        &self,
        state: &SessionState,
        connector_id: &str,
        merchant_context: &domain::MerchantContext,
        customer: &Option<domain::Customer>,
        merchant_connector_account: &domain::MerchantConnectorAccountTypeDetails,
        merchant_recipient_data: Option<types::MerchantRecipientData>,
        header_payload: Option<hyperswitch_domain_models::payments::HeaderPayload>,
    ) -> RouterResult<
        types::RouterData<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>,
    > {
        Box::pin(transformers::construct_payment_router_data_for_capture(
            state,
            self.clone(),
            connector_id,
            merchant_context,
            customer,
            merchant_connector_account,
            merchant_recipient_data,
            header_payload,
        ))
        .await
    }
}

#[async_trait]
impl Feature<api::Capture, types::PaymentsCaptureData>
    for types::RouterData<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
{
    async fn decide_flows<'a>(
        self,
        state: &SessionState,
        connector: &api::ConnectorData,
        call_connector_action: payments::CallConnectorAction,
        connector_request: Option<services::Request>,
        _business_profile: &domain::Profile,
        _header_payload: hyperswitch_domain_models::payments::HeaderPayload,
        _return_raw_connector_response: Option<bool>,
    ) -> RouterResult<Self> {
        let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
            api::Capture,
            types::PaymentsCaptureData,
            types::PaymentsResponseData,
        > = connector.connector.get_connector_integration();

        let mut new_router_data = services::execute_connector_processing_step(
            state,
            connector_integration,
            &self,
            call_connector_action,
            connector_request,
            None,
        )
        .await
        .to_payment_failed_response()?;

        // Initiating Integrity check
        let integrity_result = helpers::check_integrity_based_on_flow(
            &new_router_data.request,
            &new_router_data.response,
        );
        new_router_data.integrity_check = integrity_result;

        Ok(new_router_data)
    }

    async fn add_access_token<'a>(
        &self,
        state: &SessionState,
        connector: &api::ConnectorData,
        merchant_context: &domain::MerchantContext,
        creds_identifier: Option<&str>,
    ) -> RouterResult<types::AddAccessTokenResult> {
        Box::pin(access_token::add_access_token(
            state,
            connector,
            merchant_context,
            self,
            creds_identifier,
        ))
        .await
    }

    async fn build_flow_specific_connector_request(
        &mut self,
        state: &SessionState,
        connector: &api::ConnectorData,
        call_connector_action: payments::CallConnectorAction,
    ) -> RouterResult<(Option<services::Request>, bool)> {
        let request = match call_connector_action {
            payments::CallConnectorAction::Trigger => {
                let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
                    api::Capture,
                    types::PaymentsCaptureData,
                    types::PaymentsResponseData,
                > = connector.connector.get_connector_integration();

                connector_integration
                    .build_request(self, &state.conf.connectors)
                    .to_payment_failed_response()?
            }
            _ => None,
        };

        Ok((request, true))
    }
}


impl IncomingWebhook for Nexinets {
    fn get_webhook_object_reference_id(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
        Ok(IncomingWebhookEvent::EventNotSupported)
    }

    fn get_webhook_resource_object(
        &self,
        _request: &IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}


OpenAPI Block Path: paths."/events/profile/list"
{
  "post": {
    "tags": [
      "Event"
    ],
    "summary": "Events - List",
    "description": "List all Events associated with a Profile.",
    "operationId": "List all Events associated with a Profile",
    "requestBody": {
      "description": "The constraints that can be applied when listing Events.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/EventListConstraints"
          },
          "examples": {
            "example": {
              "value": {
                "created_after": "2023-01-01T00:00:00",
                "created_before": "2023-01-31T23:59:59",
                "event_classes": [
                  "payments",
                  "refunds"
                ],
                "event_types": [
                  "payment_succeeded"
                ],
                "is_delivered": true,
                "limit": 5,
                "object_id": "{{object_id}}",
                "offset": 0,
                "profile_id": "{{profile_id}}"
              }
            }
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "List of Events retrieved successfully",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TotalEventsResponse"
            }
          }
        }
      }
    },
    "security": [
      {
        "jwt_key": []
      }
    ]
  }
}