Bug: [FEATURE] integrate NTI flow for Worldpay and Novalnet



### Feature Description

Processing card payments using Network Transaction ID is required for below payment processors -
- Fiuu
- Novalnet
- Worldpay

This helps make card payments agnostic to the acquirer.

### Possible Implementation

Fiuu - closed source
Novalnet - https://developer.novalnet.com/encryption/directapi (include `transaction.scheme_tid`)
Worldpay - https://developer.worldpay.com/products/access/payments/openapi/other/payment#other/payment/request (Unscheduled payments)

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

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

### Have you read the Contributing Guidelines?

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

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/config/config.example.toml b/config/config.example.toml
index 821e854c9fa..c860420da38 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -802,7 +802,7 @@ check_token_status_url= ""    # base url to check token status from token servic
 connector_list = "cybersource" # Supported connectors for network tokenization
 
 [network_transaction_id_supported_connectors]
-connector_list = "stripe,adyen,cybersource" # Supported connectors for network transaction id
+connector_list = "adyen,cybersource,novalnet,stripe,worldpay" # Supported connectors for network transaction id
 
 [grpc_client.dynamic_routing_client] # Dynamic Routing Client Configuration
 host = "localhost" # Client Host
diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml
index 6283382258a..b6e487e5a3b 100644
--- a/config/deployments/integration_test.toml
+++ b/config/deployments/integration_test.toml
@@ -191,7 +191,7 @@ card.credit = { connector_list = "cybersource" }            # Update Mandate sup
 card.debit = { connector_list = "cybersource" }             # Update Mandate supported payment method type and connector for card
 
 [network_transaction_id_supported_connectors]
-connector_list = "stripe,adyen,cybersource"
+connector_list = "adyen,cybersource,novalnet,stripe,worldpay"
 
 
 [payouts]
diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml
index fcfadb339d9..7242f263672 100644
--- a/config/deployments/sandbox.toml
+++ b/config/deployments/sandbox.toml
@@ -191,7 +191,7 @@ card.credit = { connector_list = "cybersource" }            # Update Mandate sup
 card.debit = { connector_list = "cybersource" }             # Update Mandate supported payment method type and connector for card 
 
 [network_transaction_id_supported_connectors]
-connector_list = "stripe,adyen,cybersource"
+connector_list = "adyen,cybersource,novalnet,stripe,worldpay"
 
 
 [payouts]
diff --git a/config/development.toml b/config/development.toml
index 08520a2a859..a32102aeebf 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -653,7 +653,7 @@ card.credit = { connector_list = "cybersource" }
 card.debit = { connector_list = "cybersource" }
 
 [network_transaction_id_supported_connectors]
-connector_list = "stripe,adyen,cybersource"
+connector_list = "adyen,cybersource,novalnet,stripe,worldpay"
 
 [connector_request_reference_id_config]
 merchant_ids_send_payment_id_as_connector_request_id = []
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index 6f95380d2db..cfdf4b0e0c2 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -540,7 +540,7 @@ card.credit = { connector_list = "cybersource" }
 card.debit = { connector_list = "cybersource" }
 
 [network_transaction_id_supported_connectors]
-connector_list = "stripe,adyen,cybersource"
+connector_list = "adyen,cybersource,novalnet,stripe,worldpay"
 
 [connector_customer]
 connector_list = "gocardless,stax,stripe"
diff --git a/crates/hyperswitch_connectors/src/connectors/fiuu.rs b/crates/hyperswitch_connectors/src/connectors/fiuu.rs
index 3ea8793d9f5..70bca41582c 100644
--- a/crates/hyperswitch_connectors/src/connectors/fiuu.rs
+++ b/crates/hyperswitch_connectors/src/connectors/fiuu.rs
@@ -254,16 +254,23 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
         req: &PaymentsAuthorizeRouterData,
         connectors: &Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
-        let url = if req.request.off_session == Some(true) {
-            format!(
+        let optional_is_mit_flow = req.request.off_session;
+        let optional_is_nti_flow = req
+            .request
+            .mandate_id
+            .as_ref()
+            .map(|mandate_id| mandate_id.is_network_transaction_id_flow());
+        let url = match (optional_is_mit_flow, optional_is_nti_flow) {
+            (Some(true), Some(false)) => format!(
                 "{}/RMS/API/Recurring/input_v7.php",
                 self.base_url(connectors)
-            )
-        } else {
-            format!(
-                "{}RMS/API/Direct/1.4.0/index.php",
-                self.base_url(connectors)
-            )
+            ),
+            _ => {
+                format!(
+                    "{}RMS/API/Direct/1.4.0/index.php",
+                    self.base_url(connectors)
+                )
+            }
         };
         Ok(url)
     }
@@ -280,14 +287,24 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
         )?;
 
         let connector_router_data = fiuu::FiuuRouterData::from((amount, req));
-        let connector_req = if req.request.off_session == Some(true) {
-            let recurring_request = fiuu::FiuuMandateRequest::try_from(&connector_router_data)?;
-            build_form_from_struct(recurring_request)
-                .change_context(errors::ConnectorError::ParsingFailed)?
-        } else {
-            let payment_request = fiuu::FiuuPaymentRequest::try_from(&connector_router_data)?;
-            build_form_from_struct(payment_request)
-                .change_context(errors::ConnectorError::ParsingFailed)?
+        let optional_is_mit_flow = req.request.off_session;
+        let optional_is_nti_flow = req
+            .request
+            .mandate_id
+            .as_ref()
+            .map(|mandate_id| mandate_id.is_network_transaction_id_flow());
+
+        let connector_req = match (optional_is_mit_flow, optional_is_nti_flow) {
+            (Some(true), Some(false)) => {
+                let recurring_request = fiuu::FiuuMandateRequest::try_from(&connector_router_data)?;
+                build_form_from_struct(recurring_request)
+                    .change_context(errors::ConnectorError::ParsingFailed)?
+            }
+            _ => {
+                let payment_request = fiuu::FiuuPaymentRequest::try_from(&connector_router_data)?;
+                build_form_from_struct(payment_request)
+                    .change_context(errors::ConnectorError::ParsingFailed)?
+            }
         };
         Ok(RequestContent::FormData(connector_req))
     }
diff --git a/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs b/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs
index e914454e557..51fc23eee41 100644
--- a/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs
@@ -14,8 +14,8 @@ use common_utils::{
 use error_stack::{Report, ResultExt};
 use hyperswitch_domain_models::{
     payment_method_data::{
-        BankRedirectData, Card, GooglePayWalletData, PaymentMethodData, RealTimePaymentData,
-        WalletData,
+        BankRedirectData, Card, CardDetailsForNetworkTransactionId, GooglePayWalletData,
+        PaymentMethodData, RealTimePaymentData, WalletData,
     },
     router_data::{
         ApplePayPredecryptData, ConnectorAuthType, ErrorResponse, PaymentMethodToken, RouterData,
@@ -287,6 +287,7 @@ pub struct FiuuPaymentRequest {
 pub enum FiuuPaymentMethodData {
     FiuuQRData(Box<FiuuQRData>),
     FiuuCardData(Box<FiuuCardData>),
+    FiuuCardWithNTI(Box<FiuuCardWithNTI>),
     FiuuFpxData(Box<FiuuFPXData>),
     FiuuGooglePayData(Box<FiuuGooglePayData>),
     FiuuApplePayData(Box<FiuuApplePayData>),
@@ -322,6 +323,18 @@ pub struct FiuuCardData {
     customer_email: Option<Email>,
 }
 
+#[derive(Serialize, Debug, Clone)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub struct FiuuCardWithNTI {
+    #[serde(rename = "TxnChannel")]
+    txn_channel: TxnChannel,
+    cc_pan: CardNumber,
+    cc_month: Secret<String>,
+    cc_year: Secret<String>,
+    #[serde(rename = "OriginalSchemeID")]
+    original_scheme_id: Secret<String>,
+}
+
 #[derive(Serialize, Debug, Clone)]
 #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
 pub struct FiuuApplePayData {
@@ -412,125 +425,150 @@ impl TryFrom<&FiuuRouterData<&PaymentsAuthorizeRouterData>> for FiuuPaymentReque
             Url::parse(&item.router_data.request.get_webhook_url()?)
                 .change_context(errors::ConnectorError::RequestEncodingFailed)?,
         );
-        let payment_method_data = match item.router_data.request.payment_method_data {
-            PaymentMethodData::Card(ref card) => {
-                FiuuPaymentMethodData::try_from((card, item.router_data))
-            }
-            PaymentMethodData::RealTimePayment(ref real_time_payment_data) => {
-                match *real_time_payment_data.clone() {
-                    RealTimePaymentData::DuitNow {} => {
-                        Ok(FiuuPaymentMethodData::FiuuQRData(Box::new(FiuuQRData {
-                            txn_channel: TxnChannel::RppDuitNowQr,
+        let payment_method_data = match item
+            .router_data
+            .request
+            .mandate_id
+            .clone()
+            .and_then(|mandate_id| mandate_id.mandate_reference_id)
+        {
+            None => match item.router_data.request.payment_method_data {
+                PaymentMethodData::Card(ref card) => {
+                    FiuuPaymentMethodData::try_from((card, item.router_data))
+                }
+                PaymentMethodData::RealTimePayment(ref real_time_payment_data) => {
+                    match *real_time_payment_data.clone() {
+                        RealTimePaymentData::DuitNow {} => {
+                            Ok(FiuuPaymentMethodData::FiuuQRData(Box::new(FiuuQRData {
+                                txn_channel: TxnChannel::RppDuitNowQr,
+                            })))
+                        }
+                        RealTimePaymentData::Fps {}
+                        | RealTimePaymentData::PromptPay {}
+                        | RealTimePaymentData::VietQr {} => {
+                            Err(errors::ConnectorError::NotImplemented(
+                                utils::get_unimplemented_payment_method_error_message("fiuu"),
+                            )
+                            .into())
+                        }
+                    }
+                }
+                PaymentMethodData::BankRedirect(ref bank_redirect_data) => match bank_redirect_data
+                {
+                    BankRedirectData::OnlineBankingFpx { ref issuer } => {
+                        Ok(FiuuPaymentMethodData::FiuuFpxData(Box::new(FiuuFPXData {
+                            txn_channel: FPXTxnChannel::try_from(*issuer)?,
+                            non_3ds,
                         })))
                     }
-                    RealTimePaymentData::Fps {}
-                    | RealTimePaymentData::PromptPay {}
-                    | RealTimePaymentData::VietQr {} => {
+                    BankRedirectData::BancontactCard { .. }
+                    | BankRedirectData::Bizum {}
+                    | BankRedirectData::Blik { .. }
+                    | BankRedirectData::Eps { .. }
+                    | BankRedirectData::Giropay { .. }
+                    | BankRedirectData::Ideal { .. }
+                    | BankRedirectData::Interac { .. }
+                    | BankRedirectData::OnlineBankingCzechRepublic { .. }
+                    | BankRedirectData::OnlineBankingFinland { .. }
+                    | BankRedirectData::OnlineBankingPoland { .. }
+                    | BankRedirectData::OnlineBankingSlovakia { .. }
+                    | BankRedirectData::OpenBankingUk { .. }
+                    | BankRedirectData::Przelewy24 { .. }
+                    | BankRedirectData::Sofort { .. }
+                    | BankRedirectData::Trustly { .. }
+                    | BankRedirectData::OnlineBankingThailand { .. }
+                    | BankRedirectData::LocalBankRedirect {} => {
                         Err(errors::ConnectorError::NotImplemented(
                             utils::get_unimplemented_payment_method_error_message("fiuu"),
                         )
                         .into())
                     }
-                }
-            }
-            PaymentMethodData::BankRedirect(ref bank_redirect_data) => match bank_redirect_data {
-                BankRedirectData::OnlineBankingFpx { ref issuer } => {
-                    Ok(FiuuPaymentMethodData::FiuuFpxData(Box::new(FiuuFPXData {
-                        txn_channel: FPXTxnChannel::try_from(*issuer)?,
-                        non_3ds,
-                    })))
-                }
-                BankRedirectData::BancontactCard { .. }
-                | BankRedirectData::Bizum {}
-                | BankRedirectData::Blik { .. }
-                | BankRedirectData::Eps { .. }
-                | BankRedirectData::Giropay { .. }
-                | BankRedirectData::Ideal { .. }
-                | BankRedirectData::Interac { .. }
-                | BankRedirectData::OnlineBankingCzechRepublic { .. }
-                | BankRedirectData::OnlineBankingFinland { .. }
-                | BankRedirectData::OnlineBankingPoland { .. }
-                | BankRedirectData::OnlineBankingSlovakia { .. }
-                | BankRedirectData::OpenBankingUk { .. }
-                | BankRedirectData::Przelewy24 { .. }
-                | BankRedirectData::Sofort { .. }
-                | BankRedirectData::Trustly { .. }
-                | BankRedirectData::OnlineBankingThailand { .. }
-                | BankRedirectData::LocalBankRedirect {} => {
+                },
+                PaymentMethodData::Wallet(ref wallet_data) => match wallet_data {
+                    WalletData::GooglePay(google_pay_data) => {
+                        FiuuPaymentMethodData::try_from(google_pay_data)
+                    }
+                    WalletData::ApplePay(_apple_pay_data) => {
+                        let payment_method_token = item.router_data.get_payment_method_token()?;
+                        match payment_method_token {
+                            PaymentMethodToken::Token(_) => {
+                                Err(unimplemented_payment_method!("Apple Pay", "Manual", "Fiuu"))?
+                            }
+                            PaymentMethodToken::ApplePayDecrypt(decrypt_data) => {
+                                FiuuPaymentMethodData::try_from(decrypt_data)
+                            }
+                            PaymentMethodToken::PazeDecrypt(_) => {
+                                Err(unimplemented_payment_method!("Paze", "Fiuu"))?
+                            }
+                        }
+                    }
+                    WalletData::AliPayQr(_)
+                    | WalletData::AliPayRedirect(_)
+                    | WalletData::AliPayHkRedirect(_)
+                    | WalletData::MomoRedirect(_)
+                    | WalletData::KakaoPayRedirect(_)
+                    | WalletData::GoPayRedirect(_)
+                    | WalletData::GcashRedirect(_)
+                    | WalletData::ApplePayRedirect(_)
+                    | WalletData::ApplePayThirdPartySdk(_)
+                    | WalletData::DanaRedirect {}
+                    | WalletData::GooglePayRedirect(_)
+                    | WalletData::GooglePayThirdPartySdk(_)
+                    | WalletData::MbWayRedirect(_)
+                    | WalletData::MobilePayRedirect(_)
+                    | WalletData::PaypalRedirect(_)
+                    | WalletData::PaypalSdk(_)
+                    | WalletData::Paze(_)
+                    | WalletData::SamsungPay(_)
+                    | WalletData::TwintRedirect {}
+                    | WalletData::VippsRedirect {}
+                    | WalletData::TouchNGoRedirect(_)
+                    | WalletData::WeChatPayRedirect(_)
+                    | WalletData::WeChatPayQr(_)
+                    | WalletData::CashappQr(_)
+                    | WalletData::SwishQr(_)
+                    | WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented(
+                        utils::get_unimplemented_payment_method_error_message("fiuu"),
+                    )
+                    .into()),
+                },
+                PaymentMethodData::CardRedirect(_)
+                | PaymentMethodData::PayLater(_)
+                | PaymentMethodData::BankDebit(_)
+                | PaymentMethodData::BankTransfer(_)
+                | PaymentMethodData::Crypto(_)
+                | PaymentMethodData::MandatePayment
+                | PaymentMethodData::MobilePayment(_)
+                | PaymentMethodData::Reward
+                | PaymentMethodData::Upi(_)
+                | PaymentMethodData::Voucher(_)
+                | PaymentMethodData::GiftCard(_)
+                | PaymentMethodData::CardToken(_)
+                | PaymentMethodData::OpenBanking(_)
+                | PaymentMethodData::NetworkToken(_)
+                | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
                     Err(errors::ConnectorError::NotImplemented(
                         utils::get_unimplemented_payment_method_error_message("fiuu"),
                     )
                     .into())
                 }
             },
-            PaymentMethodData::Wallet(ref wallet_data) => match wallet_data {
-                WalletData::GooglePay(google_pay_data) => {
-                    FiuuPaymentMethodData::try_from(google_pay_data)
-                }
-                WalletData::ApplePay(_apple_pay_data) => {
-                    let payment_method_token = item.router_data.get_payment_method_token()?;
-                    match payment_method_token {
-                        PaymentMethodToken::Token(_) => {
-                            Err(unimplemented_payment_method!("Apple Pay", "Manual", "Fiuu"))?
-                        }
-                        PaymentMethodToken::ApplePayDecrypt(decrypt_data) => {
-                            FiuuPaymentMethodData::try_from(decrypt_data)
-                        }
-                        PaymentMethodToken::PazeDecrypt(_) => {
-                            Err(unimplemented_payment_method!("Paze", "Fiuu"))?
-                        }
+            // Card payments using network transaction ID
+            Some(payments::MandateReferenceId::NetworkMandateId(network_transaction_id)) => {
+                match item.router_data.request.payment_method_data {
+                    PaymentMethodData::CardDetailsForNetworkTransactionId(ref raw_card_details) => {
+                        FiuuPaymentMethodData::try_from((raw_card_details, network_transaction_id))
                     }
+                    _ => Err(errors::ConnectorError::NotImplemented(
+                        utils::get_unimplemented_payment_method_error_message("fiuu"),
+                    )
+                    .into()),
                 }
-                WalletData::AliPayQr(_)
-                | WalletData::AliPayRedirect(_)
-                | WalletData::AliPayHkRedirect(_)
-                | WalletData::MomoRedirect(_)
-                | WalletData::KakaoPayRedirect(_)
-                | WalletData::GoPayRedirect(_)
-                | WalletData::GcashRedirect(_)
-                | WalletData::ApplePayRedirect(_)
-                | WalletData::ApplePayThirdPartySdk(_)
-                | WalletData::DanaRedirect {}
-                | WalletData::GooglePayRedirect(_)
-                | WalletData::GooglePayThirdPartySdk(_)
-                | WalletData::MbWayRedirect(_)
-                | WalletData::MobilePayRedirect(_)
-                | WalletData::PaypalRedirect(_)
-                | WalletData::PaypalSdk(_)
-                | WalletData::Paze(_)
-                | WalletData::SamsungPay(_)
-                | WalletData::TwintRedirect {}
-                | WalletData::VippsRedirect {}
-                | WalletData::TouchNGoRedirect(_)
-                | WalletData::WeChatPayRedirect(_)
-                | WalletData::WeChatPayQr(_)
-                | WalletData::CashappQr(_)
-                | WalletData::SwishQr(_)
-                | WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented(
-                    utils::get_unimplemented_payment_method_error_message("fiuu"),
-                )
-                .into()),
-            },
-            PaymentMethodData::CardRedirect(_)
-            | PaymentMethodData::PayLater(_)
-            | PaymentMethodData::BankDebit(_)
-            | PaymentMethodData::BankTransfer(_)
-            | PaymentMethodData::Crypto(_)
-            | PaymentMethodData::MandatePayment
-            | PaymentMethodData::MobilePayment(_)
-            | PaymentMethodData::Reward
-            | PaymentMethodData::Upi(_)
-            | PaymentMethodData::Voucher(_)
-            | PaymentMethodData::GiftCard(_)
-            | PaymentMethodData::CardToken(_)
-            | PaymentMethodData::OpenBanking(_)
-            | PaymentMethodData::NetworkToken(_)
-            | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
-                Err(errors::ConnectorError::NotImplemented(
-                    utils::get_unimplemented_payment_method_error_message("fiuu"),
-                )
-                .into())
             }
+            _ => Err(errors::ConnectorError::NotImplemented(
+                utils::get_unimplemented_payment_method_error_message("fiuu"),
+            )
+            .into()),
         }?;
 
         Ok(Self {
@@ -556,7 +594,7 @@ impl TryFrom<(&Card, &PaymentsAuthorizeRouterData)> for FiuuPaymentMethodData {
             if item.request.is_customer_initiated_mandate_payment() {
                 (Some(1), Some(item.get_billing_email()?))
             } else {
-                (None, None)
+                (Some(3), None)
             };
         let non_3ds = match item.is_three_ds() {
             false => 1,
@@ -575,6 +613,21 @@ impl TryFrom<(&Card, &PaymentsAuthorizeRouterData)> for FiuuPaymentMethodData {
     }
 }
 
+impl TryFrom<(&CardDetailsForNetworkTransactionId, String)> for FiuuPaymentMethodData {
+    type Error = Report<errors::ConnectorError>;
+    fn try_from(
+        (raw_card_data, network_transaction_id): (&CardDetailsForNetworkTransactionId, String),
+    ) -> Result<Self, Self::Error> {
+        Ok(Self::FiuuCardWithNTI(Box::new(FiuuCardWithNTI {
+            txn_channel: TxnChannel::Creditan,
+            cc_pan: raw_card_data.card_number.clone(),
+            cc_month: raw_card_data.card_exp_month.clone(),
+            cc_year: raw_card_data.card_exp_year.clone(),
+            original_scheme_id: Secret::new(network_transaction_id),
+        })))
+    }
+}
+
 impl TryFrom<&GooglePayWalletData> for FiuuPaymentMethodData {
     type Error = Report<errors::ConnectorError>;
     fn try_from(data: &GooglePayWalletData) -> Result<Self, Self::Error> {
@@ -1092,6 +1145,8 @@ pub struct FiuuPaymentSyncResponse {
     error_desc: String,
     #[serde(rename = "miscellaneous")]
     miscellaneous: Option<HashMap<String, Secret<String>>>,
+    #[serde(rename = "SchemeTransactionID")]
+    scheme_transaction_id: Option<Secret<String>>,
 }
 
 #[derive(Debug, Serialize, Deserialize, Display, Clone, PartialEq)]
@@ -1183,7 +1238,10 @@ impl TryFrom<PaymentsSyncResponseRouterData<FiuuPaymentResponse>> for PaymentsSy
                     redirection_data: Box::new(None),
                     mandate_reference: Box::new(None),
                     connector_metadata: None,
-                    network_txn_id: None,
+                    network_txn_id: response
+                        .scheme_transaction_id
+                        .as_ref()
+                        .map(|id| id.clone().expose()),
                     connector_response_reference_id: None,
                     incremental_authorization_allowed: None,
                     charge_id: None,
diff --git a/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs b/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
index d62d3d2a755..6d3199ecf1a 100644
--- a/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
@@ -102,6 +102,13 @@ pub struct NovalnetCard {
     card_holder: Secret<String>,
 }
 
+#[derive(Default, Debug, Clone, Serialize, Deserialize)]
+pub struct NovalnetRawCardDetails {
+    card_number: CardNumber,
+    card_expiry_month: Secret<String>,
+    card_expiry_year: Secret<String>,
+}
+
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct NovalnetMandate {
     token: Secret<String>,
@@ -121,6 +128,7 @@ pub struct NovalnetApplePay {
 #[serde(untagged)]
 pub enum NovalNetPaymentData {
     Card(NovalnetCard),
+    RawCardForNTI(NovalnetRawCardDetails),
     GooglePay(NovalnetGooglePay),
     ApplePay(NovalnetApplePay),
     MandatePayment(NovalnetMandate),
@@ -151,6 +159,7 @@ pub struct NovalnetPaymentsRequestTransaction {
     error_return_url: Option<String>,
     enforce_3d: Option<i8>, //NOTE: Needed for CREDITCARD, GOOGLEPAY
     create_token: Option<i8>,
+    scheme_tid: Option<Secret<String>>, // Card network's transaction ID
 }
 
 #[derive(Debug, Serialize, Clone)]
@@ -261,6 +270,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
                         payment_data: Some(novalnet_card),
                         enforce_3d,
                         create_token,
+                        scheme_tid: None,
                     };
 
                     Ok(Self {
@@ -292,6 +302,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
                             payment_data: Some(novalnet_google_pay),
                             enforce_3d,
                             create_token,
+                            scheme_tid: None,
                         };
 
                         Ok(Self {
@@ -317,6 +328,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
                             })),
                             enforce_3d: None,
                             create_token,
+                            scheme_tid: None,
                         };
 
                         Ok(Self {
@@ -358,6 +370,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
                             payment_data: None,
                             enforce_3d: None,
                             create_token,
+                            scheme_tid: None,
                         };
                         Ok(Self {
                             merchant,
@@ -416,6 +429,7 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
                     payment_data: Some(novalnet_mandate_data),
                     enforce_3d,
                     create_token: None,
+                    scheme_tid: None,
                 };
 
                 Ok(Self {
@@ -425,6 +439,44 @@ impl TryFrom<&NovalnetRouterData<&PaymentsAuthorizeRouterData>> for NovalnetPaym
                     custom,
                 })
             }
+            Some(api_models::payments::MandateReferenceId::NetworkMandateId(
+                network_transaction_id,
+            )) => match item.router_data.request.payment_method_data {
+                PaymentMethodData::CardDetailsForNetworkTransactionId(ref raw_card_details) => {
+                    let novalnet_card =
+                        NovalNetPaymentData::RawCardForNTI(NovalnetRawCardDetails {
+                            card_number: raw_card_details.card_number.clone(),
+                            card_expiry_month: raw_card_details.card_exp_month.clone(),
+                            card_expiry_year: raw_card_details.card_exp_year.clone(),
+                        });
+
+                    let transaction = NovalnetPaymentsRequestTransaction {
+                        test_mode,
+                        payment_type: NovalNetPaymentTypes::CREDITCARD,
+                        amount: NovalNetAmount::StringMinor(item.amount.clone()),
+                        currency: item.router_data.request.currency,
+                        order_no: item.router_data.connector_request_reference_id.clone(),
+                        hook_url: Some(hook_url),
+                        return_url: Some(return_url.clone()),
+                        error_return_url: Some(return_url.clone()),
+                        payment_data: Some(novalnet_card),
+                        enforce_3d,
+                        create_token,
+                        scheme_tid: Some(network_transaction_id.into()),
+                    };
+
+                    Ok(Self {
+                        merchant,
+                        transaction,
+                        customer,
+                        custom,
+                    })
+                }
+                _ => Err(errors::ConnectorError::NotImplemented(
+                    utils::get_unimplemented_payment_method_error_message("novalnet"),
+                )
+                .into()),
+            },
             _ => Err(errors::ConnectorError::NotImplemented(
                 utils::get_unimplemented_payment_method_error_message("novalnet"),
             )
@@ -1466,6 +1518,7 @@ impl TryFrom<&SetupMandateRouterData> for NovalnetPaymentsRequest {
                     payment_data: Some(novalnet_card),
                     enforce_3d,
                     create_token,
+                    scheme_tid: None,
                 };
 
                 Ok(Self {
@@ -1495,6 +1548,7 @@ impl TryFrom<&SetupMandateRouterData> for NovalnetPaymentsRequest {
                         payment_data: Some(novalnet_google_pay),
                         enforce_3d,
                         create_token,
+                        scheme_tid: None,
                     };
 
                     Ok(Self {
@@ -1519,6 +1573,7 @@ impl TryFrom<&SetupMandateRouterData> for NovalnetPaymentsRequest {
                         })),
                         enforce_3d: None,
                         create_token,
+                        scheme_tid: None,
                     };
 
                     Ok(Self {
@@ -1559,7 +1614,9 @@ impl TryFrom<&SetupMandateRouterData> for NovalnetPaymentsRequest {
                         payment_data: None,
                         enforce_3d: None,
                         create_token,
+                        scheme_tid: None,
                     };
+
                     Ok(Self {
                         merchant,
                         transaction,
diff --git a/crates/hyperswitch_connectors/src/connectors/worldpay.rs b/crates/hyperswitch_connectors/src/connectors/worldpay.rs
index 07e4c178f9b..104e854e6fe 100644
--- a/crates/hyperswitch_connectors/src/connectors/worldpay.rs
+++ b/crates/hyperswitch_connectors/src/connectors/worldpay.rs
@@ -1199,6 +1199,42 @@ impl IncomingWebhook for Worldpay {
         let psync_body = WorldpayEventResponse::try_from(body)?;
         Ok(Box::new(psync_body))
     }
+
+    fn get_mandate_details(
+        &self,
+        request: &IncomingWebhookRequestDetails<'_>,
+    ) -> CustomResult<
+        Option<hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails>,
+        errors::ConnectorError,
+    > {
+        let body: WorldpayWebhookTransactionId = request
+            .body
+            .parse_struct("WorldpayWebhookTransactionId")
+            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
+        let mandate_reference = body.event_details.token.map(|mandate_token| {
+            hyperswitch_domain_models::router_flow_types::ConnectorMandateDetails {
+                connector_mandate_id: mandate_token.href,
+            }
+        });
+        Ok(mandate_reference)
+    }
+
+    fn get_network_txn_id(
+        &self,
+        request: &IncomingWebhookRequestDetails<'_>,
+    ) -> CustomResult<
+        Option<hyperswitch_domain_models::router_flow_types::ConnectorNetworkTxnId>,
+        errors::ConnectorError,
+    > {
+        let body: WorldpayWebhookTransactionId = request
+            .body
+            .parse_struct("WorldpayWebhookTransactionId")
+            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
+        let optional_network_txn_id = body.event_details.scheme_reference.map(|network_txn_id| {
+            hyperswitch_domain_models::router_flow_types::ConnectorNetworkTxnId::new(network_txn_id)
+        });
+        Ok(optional_network_txn_id)
+    }
 }
 
 impl ConnectorRedirectResponse for Worldpay {
diff --git a/crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs b/crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs
index 884caa9e840..52ae2c4f16f 100644
--- a/crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs
+++ b/crates/hyperswitch_connectors/src/connectors/worldpay/requests.rs
@@ -52,18 +52,22 @@ pub enum TokenCreationType {
     Worldpay,
 }
 
+#[serde_with::skip_serializing_none]
 #[derive(Clone, Debug, PartialEq, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct CustomerAgreement {
     #[serde(rename = "type")]
     pub agreement_type: CustomerAgreementType,
-    pub stored_card_usage: StoredCardUsageType,
+    pub stored_card_usage: Option<StoredCardUsageType>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub scheme_reference: Option<Secret<String>>,
 }
 
 #[derive(Clone, Debug, PartialEq, Serialize)]
 #[serde(rename_all = "lowercase")]
 pub enum CustomerAgreementType {
     Subscription,
+    Unscheduled,
 }
 
 #[derive(Clone, Debug, PartialEq, Serialize)]
@@ -78,6 +82,7 @@ pub enum StoredCardUsageType {
 pub enum PaymentInstrument {
     Card(CardPayment),
     CardToken(CardToken),
+    RawCardForNTI(RawCardDetails),
     Googlepay(WalletPayment),
     Applepay(WalletPayment),
 }
@@ -85,15 +90,22 @@ pub enum PaymentInstrument {
 #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 pub struct CardPayment {
-    #[serde(rename = "type")]
-    pub payment_type: PaymentType,
+    #[serde(flatten)]
+    pub raw_card_details: RawCardDetails,
+    pub cvc: Secret<String>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub card_holder_name: Option<Secret<String>>,
-    pub card_number: cards::CardNumber,
-    pub expiry_date: ExpiryDate,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub billing_address: Option<BillingAddress>,
-    pub cvc: Secret<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct RawCardDetails {
+    #[serde(rename = "type")]
+    pub payment_type: PaymentType,
+    pub card_number: cards::CardNumber,
+    pub expiry_date: ExpiryDate,
 }
 
 #[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
diff --git a/crates/hyperswitch_connectors/src/connectors/worldpay/response.rs b/crates/hyperswitch_connectors/src/connectors/worldpay/response.rs
index 5e9fb030424..b4d6a370401 100644
--- a/crates/hyperswitch_connectors/src/connectors/worldpay/response.rs
+++ b/crates/hyperswitch_connectors/src/connectors/worldpay/response.rs
@@ -43,6 +43,8 @@ pub struct AuthorizedResponse {
     pub fraud: Option<Fraud>,
     /// Mandate's token
     pub token: Option<MandateToken>,
+    /// Network transaction ID
+    pub scheme_reference: Option<Secret<String>>,
 }
 
 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@@ -429,9 +431,13 @@ pub struct WorldpayWebhookTransactionId {
 #[derive(Debug, Serialize, Deserialize)]
 #[serde(rename_all = "camelCase")]
 pub struct EventDetails {
-    pub transaction_reference: String,
     #[serde(rename = "type")]
     pub event_type: EventType,
+    pub transaction_reference: String,
+    /// Mandate's token
+    pub token: Option<MandateToken>,
+    /// Network transaction ID
+    pub scheme_reference: Option<Secret<String>>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
diff --git a/crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs
index ec23b520a20..cd028e81ef1 100644
--- a/crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs
@@ -76,12 +76,14 @@ fn fetch_payment_instrument(
 ) -> CustomResult<PaymentInstrument, errors::ConnectorError> {
     match payment_method {
         PaymentMethodData::Card(card) => Ok(PaymentInstrument::Card(CardPayment {
-            payment_type: PaymentType::Plain,
-            expiry_date: ExpiryDate {
-                month: card.get_expiry_month_as_i8()?,
-                year: card.get_expiry_year_as_4_digit_i32()?,
+            raw_card_details: RawCardDetails {
+                payment_type: PaymentType::Plain,
+                expiry_date: ExpiryDate {
+                    month: card.get_expiry_month_as_i8()?,
+                    year: card.get_expiry_year_as_4_digit_i32()?,
+                },
+                card_number: card.card_number,
             },
-            card_number: card.card_number,
             cvc: card.card_cvc,
             card_holder_name: billing_address.and_then(|address| address.get_optional_full_name()),
             billing_address: if let Some(address) =
@@ -107,6 +109,16 @@ fn fetch_payment_instrument(
                 None
             },
         })),
+        PaymentMethodData::CardDetailsForNetworkTransactionId(raw_card_details) => {
+            Ok(PaymentInstrument::RawCardForNTI(RawCardDetails {
+                payment_type: PaymentType::Plain,
+                expiry_date: ExpiryDate {
+                    month: raw_card_details.get_expiry_month_as_i8()?,
+                    year: raw_card_details.get_expiry_year_as_4_digit_i32()?,
+                },
+                card_number: raw_card_details.card_number,
+            }))
+        }
         PaymentMethodData::MandatePayment => mandate_ids
             .and_then(|mandate_ids| {
                 mandate_ids
@@ -185,13 +197,10 @@ fn fetch_payment_instrument(
         | PaymentMethodData::GiftCard(_)
         | PaymentMethodData::OpenBanking(_)
         | PaymentMethodData::CardToken(_)
-        | PaymentMethodData::NetworkToken(_)
-        | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => {
-            Err(errors::ConnectorError::NotImplemented(
-                utils::get_unimplemented_payment_method_error_message("worldpay"),
-            )
-            .into())
-        }
+        | PaymentMethodData::NetworkToken(_) => Err(errors::ConnectorError::NotImplemented(
+            utils::get_unimplemented_payment_method_error_message("worldpay"),
+        )
+        .into()),
     }
 }
 
@@ -439,6 +448,7 @@ fn get_token_and_agreement(
     payment_method_data: &PaymentMethodData,
     setup_future_usage: Option<enums::FutureUsage>,
     off_session: Option<bool>,
+    mandate_ids: Option<MandateIds>,
 ) -> (Option<TokenCreation>, Option<CustomerAgreement>) {
     match (payment_method_data, setup_future_usage, off_session) {
         // CIT
@@ -448,7 +458,8 @@ fn get_token_and_agreement(
             }),
             Some(CustomerAgreement {
                 agreement_type: CustomerAgreementType::Subscription,
-                stored_card_usage: StoredCardUsageType::First,
+                stored_card_usage: Some(StoredCardUsageType::First),
+                scheme_reference: None,
             }),
         ),
         // MIT
@@ -456,7 +467,26 @@ fn get_token_and_agreement(
             None,
             Some(CustomerAgreement {
                 agreement_type: CustomerAgreementType::Subscription,
-                stored_card_usage: StoredCardUsageType::Subsequent,
+                stored_card_usage: Some(StoredCardUsageType::Subsequent),
+                scheme_reference: None,
+            }),
+        ),
+        // NTI with raw card data
+        (PaymentMethodData::CardDetailsForNetworkTransactionId(_), _, _) => (
+            None,
+            mandate_ids.and_then(|mandate_ids| {
+                mandate_ids
+                    .mandate_reference_id
+                    .and_then(|mandate_id| match mandate_id {
+                        MandateReferenceId::NetworkMandateId(network_transaction_id) => {
+                            Some(CustomerAgreement {
+                                agreement_type: CustomerAgreementType::Unscheduled,
+                                scheme_reference: Some(network_transaction_id.into()),
+                                stored_card_usage: None,
+                            })
+                        }
+                        _ => None,
+                    })
             }),
         ),
         _ => (None, None),
@@ -487,6 +517,7 @@ impl<T: WorldpayPaymentsRequestData> TryFrom<(&WorldpayRouterData<&T>, &Secret<S
             item.router_data.get_payment_method_data(),
             item.router_data.get_setup_future_usage(),
             item.router_data.get_off_session(),
+            item.router_data.get_mandate_id(),
         );
 
         Ok(Self {
@@ -646,7 +677,7 @@ impl<F, T>
         ),
     ) -> Result<Self, Self::Error> {
         let (router_data, optional_correlation_id) = item;
-        let (description, redirection_data, mandate_reference, error) = router_data
+        let (description, redirection_data, mandate_reference, network_txn_id, error) = router_data
             .response
             .other_fields
             .as_ref()
@@ -660,6 +691,7 @@ impl<F, T>
                         mandate_metadata: None,
                         connector_mandate_request_reference_id: None,
                     }),
+                    res.scheme_reference.clone(),
                     None,
                 ),
                 WorldpayPaymentResponseFields::DDCResponse(res) => (
@@ -681,6 +713,7 @@ impl<F, T>
                     }),
                     None,
                     None,
+                    None,
                 ),
                 WorldpayPaymentResponseFields::ThreeDsChallenged(res) => (
                     None,
@@ -694,16 +727,18 @@ impl<F, T>
                     }),
                     None,
                     None,
+                    None,
                 ),
                 WorldpayPaymentResponseFields::RefusedResponse(res) => (
                     None,
                     None,
                     None,
+                    None,
                     Some((res.refusal_code.clone(), res.refusal_description.clone())),
                 ),
-                WorldpayPaymentResponseFields::FraudHighRisk(_) => (None, None, None, None),
+                WorldpayPaymentResponseFields::FraudHighRisk(_) => (None, None, None, None, None),
             })
-            .unwrap_or((None, None, None, None));
+            .unwrap_or((None, None, None, None, None));
         let worldpay_status = router_data.response.outcome.clone();
         let optional_error_message = match worldpay_status {
             PaymentOutcome::ThreeDsAuthenticationFailed => {
@@ -725,7 +760,7 @@ impl<F, T>
                 redirection_data: Box::new(redirection_data),
                 mandate_reference: Box::new(mandate_reference),
                 connector_metadata: None,
-                network_txn_id: None,
+                network_txn_id: network_txn_id.map(|id| id.expose()),
                 connector_response_reference_id: optional_correlation_id.clone(),
                 incremental_authorization_allowed: None,
                 charge_id: None,
diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs
index 190a4eb2566..671aed36378 100644
--- a/crates/hyperswitch_connectors/src/utils.rs
+++ b/crates/hyperswitch_connectors/src/utils.rs
@@ -17,7 +17,7 @@ use common_utils::{
 use error_stack::{report, ResultExt};
 use hyperswitch_domain_models::{
     address::{Address, AddressDetails, PhoneDetails},
-    payment_method_data::{self, Card, PaymentMethodData},
+    payment_method_data::{self, Card, CardDetailsForNetworkTransactionId, PaymentMethodData},
     router_data::{
         ApplePayPredecryptData, ErrorResponse, PaymentMethodToken, RecurringMandatePaymentData,
     },
@@ -1040,6 +1040,97 @@ impl CardData for Card {
     }
 }
 
+impl CardData for CardDetailsForNetworkTransactionId {
+    fn get_card_expiry_year_2_digit(&self) -> Result<Secret<String>, errors::ConnectorError> {
+        let binding = self.card_exp_year.clone();
+        let year = binding.peek();
+        Ok(Secret::new(
+            year.get(year.len() - 2..)
+                .ok_or(errors::ConnectorError::RequestEncodingFailed)?
+                .to_string(),
+        ))
+    }
+    fn get_card_issuer(&self) -> Result<CardIssuer, Error> {
+        get_card_issuer(self.card_number.peek())
+    }
+    fn get_card_expiry_month_year_2_digit_with_delimiter(
+        &self,
+        delimiter: String,
+    ) -> Result<Secret<String>, errors::ConnectorError> {
+        let year = self.get_card_expiry_year_2_digit()?;
+        Ok(Secret::new(format!(
+            "{}{}{}",
+            self.card_exp_month.peek(),
+            delimiter,
+            year.peek()
+        )))
+    }
+    fn get_expiry_date_as_yyyymm(&self, delimiter: &str) -> Secret<String> {
+        let year = self.get_expiry_year_4_digit();
+        Secret::new(format!(
+            "{}{}{}",
+            year.peek(),
+            delimiter,
+            self.card_exp_month.peek()
+        ))
+    }
+    fn get_expiry_date_as_mmyyyy(&self, delimiter: &str) -> Secret<String> {
+        let year = self.get_expiry_year_4_digit();
+        Secret::new(format!(
+            "{}{}{}",
+            self.card_exp_month.peek(),
+            delimiter,
+            year.peek()
+        ))
+    }
+    fn get_expiry_year_4_digit(&self) -> Secret<String> {
+        let mut year = self.card_exp_year.peek().clone();
+        if year.len() == 2 {
+            year = format!("20{}", year);
+        }
+        Secret::new(year)
+    }
+    fn get_expiry_date_as_yymm(&self) -> Result<Secret<String>, errors::ConnectorError> {
+        let year = self.get_card_expiry_year_2_digit()?.expose();
+        let month = self.card_exp_month.clone().expose();
+        Ok(Secret::new(format!("{year}{month}")))
+    }
+    fn get_expiry_date_as_mmyy(&self) -> Result<Secret<String>, errors::ConnectorError> {
+        let year = self.get_card_expiry_year_2_digit()?.expose();
+        let month = self.card_exp_month.clone().expose();
+        Ok(Secret::new(format!("{month}{year}")))
+    }
+    fn get_expiry_month_as_i8(&self) -> Result<Secret<i8>, Error> {
+        self.card_exp_month
+            .peek()
+            .clone()
+            .parse::<i8>()
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)
+            .map(Secret::new)
+    }
+    fn get_expiry_year_as_i32(&self) -> Result<Secret<i32>, Error> {
+        self.card_exp_year
+            .peek()
+            .clone()
+            .parse::<i32>()
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)
+            .map(Secret::new)
+    }
+    fn get_expiry_year_as_4_digit_i32(&self) -> Result<Secret<i32>, Error> {
+        self.get_expiry_year_4_digit()
+            .peek()
+            .clone()
+            .parse::<i32>()
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)
+            .map(Secret::new)
+    }
+    fn get_cardholder_name(&self) -> Result<Secret<String>, Error> {
+        self.card_holder_name
+            .clone()
+            .ok_or_else(missing_field_err("card.card_holder_name"))
+    }
+}
+
 #[track_caller]
 fn get_card_issuer(card_number: &str) -> Result<CardIssuer, Error> {
     for (k, v) in CARD_REGEX.iter() {
diff --git a/crates/router/locales/en.yml b/crates/router/locales/en.yml
index c85be7ccf46..67eec844fb1 100644
--- a/crates/router/locales/en.yml
+++ b/crates/router/locales/en.yml
@@ -7,7 +7,7 @@ payout_link:
   status:
     title: "Payout Status"
     info:
-      ref_id: "Ref Id"
+      ref_id: "Reference Id"
       error_code: "Error Code"
       error_message: "Error Message"
     message:
diff --git a/crates/router/src/configs/defaults/payment_connector_required_fields.rs b/crates/router/src/configs/defaults/payment_connector_required_fields.rs
index 1d2be85ba17..d957109bcef 100644
--- a/crates/router/src/configs/defaults/payment_connector_required_fields.rs
+++ b/crates/router/src/configs/defaults/payment_connector_required_fields.rs
@@ -67,6 +67,7 @@ impl Default for Mandates {
                                     enums::Connector::Authorizedotnet,
                                     enums::Connector::Globalpay,
                                     enums::Connector::Worldpay,
+                                    enums::Connector::Fiuu,
                                     enums::Connector::Multisafepay,
                                     enums::Connector::Nexinets,
                                     enums::Connector::Noon,
@@ -88,6 +89,7 @@ impl Default for Mandates {
                                     enums::Connector::Authorizedotnet,
                                     enums::Connector::Globalpay,
                                     enums::Connector::Worldpay,
+                                    enums::Connector::Fiuu,
                                     enums::Connector::Multisafepay,
                                     enums::Connector::Nexinets,
                                     enums::Connector::Noon,
diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml
index b26b5b2e438..e90eb16ab61 100644
--- a/loadtest/config/development.toml
+++ b/loadtest/config/development.toml
@@ -370,7 +370,7 @@ card.credit ={connector_list ="cybersource"}
 card.debit = {connector_list ="cybersource"}
 
 [network_transaction_id_supported_connectors]
-connector_list = "stripe,adyen,cybersource"
+connector_list = "adyen,cybersource,novalnet,stripe,worldpay"
 
 [analytics]
 source = "sqlx"

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

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

## Description
Described in #6941 

This PR adds NTI flow integrations for below connectors

- Fiuu - store NTI ID in `payment_methods` from connector's PSync response
- Novalnet - use NTI ID for card payments
- Worldpay - store and use NTI ID for card payments

### Additional Changes

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

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

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


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

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


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->

<details>
    <summary>1. CIT for cards through Adyen</summary>

cURL

    curl --location --request POST 'http://localhost:8080/payments' \
        --header 'Content-Type: application/json' \
        --header 'Accept: application/json' \
        --header 'api-key: dev_rh7Gdbe4bpB4Vxz9A7SQge8NwmI48LHgckedcW181ltQ5xJte0ADtOBsW7tmQaI0' \
        --data-raw '{"amount":100,"currency":"USD","confirm":true,"capture_method":"automatic","capture_on":"2022-09-10T10:11:12Z","customer_id":"cus_VzApV1FxWKoB90X5uEcm","email":"guest@example.com","name":"John Doe","phone":"999999999","profile_id":"pro_lNLLS8WnmDP5uYTJQpIE","phone_country_code":"+65","description":"Its my first payment request","authentication_type":"no_three_ds","return_url":"https://hyperswitch.io","setup_future_usage":"off_session","customer_acceptance":{"acceptance_type":"online","accepted_at":"1963-05-03T04:07:52.723Z","online":{"ip_address":"127.0.0.1","user_agent":"amet irure esse"}},"connector":["adyen"],"payment_method":"card","payment_method_data":{"card":{"card_number":"5454545454545454","card_exp_month":"03","card_exp_year":"2030","card_cvc":"737","nick_name":"JD"},"billing":{"email":"guest@example.com","address":{"first_name":"John","last_name":"US"}}},"billing":{"address":{"line1":"1467","line2":"Harrison Street","line3":"Harrison Street","city":"San Fransico","state":"California","zip":"94122","country":"US","first_name":"John","last_name":"US"}},"statement_descriptor_name":"joseph","statement_descriptor_suffix":"JS","metadata":{"udf1":"value1","new_customer":"true","login_date":"2019-09-10T10:11:12Z"},"browser_info":{"ip_address":"129.0.0.1","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","language":"en-US","color_depth":32,"screen_height":1117,"screen_width":1728,"time_zone":-330,"java_enabled":true,"java_script_enabled":true}}'

Response

    {"payment_id":"pay_lVqK4xVFlhPsDKVArnIo","merchant_id":"merchant_1735800357","status":"requires_customer_action","amount":100,"net_amount":100,"shipping_cost":null,"amount_capturable":100,"amount_received":null,"connector":"adyen","client_secret":"pay_lVqK4xVFlhPsDKVArnIo_secret_jge63cwkJDCY1FZMzOeR","created":"2025-01-02T08:27:51.185Z","currency":"USD","customer_id":"cus_VzApV1FxWKoB90X5uEcm","customer":{"id":"cus_VzApV1FxWKoB90X5uEcm","name":"John Doe","email":"guest@example.com","phone":"999999999","phone_country_code":"+65"},"description":"Its my first payment request","refunds":null,"disputes":null,"mandate_id":null,"mandate_data":null,"setup_future_usage":"off_session","off_session":null,"capture_on":null,"capture_method":"automatic","payment_method":"card","payment_method_data":{"card":{"last4":"5454","card_type":"CREDIT","card_network":"Mastercard","card_issuer":"BANKHANDLOWYWWARSZAWIE.S.A.","card_issuing_country":"POLAND","card_isin":"545454","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"2030","card_holder_name":"John US","payment_checks":null,"authentication_data":null},"billing":{"address":{"city":null,"country":null,"line1":null,"line2":null,"line3":null,"zip":null,"state":null,"first_name":"John","last_name":"US"},"phone":null,"email":"guest@example.com"}},"payment_token":null,"shipping":null,"billing":{"address":{"city":"San Fransico","country":"US","line1":"1467","line2":"Harrison Street","line3":"Harrison Street","zip":"94122","state":"California","first_name":"John","last_name":"US"},"phone":null,"email":null},"order_details":null,"email":"guest@example.com","name":"John Doe","phone":"999999999","return_url":"https://hyperswitch.io/","authentication_type":"no_three_ds","statement_descriptor_name":"joseph","statement_descriptor_suffix":"JS","next_action":{"type":"redirect_to_url","redirect_to_url":"http://localhost:8080/payments/redirect/pay_lVqK4xVFlhPsDKVArnIo/merchant_1735800357/pay_lVqK4xVFlhPsDKVArnIo_1"},"cancellation_reason":null,"error_code":null,"error_message":null,"unified_code":null,"unified_message":null,"payment_experience":null,"payment_method_type":"credit","connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"cus_VzApV1FxWKoB90X5uEcm","created_at":1735806471,"expires":1735810071,"secret":"epk_d3cf3844e1144988bb2bf79bb9f0d8bf"},"manual_retry_allowed":null,"connector_transaction_id":"Z3S5HHVH5S5H3275","frm_message":null,"metadata":{"udf1":"value1","login_date":"2019-09-10T10:11:12Z","new_customer":"true"},"connector_metadata":null,"feature_metadata":null,"reference_id":"Z3S5HHVH5S5H3275","payment_link":null,"profile_id":"pro_lNLLS8WnmDP5uYTJQpIE","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_Vcy2aZeTpgwfuzHd79R3","incremental_authorization_allowed":null,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-01-02T08:42:51.185Z","fingerprint":null,"browser_info":{"language":"en-US","time_zone":-330,"ip_address":"129.0.0.1","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","color_depth":32,"java_enabled":true,"screen_width":1728,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":1117,"java_script_enabled":true},"payment_method_id":"pm_MO7c0p19Rgc2p6nDSWCd","payment_method_status":"inactive","updated":"2025-01-02T08:27:52.557Z","split_payments":null,"frm_metadata":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null}

- Complete the transaction
- Retrieve payment to get the `payment_method_id`

cURL

    curl --location --request GET 'http://localhost:8080/payments/pay_lVqK4xVFlhPsDKVArnIo?force_sync=true' \
        --header 'Accept: application/json' \
        --header 'api-key: dev_rh7Gdbe4bpB4Vxz9A7SQge8NwmI48LHgckedcW181ltQ5xJte0ADtOBsW7tmQaI0'

Response

    {"payment_id":"pay_lVqK4xVFlhPsDKVArnIo","merchant_id":"merchant_1735800357","status":"succeeded","amount":100,"net_amount":100,"shipping_cost":null,"amount_capturable":0,"amount_received":100,"connector":"adyen","client_secret":"pay_lVqK4xVFlhPsDKVArnIo_secret_jge63cwkJDCY1FZMzOeR","created":"2025-01-02T08:27:51.185Z","currency":"USD","customer_id":"cus_VzApV1FxWKoB90X5uEcm","customer":{"id":"cus_VzApV1FxWKoB90X5uEcm","name":"John Doe","email":"guest@example.com","phone":"999999999","phone_country_code":"+65"},"description":"Its my first payment request","refunds":null,"disputes":null,"mandate_id":null,"mandate_data":null,"setup_future_usage":"off_session","off_session":null,"capture_on":null,"capture_method":"automatic","payment_method":"card","payment_method_data":{"card":{"last4":"5454","card_type":"CREDIT","card_network":"Mastercard","card_issuer":"BANKHANDLOWYWWARSZAWIE.S.A.","card_issuing_country":"POLAND","card_isin":"545454","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"2030","card_holder_name":"John US","payment_checks":null,"authentication_data":null},"billing":{"address":{"city":null,"country":null,"line1":null,"line2":null,"line3":null,"zip":null,"state":null,"first_name":"John","last_name":"US"},"phone":null,"email":"guest@example.com"}},"payment_token":null,"shipping":null,"billing":{"address":{"city":"San Fransico","country":"US","line1":"1467","line2":"Harrison Street","line3":"Harrison Street","zip":"94122","state":"California","first_name":"John","last_name":"US"},"phone":null,"email":null},"order_details":null,"email":"guest@example.com","name":"John Doe","phone":"999999999","return_url":"https://hyperswitch.io/","authentication_type":"no_three_ds","statement_descriptor_name":"joseph","statement_descriptor_suffix":"JS","next_action":null,"cancellation_reason":null,"error_code":null,"error_message":null,"unified_code":null,"unified_message":null,"payment_experience":null,"payment_method_type":"credit","connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":null,"manual_retry_allowed":false,"connector_transaction_id":"Z3S5HHVH5S5H3275","frm_message":null,"metadata":{"udf1":"value1","login_date":"2019-09-10T10:11:12Z","new_customer":"true"},"connector_metadata":null,"feature_metadata":null,"reference_id":"pay_lVqK4xVFlhPsDKVArnIo_1","payment_link":null,"profile_id":"pro_lNLLS8WnmDP5uYTJQpIE","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_Vcy2aZeTpgwfuzHd79R3","incremental_authorization_allowed":null,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-01-02T08:42:51.185Z","fingerprint":null,"browser_info":{"language":"en-US","time_zone":-330,"ip_address":"129.0.0.1","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","color_depth":32,"java_enabled":true,"screen_width":1728,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":1117,"java_script_enabled":true},"payment_method_id":"pm_MO7c0p19Rgc2p6nDSWCd","payment_method_status":"active","updated":"2025-01-02T08:29:21.898Z","split_payments":null,"frm_metadata":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null}

</details>

<details>
    <summary>2. [Novalnet] MIT for cards using NTI</summary>

cURL

    curl --location --request POST 'http://localhost:8080/payments' \
        --header 'Content-Type: application/json' \
        --header 'Accept: application/json' \
        --header 'api-key: dev_rh7Gdbe4bpB4Vxz9A7SQge8NwmI48LHgckedcW181ltQ5xJte0ADtOBsW7tmQaI0' \
        --data-raw '{"amount":6500,"currency":"USD","confirm":true,"capture_method":"automatic","capture_on":"2022-09-10T10:11:12Z","customer_id":"cus_VzApV1FxWKoB90X5uEcm","email":"guest@example.com","name":"John Doe","phone":"999999999","profile_id":"pro_lNLLS8WnmDP5uYTJQpIE","phone_country_code":"+65","description":"Its my first payment request","authentication_type":"no_three_ds","return_url":"https://hyperswitch.io","off_session":true,"recurring_details":{"type":"payment_method_id","data":"pm_dKKRxNRCIsi84dCE3DCc"},"connector":["novalnet"],"statement_descriptor_name":"joseph","statement_descriptor_suffix":"JS","metadata":{"udf1":"value1","new_customer":"true","login_date":"2019-09-10T10:11:12Z"},"browser_info":{"ip_address":"129.0.0.1","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","language":"en-US","color_depth":32,"screen_height":1117,"screen_width":1728,"time_zone":-330,"java_enabled":true,"java_script_enabled":true}}'

Response

    {"payment_id":"pay_3W4Chua2lDw4bYxDaRqt","merchant_id":"merchant_1735800357","status":"succeeded","amount":6500,"net_amount":6500,"shipping_cost":null,"amount_capturable":0,"amount_received":6500,"connector":"novalnet","client_secret":"pay_3W4Chua2lDw4bYxDaRqt_secret_nA6hiXdx8QLwjt71ffOd","created":"2025-01-02T08:32:03.307Z","currency":"USD","customer_id":"cus_VzApV1FxWKoB90X5uEcm","customer":{"id":"cus_VzApV1FxWKoB90X5uEcm","name":"John Doe","email":"guest@example.com","phone":"999999999","phone_country_code":"+65"},"description":"Its my first payment request","refunds":null,"disputes":null,"mandate_id":null,"mandate_data":null,"setup_future_usage":null,"off_session":true,"capture_on":null,"capture_method":"automatic","payment_method":"card","payment_method_data":{"card":{"last4":"5454","card_type":"CREDIT","card_network":"Mastercard","card_issuer":"BANKHANDLOWYWWARSZAWIE.S.A.","card_issuing_country":"POLAND","card_isin":"545454","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"2030","card_holder_name":"John US","payment_checks":null,"authentication_data":null},"billing":null},"payment_token":null,"shipping":null,"billing":null,"order_details":null,"email":"guest@example.com","name":"John Doe","phone":"999999999","return_url":"https://hyperswitch.io/","authentication_type":"no_three_ds","statement_descriptor_name":"joseph","statement_descriptor_suffix":"JS","next_action":null,"cancellation_reason":null,"error_code":null,"error_message":null,"unified_code":null,"unified_message":null,"payment_experience":null,"payment_method_type":"credit","connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"cus_VzApV1FxWKoB90X5uEcm","created_at":1735806723,"expires":1735810323,"secret":"epk_4479174c59444f52816900c1d0a0a602"},"manual_retry_allowed":false,"connector_transaction_id":"15133000040614710","frm_message":null,"metadata":{"udf1":"value1","login_date":"2019-09-10T10:11:12Z","new_customer":"true"},"connector_metadata":null,"feature_metadata":null,"reference_id":"15133000040614710","payment_link":null,"profile_id":"pro_lNLLS8WnmDP5uYTJQpIE","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_q8uMuxuvlutjsnNPaqEs","incremental_authorization_allowed":null,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-01-02T08:47:03.307Z","fingerprint":null,"browser_info":{"language":"en-US","time_zone":-330,"ip_address":"129.0.0.1","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","color_depth":32,"java_enabled":true,"screen_width":1728,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":1117,"java_script_enabled":true},"payment_method_id":"pm_dKKRxNRCIsi84dCE3DCc","payment_method_status":"active","updated":"2025-01-02T08:32:07.974Z","split_payments":null,"frm_metadata":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null}

</details>

<details>
    <summary>3. [Worldpay] MIT for cards using NTI</summary>

cURL

    curl --location --request POST 'http://localhost:8080/payments' \
        --header 'Content-Type: application/json' \
        --header 'Accept: application/json' \
        --header 'api-key: dev_rh7Gdbe4bpB4Vxz9A7SQge8NwmI48LHgckedcW181ltQ5xJte0ADtOBsW7tmQaI0' \
        --data-raw '{"amount":6500,"currency":"USD","confirm":true,"capture_method":"automatic","capture_on":"2022-09-10T10:11:12Z","customer_id":"cus_VzApV1FxWKoB90X5uEcm","email":"guest@example.com","name":"John Doe","phone":"999999999","profile_id":"pro_lNLLS8WnmDP5uYTJQpIE","phone_country_code":"+65","description":"Its my first payment request","authentication_type":"no_three_ds","return_url":"https://hyperswitch.io","off_session":true,"recurring_details":{"type":"payment_method_id","data":"pm_dKKRxNRCIsi84dCE3DCc"},"connector":["worldpay"],"statement_descriptor_name":"joseph","statement_descriptor_suffix":"JS","metadata":{"udf1":"value1","new_customer":"true","login_date":"2019-09-10T10:11:12Z"},"browser_info":{"ip_address":"129.0.0.1","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","language":"en-US","color_depth":32,"screen_height":1117,"screen_width":1728,"time_zone":-330,"java_enabled":true,"java_script_enabled":true}}'

Response

    {"payment_id":"pay_rzcivnTTSrT8D2doTu8S","merchant_id":"merchant_1735800357","status":"succeeded","amount":6500,"net_amount":6500,"shipping_cost":null,"amount_capturable":0,"amount_received":6500,"connector":"worldpay","client_secret":"pay_rzcivnTTSrT8D2doTu8S_secret_nFPSG4JuDSZRr6iYV7sk","created":"2025-01-02T08:30:36.855Z","currency":"USD","customer_id":"cus_VzApV1FxWKoB90X5uEcm","customer":{"id":"cus_VzApV1FxWKoB90X5uEcm","name":"John Doe","email":"guest@example.com","phone":"999999999","phone_country_code":"+65"},"description":"Its my first payment request","refunds":null,"disputes":null,"mandate_id":null,"mandate_data":null,"setup_future_usage":null,"off_session":true,"capture_on":null,"capture_method":"automatic","payment_method":"card","payment_method_data":{"card":{"last4":"5454","card_type":"CREDIT","card_network":"Mastercard","card_issuer":"BANKHANDLOWYWWARSZAWIE.S.A.","card_issuing_country":"POLAND","card_isin":"545454","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"2030","card_holder_name":"John US","payment_checks":null,"authentication_data":null},"billing":null},"payment_token":null,"shipping":null,"billing":null,"order_details":null,"email":"guest@example.com","name":"John Doe","phone":"999999999","return_url":"https://hyperswitch.io/","authentication_type":"no_three_ds","statement_descriptor_name":"joseph","statement_descriptor_suffix":"JS","next_action":null,"cancellation_reason":null,"error_code":null,"error_message":null,"unified_code":null,"unified_message":null,"payment_experience":null,"payment_method_type":"credit","connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"cus_VzApV1FxWKoB90X5uEcm","created_at":1735806636,"expires":1735810236,"secret":"epk_f8f4d087bc4148f98b3b0ba8e81e22b3"},"manual_retry_allowed":false,"connector_transaction_id":"eyJrIjoiazNhYjYzMiIsImxpbmtWZXJzaW9uIjoiNS4wLjAifQ==.sN:g8wd64bwkbrp0md+bPxcanBnk2zLdsIqSa1pR99GGg8fCNQpPLoWNslSzWNPFBM5Tpa8tW7EFI5onKINsgChMHeJVoeH2lrBWCRyjZYT6h+lbqfJa+1BSoKFSY8HLiz6vUTzxKAX24Ht8ZQ4HMhu9ADJnDtIHgxF9tK1ofAqmfgF9Uk2Www3mSVoKRxeIXIe9pic4l22Rveu3MW0qp:7+4GYJYOg3e9WdLnxDKf8zDOVuNV9Smp3TrKAPuNF+l9HY8h4r+1y1WBHupQz59qPpv59wMMnZCI15w9voaKGUgn8jvCNhmdUlN6uDEfAu3+Gpx8cadeYO0VLI6Wl9IpfjEUa63t7mpDaTErQBefTyL+3aw0lAN5HuRY6n0Lw81eWY3h7IW9jcvHhnfJ6QTQ==","frm_message":null,"metadata":{"udf1":"value1","login_date":"2019-09-10T10:11:12Z","new_customer":"true"},"connector_metadata":null,"feature_metadata":null,"reference_id":"4af31547-85c9-4413-93e6-67917d09db32","payment_link":null,"profile_id":"pro_lNLLS8WnmDP5uYTJQpIE","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_9i9j8AIAxASZwPltj1ED","incremental_authorization_allowed":null,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-01-02T08:45:36.855Z","fingerprint":null,"browser_info":{"language":"en-US","time_zone":-330,"ip_address":"129.0.0.1","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","color_depth":32,"java_enabled":true,"screen_width":1728,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":1117,"java_script_enabled":true},"payment_method_id":"pm_dKKRxNRCIsi84dCE3DCc","payment_method_status":"active","updated":"2025-01-02T08:30:38.635Z","split_payments":null,"frm_metadata":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null}

</details>

<details>
    <summary>4. Ran cypress test cases for Worldpay</summary>

<img width="524" alt="Screenshot 2025-01-16 at 12 09 21 AM" src="https://github.com/user-attachments/assets/37ec3e5a-c839-4895-9320-ae023699cda0" />


</details>

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
