Bug: [FEATURE] : [Loonio] Implement interac Bank Redirect Payment Method



Implement interac Bank Redirect Payment Method

- Payments
- Psync

diff --git a/config/config.example.toml b/config/config.example.toml
index f584755d516..829a9bcec48 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -253,7 +253,7 @@ juspaythreedsserver.base_url = "http://localhost:8000"
 katapult.base_url = "https://sandbox.katapult.com/api/v3"
 jpmorgan.secondary_base_url= "https://id.payments.jpmorgan.com"
 klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/"
-loonio.base_url = "https://loonio.ca/"
+loonio.base_url = "https://integration.loonio.ca/"
 mifinity.base_url = "https://demo.mifinity.com/"
 mollie.base_url = "https://api.mollie.com/v2/"
 moneris.base_url = "https://api.sb.moneris.io"
diff --git a/config/deployments/integration_test.toml b/config/deployments/integration_test.toml
index ea34d70769a..b67a323c05c 100644
--- a/config/deployments/integration_test.toml
+++ b/config/deployments/integration_test.toml
@@ -91,7 +91,7 @@ juspaythreedsserver.base_url = "http://localhost:8000"
 katapult.base_url = "https://sandbox.katapult.com/api/v3"
 jpmorgan.secondary_base_url="https://id.payments.jpmorgan.com"
 klarna.base_url =  "https://api{{klarna_region}}.playground.klarna.com/"
-loonio.base_url = "https://loonio.ca/"
+loonio.base_url = "https://integration.loonio.ca/"
 mifinity.base_url = "https://demo.mifinity.com/"
 mollie.base_url = "https://api.mollie.com/v2/"
 mollie.secondary_base_url = "https://api.cc.mollie.com/v1/"
@@ -766,6 +766,9 @@ klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,C
 [pm_filters.gigadat]
 interac = { currency = "CAD"}
 
+[pm_filters.loonio]
+interac = { currency = "CAD"}
+
 [payout_method_filters.adyenplatform]
 sepa = { country = "AT,BE,CH,CZ,DE,EE,ES,FI,FR,GB,HU,IE,IT,LT,LV,NL,NO,PL,PT,SE,SK", currency = "EUR,CZK,DKK,HUF,NOK,PLN,SEK,GBP,CHF" }
 credit = { country = "AT,BE,BG,CY,CZ,DE,DK,EE,ES,FI,FR,GB,GR,HR,HU,IE,IS,IT,LI,LT,LU,LV,MT,NL,NO,PL,PT,RO,SE,SI,SK,US", currency = "EUR,USD,GBP" }
diff --git a/config/deployments/production.toml b/config/deployments/production.toml
index 84adba409b3..f3c97876836 100644
--- a/config/deployments/production.toml
+++ b/config/deployments/production.toml
@@ -791,6 +791,9 @@ klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,C
 [pm_filters.gigadat]
 interac = { currency = "CAD"}
 
+[pm_filters.loonio]
+interac = { currency = "CAD"}
+
 [pm_filters.coingate]
 crypto_currency = { country = "AL, AD, AT, BE, BA, BG, HR, CZ, DK, EE, FI, FR, DE, GR, HU, IS, IE, IT, LV, LT, LU, MT, MD, NL, NO, PL, PT, RO, RS, SK, SI, ES, SE, CH, UA, GB, AR, BR, CL, CO, CR, DO, SV, GD, MX, PE, LC, AU, NZ, CY, HK, IN, IL, JP, KR, QA, SA, SG, EG", currency = "EUR, USD, GBP" }
 
diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml
index e5f9c327245..db907d94e3e 100644
--- a/config/deployments/sandbox.toml
+++ b/config/deployments/sandbox.toml
@@ -94,7 +94,7 @@ juspaythreedsserver.base_url = "http://localhost:8000"
 katapult.base_url = "https://sandbox.katapult.com/api/v3"
 jpmorgan.secondary_base_url="https://id.payments.jpmorgan.com"
 klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/"
-loonio.base_url = "https://loonio.ca/"
+loonio.base_url = "https://integration.loonio.ca/"
 mifinity.base_url = "https://demo.mifinity.com/"
 mollie.base_url = "https://api.mollie.com/v2/"
 mollie.secondary_base_url = "https://api.cc.mollie.com/v1/"
@@ -801,6 +801,9 @@ klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,C
 [pm_filters.gigadat]
 interac = { currency = "CAD"}
 
+[pm_filters.loonio]
+interac = { currency = "CAD"}
+
 [pm_filters.coingate]
 crypto_currency = { country = "AL, AD, AT, BE, BA, BG, HR, CZ, DK, EE, FI, FR, DE, GR, HU, IS, IE, IT, LV, LT, LU, MT, MD, NL, NO, PL, PT, RO, RS, SK, SI, ES, SE, CH, UA, GB, AR, BR, CL, CO, CR, DO, SV, GD, MX, PE, LC, AU, NZ, CY, HK, IN, IL, JP, KR, QA, SA, SG, EG", currency = "EUR, USD, GBP" }
 
diff --git a/config/development.toml b/config/development.toml
index 1a16b15c42b..e36688974d3 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -291,7 +291,7 @@ juspaythreedsserver.base_url = "http://localhost:8000"
 katapult.base_url = "https://sandbox.katapult.com/api/v3"
 jpmorgan.secondary_base_url = "https://id.payments.jpmorgan.com"
 klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/"
-loonio.base_url = "https://loonio.ca/"
+loonio.base_url = "https://integration.loonio.ca/"
 mifinity.base_url = "https://demo.mifinity.com/"
 mollie.base_url = "https://api.mollie.com/v2/"
 moneris.base_url = "https://api.sb.moneris.io"
@@ -784,6 +784,9 @@ klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,C
 [pm_filters.gigadat]
 interac = { currency = "CAD"}
 
+[pm_filters.loonio]
+interac = { currency = "CAD"}
+
 [pm_filters.mollie]
 credit = { not_available_flows = { capture_method = "manual" } }
 debit = { not_available_flows = { capture_method = "manual" } }
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index 9d5991a3125..30c9b64bd64 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -179,7 +179,7 @@ juspaythreedsserver.base_url = "http://localhost:8000"
 katapult.base_url = "https://sandbox.katapult.com/api/v3"
 jpmorgan.secondary_base_url="https://id.payments.jpmorgan.com"
 klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/"
-loonio.base_url = "https://loonio.ca/"
+loonio.base_url = "https://integration.loonio.ca/"
 mifinity.base_url = "https://demo.mifinity.com/"
 mollie.base_url = "https://api.mollie.com/v2/"
 moneris.base_url = "https://api.sb.moneris.io"
@@ -934,6 +934,9 @@ klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,C
 [pm_filters.gigadat]
 interac = { currency = "CAD"}
 
+[pm_filters.loonio]
+interac = { currency = "CAD"}
+
 [pm_filters.coingate]
 crypto_currency = { country = "AL, AD, AT, BE, BA, BG, HR, CZ, DK, EE, FI, FR, DE, GR, HU, IS, IE, IT, LV, LT, LU, MT, MD, NL, NO, PL, PT, RO, RS, SK, SI, ES, SE, CH, UA, GB, AR, BR, CL, CO, CR, DO, SV, GD, MX, PE, LC, AU, NZ, CY, HK, IN, IL, JP, KR, QA, SA, SG, EG", currency = "EUR, USD, GBP" }
 
diff --git a/crates/common_enums/src/connector_enums.rs b/crates/common_enums/src/connector_enums.rs
index a4369cd7862..2db7e7613d8 100644
--- a/crates/common_enums/src/connector_enums.rs
+++ b/crates/common_enums/src/connector_enums.rs
@@ -113,6 +113,7 @@ pub enum RoutableConnectors {
     Itaubank,
     Jpmorgan,
     Klarna,
+    Loonio,
     Mifinity,
     Mollie,
     Moneris,
@@ -293,6 +294,7 @@ pub enum Connector {
     Jpmorgan,
     Juspaythreedsserver,
     Klarna,
+    Loonio,
     Mifinity,
     Mollie,
     Moneris,
@@ -491,6 +493,7 @@ impl Connector {
             | Self::Jpmorgan
             | Self::Juspaythreedsserver
             | Self::Klarna
+            | Self::Loonio
             | Self::Mifinity
             | Self::Mollie
             | Self::Moneris
@@ -672,6 +675,7 @@ impl From<RoutableConnectors> for Connector {
             RoutableConnectors::Itaubank => Self::Itaubank,
             RoutableConnectors::Jpmorgan => Self::Jpmorgan,
             RoutableConnectors::Klarna => Self::Klarna,
+            RoutableConnectors::Loonio => Self::Loonio,
             RoutableConnectors::Mifinity => Self::Mifinity,
             RoutableConnectors::Mollie => Self::Mollie,
             RoutableConnectors::Moneris => Self::Moneris,
@@ -808,6 +812,7 @@ impl TryFrom<Connector> for RoutableConnectors {
             Connector::Itaubank => Ok(Self::Itaubank),
             Connector::Jpmorgan => Ok(Self::Jpmorgan),
             Connector::Klarna => Ok(Self::Klarna),
+            Connector::Loonio => Ok(Self::Loonio),
             Connector::Mifinity => Ok(Self::Mifinity),
             Connector::Mollie => Ok(Self::Mollie),
             Connector::Moneris => Ok(Self::Moneris),
diff --git a/crates/connector_configs/src/connector.rs b/crates/connector_configs/src/connector.rs
index c01ac16c0e1..41d3cb1b5d1 100644
--- a/crates/connector_configs/src/connector.rs
+++ b/crates/connector_configs/src/connector.rs
@@ -511,6 +511,7 @@ impl ConnectorConfig {
             Connector::Jpmorgan => Ok(connector_data.jpmorgan),
             Connector::Juspaythreedsserver => Ok(connector_data.juspaythreedsserver),
             Connector::Klarna => Ok(connector_data.klarna),
+            Connector::Loonio => Ok(connector_data.loonio),
             Connector::Mifinity => Ok(connector_data.mifinity),
             Connector::Mollie => Ok(connector_data.mollie),
             Connector::Moneris => Ok(connector_data.moneris),
diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml
index 0f98861cc04..84dfabd1c50 100644
--- a/crates/connector_configs/toml/development.toml
+++ b/crates/connector_configs/toml/development.toml
@@ -7187,6 +7187,10 @@ api_key = "API Key"
 [tesouro.connector_auth.BodyKey]
 api_key="Client ID"
 key1="Client Secret"
+
 [loonio]
-[loonio.connector_auth.HeaderKey]
-api_key = "API Key"
+[loonio.connector_auth.BodyKey]
+api_key = "Merchant ID"
+api_secret = "Merchant Token"
+[[loonio.bank_redirect]]
+payment_method_type = "interac"
diff --git a/crates/connector_configs/toml/production.toml b/crates/connector_configs/toml/production.toml
index aea8277906e..b4fcbe8e18c 100644
--- a/crates/connector_configs/toml/production.toml
+++ b/crates/connector_configs/toml/production.toml
@@ -5924,6 +5924,10 @@ api_key = "API Key"
 [tesouro.connector_auth.BodyKey]
 api_key="Client ID"
 key1="Client Secret"
+
 [loonio]
-[loonio.connector_auth.HeaderKey]
-api_key = "API Key"
+[loonio.connector_auth.BodyKey]
+api_key = "Merchant ID"
+api_secret = "Merchant Token"
+[[loonio.bank_redirect]]
+payment_method_type = "interac"
diff --git a/crates/connector_configs/toml/sandbox.toml b/crates/connector_configs/toml/sandbox.toml
index f7c7ed3e997..02abf6c2a0f 100644
--- a/crates/connector_configs/toml/sandbox.toml
+++ b/crates/connector_configs/toml/sandbox.toml
@@ -7166,6 +7166,10 @@ api_key = "API Key"
 [tesouro.connector_auth.BodyKey]
 api_key="Client ID"
 key1="Client Secret"
+
 [loonio]
-[loonio.connector_auth.HeaderKey]
-api_key = "API Key"
+[loonio.connector_auth.BodyKey]
+api_key = "Merchant ID"
+api_secret = "Merchant Token"
+[[loonio.bank_redirect]]
+payment_method_type = "interac"
diff --git a/crates/hyperswitch_connectors/src/connectors/loonio.rs b/crates/hyperswitch_connectors/src/connectors/loonio.rs
index ad57fad435e..96ee717b862 100644
--- a/crates/hyperswitch_connectors/src/connectors/loonio.rs
+++ b/crates/hyperswitch_connectors/src/connectors/loonio.rs
@@ -1,13 +1,11 @@
 pub mod transformers;
 
-use std::sync::LazyLock;
-
 use common_enums::enums;
 use common_utils::{
     errors::CustomResult,
     ext_traits::BytesExt,
     request::{Method, Request, RequestBuilder, RequestContent},
-    types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector},
+    types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector},
 };
 use error_stack::{report, ResultExt};
 use hyperswitch_domain_models::{
@@ -24,7 +22,8 @@ use hyperswitch_domain_models::{
         RefundsData, SetupMandateRequestData,
     },
     router_response_types::{
-        ConnectorInfo, PaymentsResponseData, RefundsResponseData, SupportedPaymentMethods,
+        ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
+        SupportedPaymentMethods, SupportedPaymentMethodsExt,
     },
     types::{
         PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
@@ -37,11 +36,12 @@ use hyperswitch_interfaces::{
         ConnectorValidation,
     },
     configs::Connectors,
-    errors,
+    consts as api_consts, errors,
     events::connector_api_logs::ConnectorEvent,
     types::{self, Response},
     webhooks,
 };
+use lazy_static::lazy_static;
 use masking::{ExposeInterface, Mask};
 use transformers as loonio;
 
@@ -49,13 +49,13 @@ use crate::{constants::headers, types::ResponseRouterData, utils};
 
 #[derive(Clone)]
 pub struct Loonio {
-    amount_converter: &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
+    amount_converter: &'static (dyn AmountConvertor<Output = FloatMajorUnit> + Sync),
 }
 
 impl Loonio {
     pub fn new() -> &'static Self {
         &Self {
-            amount_converter: &StringMinorUnitForConnector,
+            amount_converter: &FloatMajorUnitForConnector,
         }
     }
 }
@@ -121,10 +121,16 @@ impl ConnectorCommon for Loonio {
     ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
         let auth = loonio::LoonioAuthType::try_from(auth_type)
             .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
-        Ok(vec![(
-            headers::AUTHORIZATION.to_string(),
-            auth.api_key.expose().into_masked(),
-        )])
+        Ok(vec![
+            (
+                headers::MERCHANTID.to_string(),
+                auth.merchant_id.expose().into_masked(),
+            ),
+            (
+                headers::MERCHANT_TOKEN.to_string(),
+                auth.merchant_token.expose().into_masked(),
+            ),
+        ])
     }
 
     fn build_error_response(
@@ -142,9 +148,12 @@ impl ConnectorCommon for Loonio {
 
         Ok(ErrorResponse {
             status_code: res.status_code,
-            code: response.code,
-            message: response.message,
-            reason: response.reason,
+            code: response
+                .error_code
+                .clone()
+                .unwrap_or(api_consts::NO_ERROR_CODE.to_string()),
+            message: response.message.clone(),
+            reason: Some(response.message.clone()),
             attempt_status: None,
             connector_transaction_id: None,
             network_advice_code: None,
@@ -205,9 +214,12 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
     fn get_url(
         &self,
         _req: &PaymentsAuthorizeRouterData,
-        _connectors: &Connectors,
+        connectors: &Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
+        Ok(format!(
+            "{}api/v1/transactions/incoming/payment_form",
+            self.base_url(connectors),
+        ))
     }
 
     fn get_request_body(
@@ -222,7 +234,7 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
         )?;
 
         let connector_router_data = loonio::LoonioRouterData::from((amount, req));
-        let connector_req = loonio::LoonioPaymentsRequest::try_from(&connector_router_data)?;
+        let connector_req = loonio::LoonioPaymentRequest::try_from(&connector_router_data)?;
         Ok(RequestContent::Json(Box::new(connector_req)))
     }
 
@@ -291,10 +303,14 @@ impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Loo
 
     fn get_url(
         &self,
-        _req: &PaymentsSyncRouterData,
-        _connectors: &Connectors,
+        req: &PaymentsSyncRouterData,
+        connectors: &Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
+        let base_url = self.base_url(connectors);
+        let connector_payment_id = req.connector_request_reference_id.clone();
+        Ok(format!(
+            "{base_url}api/v1/transactions/{connector_payment_id}/details"
+        ))
     }
 
     fn build_request(
@@ -318,9 +334,9 @@ impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Loo
         event_builder: Option<&mut ConnectorEvent>,
         res: Response,
     ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
-        let response: loonio::LoonioPaymentsResponse = res
+        let response: loonio::LoonioTransactionSyncResponse = res
             .response
-            .parse_struct("loonio PaymentsSyncResponse")
+            .parse_struct("loonio LoonioTransactionSyncResponse")
             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
@@ -594,21 +610,36 @@ impl webhooks::IncomingWebhook for Loonio {
     }
 }
 
-static LOONIO_SUPPORTED_PAYMENT_METHODS: LazyLock<SupportedPaymentMethods> =
-    LazyLock::new(SupportedPaymentMethods::new);
-
-static LOONIO_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
-    display_name: "Loonio",
-    description: "Loonio connector",
-    connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
-    integration_status: enums::ConnectorIntegrationStatus::Sandbox,
-};
-
-static LOONIO_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 0] = [];
+lazy_static! {
+    static ref LOONIO_SUPPORTED_PAYMENT_METHODS: SupportedPaymentMethods = {
+        let supported_capture_methods = vec![enums::CaptureMethod::Automatic];
+
+        let mut gigadat_supported_payment_methods = SupportedPaymentMethods::new();
+        gigadat_supported_payment_methods.add(
+            enums::PaymentMethod::BankRedirect,
+            enums::PaymentMethodType::Interac,
+            PaymentMethodDetails {
+                mandates: common_enums::FeatureStatus::NotSupported,
+                refunds: common_enums::FeatureStatus::Supported,
+                supported_capture_methods,
+                specific_features: None,
+            },
+        );
+
+        gigadat_supported_payment_methods
+    };
+    static ref LOONIO_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
+        display_name: "Loonio",
+        description: "Loonio is a payment processing platform that provides APIs for deposits and payouts via methods like Interac, PIX, EFT, and credit cards, with webhook support and transaction sync for real-time and manual status tracking.",
+        connector_type: enums::HyperswitchConnectorCategory::PaymentGateway,
+        integration_status: enums::ConnectorIntegrationStatus::Sandbox,
+    };
+    static ref LOONIO_SUPPORTED_WEBHOOK_FLOWS: Vec<enums::EventClass> = Vec::new();
+}
 
 impl ConnectorSpecifications for Loonio {
     fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
-        Some(&LOONIO_CONNECTOR_INFO)
+        Some(&*LOONIO_CONNECTOR_INFO)
     }
 
     fn get_supported_payment_methods(&self) -> Option<&'static SupportedPaymentMethods> {
@@ -616,6 +647,6 @@ impl ConnectorSpecifications for Loonio {
     }
 
     fn get_supported_webhook_flows(&self) -> Option<&'static [enums::EventClass]> {
-        Some(&LOONIO_SUPPORTED_WEBHOOK_FLOWS)
+        Some(&*LOONIO_SUPPORTED_WEBHOOK_FLOWS)
     }
 }
diff --git a/crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs b/crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs
index 0bdaf494cea..7efc1a895dc 100644
--- a/crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/loonio/transformers.rs
@@ -1,28 +1,31 @@
-use common_enums::enums;
-use common_utils::types::StringMinorUnit;
+use std::collections::HashMap;
+
+use common_enums::{enums, Currency};
+use common_utils::{id_type, pii::Email, request::Method, types::FloatMajorUnit};
 use hyperswitch_domain_models::{
-    payment_method_data::PaymentMethodData,
+    payment_method_data::{BankRedirectData, PaymentMethodData},
     router_data::{ConnectorAuthType, RouterData},
     router_flow_types::refunds::{Execute, RSync},
     router_request_types::ResponseId,
-    router_response_types::{PaymentsResponseData, RefundsResponseData},
+    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
     types::{PaymentsAuthorizeRouterData, RefundsRouterData},
 };
 use hyperswitch_interfaces::errors;
 use masking::Secret;
 use serde::{Deserialize, Serialize};
 
-use crate::types::{RefundsResponseRouterData, ResponseRouterData};
+use crate::{
+    types::{RefundsResponseRouterData, ResponseRouterData},
+    utils::{self, PaymentsAuthorizeRequestData, RouterData as _},
+};
 
-//TODO: Fill the struct with respective fields
 pub struct LoonioRouterData<T> {
-    pub amount: StringMinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
+    pub amount: FloatMajorUnit,
     pub router_data: T,
 }
 
-impl<T> From<(StringMinorUnit, T)> for LoonioRouterData<T> {
-    fn from((amount, item): (StringMinorUnit, T)) -> Self {
-        //Todo :  use utils to convert the amount to the type of amount that a connector accepts
+impl<T> From<(FloatMajorUnit, T)> for LoonioRouterData<T> {
+    fn from((amount, item): (FloatMajorUnit, T)) -> Self {
         Self {
             amount,
             router_data: item,
@@ -30,80 +33,101 @@ impl<T> From<(StringMinorUnit, T)> for LoonioRouterData<T> {
     }
 }
 
-//TODO: Fill the struct with respective fields
-#[derive(Default, Debug, Serialize, PartialEq)]
-pub struct LoonioPaymentsRequest {
-    amount: StringMinorUnit,
-    card: LoonioCard,
-}
-
-#[derive(Default, Debug, Serialize, Eq, PartialEq)]
-pub struct LoonioCard {
-    number: cards::CardNumber,
-    expiry_month: Secret<String>,
-    expiry_year: Secret<String>,
-    cvc: Secret<String>,
-    complete: bool,
-}
-
-impl TryFrom<&LoonioRouterData<&PaymentsAuthorizeRouterData>> for LoonioPaymentsRequest {
-    type Error = error_stack::Report<errors::ConnectorError>;
-    fn try_from(
-        item: &LoonioRouterData<&PaymentsAuthorizeRouterData>,
-    ) -> Result<Self, Self::Error> {
-        match item.router_data.request.payment_method_data.clone() {
-            PaymentMethodData::Card(_) => Err(errors::ConnectorError::NotImplemented(
-                "Card payment method not implemented".to_string(),
-            )
-            .into()),
-            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
-        }
-    }
-}
-
-//TODO: Fill the struct with respective fields
 // Auth Struct
 pub struct LoonioAuthType {
-    pub(super) api_key: Secret<String>,
+    pub(super) merchant_id: Secret<String>,
+    pub(super) merchant_token: Secret<String>,
 }
 
 impl TryFrom<&ConnectorAuthType> for LoonioAuthType {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
         match auth_type {
-            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
-                api_key: api_key.to_owned(),
+            ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
+                merchant_id: api_key.to_owned(),
+                merchant_token: key1.to_owned(),
             }),
             _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
         }
     }
 }
-// PaymentsResponse
-//TODO: Append the remaining status flags
-#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "lowercase")]
-pub enum LoonioPaymentStatus {
-    Succeeded,
-    Failed,
-    #[default]
-    Processing,
+
+#[derive(Debug, Serialize)]
+pub struct LoonioPaymentRequest {
+    pub currency_code: Currency,
+    pub customer_profile: LoonioCustomerProfile,
+    pub amount: FloatMajorUnit,
+    pub customer_id: id_type::CustomerId,
+    pub transaction_id: String,
+    pub payment_method_type: InteracPaymentMethodType,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub redirect_url: Option<LoonioRedirectUrl>,
 }
 
-impl From<LoonioPaymentStatus> for common_enums::AttemptStatus {
-    fn from(item: LoonioPaymentStatus) -> Self {
-        match item {
-            LoonioPaymentStatus::Succeeded => Self::Charged,
-            LoonioPaymentStatus::Failed => Self::Failure,
-            LoonioPaymentStatus::Processing => Self::Authorizing,
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum InteracPaymentMethodType {
+    InteracEtransfer,
+}
+
+#[derive(Debug, Serialize)]
+pub struct LoonioCustomerProfile {
+    pub first_name: Secret<String>,
+    pub last_name: Secret<String>,
+    pub email: Email,
+}
+
+#[derive(Debug, Serialize)]
+pub struct LoonioRedirectUrl {
+    pub success_url: String,
+    pub failed_url: String,
+}
+
+impl TryFrom<&LoonioRouterData<&PaymentsAuthorizeRouterData>> for LoonioPaymentRequest {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: &LoonioRouterData<&PaymentsAuthorizeRouterData>,
+    ) -> Result<Self, Self::Error> {
+        match item.router_data.request.payment_method_data.clone() {
+            PaymentMethodData::BankRedirect(BankRedirectData::Interac { .. }) => {
+                let transaction_id = item.router_data.connector_request_reference_id.clone();
+
+                let customer_profile = LoonioCustomerProfile {
+                    first_name: item.router_data.get_billing_first_name()?,
+                    last_name: item.router_data.get_billing_last_name()?,
+                    email: item.router_data.get_billing_email()?,
+                };
+
+                let redirect_url = LoonioRedirectUrl {
+                    success_url: item.router_data.request.get_router_return_url()?,
+                    failed_url: item.router_data.request.get_router_return_url()?,
+                };
+
+                Ok(Self {
+                    currency_code: item.router_data.request.currency,
+                    customer_profile,
+                    amount: item.amount,
+                    customer_id: item.router_data.get_customer_id()?,
+                    transaction_id,
+                    payment_method_type: InteracPaymentMethodType::InteracEtransfer,
+                    redirect_url: Some(redirect_url),
+                })
+            }
+            PaymentMethodData::BankRedirect(_) => Err(errors::ConnectorError::NotImplemented(
+                utils::get_unimplemented_payment_method_error_message("Loonio"),
+            ))?,
+
+            _ => Err(errors::ConnectorError::NotImplemented(
+                utils::get_unimplemented_payment_method_error_message("Loonio"),
+            )
+            .into()),
         }
     }
 }
 
-//TODO: Fill the struct with respective fields
-#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct LoonioPaymentsResponse {
-    status: LoonioPaymentStatus,
-    id: String,
+    pub payment_form: String,
 }
 
 impl<F, T> TryFrom<ResponseRouterData<F, LoonioPaymentsResponse, T, PaymentsResponseData>>
@@ -114,10 +138,14 @@ impl<F, T> TryFrom<ResponseRouterData<F, LoonioPaymentsResponse, T, PaymentsResp
         item: ResponseRouterData<F, LoonioPaymentsResponse, T, PaymentsResponseData>,
     ) -> Result<Self, Self::Error> {
         Ok(Self {
-            status: common_enums::AttemptStatus::from(item.response.status),
+            status: enums::AttemptStatus::AuthenticationPending,
             response: Ok(PaymentsResponseData::TransactionResponse {
-                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
-                redirection_data: Box::new(None),
+                resource_id: ResponseId::ConnectorTransactionId(item.response.payment_form.clone()),
+                redirection_data: Box::new(Some(RedirectForm::Form {
+                    endpoint: item.response.payment_form,
+                    method: Method::Get,
+                    form_fields: HashMap::new(),
+                })),
                 mandate_reference: Box::new(None),
                 connector_metadata: None,
                 network_txn_id: None,
@@ -130,12 +158,48 @@ impl<F, T> TryFrom<ResponseRouterData<F, LoonioPaymentsResponse, T, PaymentsResp
     }
 }
 
-//TODO: Fill the struct with respective fields
-// REFUND :
-// Type definition for RefundRequest
+#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum LoonioTransactionStatus {
+    Created,
+    Prepared,
+    Pending,
+    Settled,
+    Available,
+    Abandoned,
+    Rejected,
+    Failed,
+    Rollback,
+    Returned,
+    Nsf,
+}
+
+impl From<LoonioTransactionStatus> for enums::AttemptStatus {
+    fn from(item: LoonioTransactionStatus) -> Self {
+        match item {
+            LoonioTransactionStatus::Created => Self::AuthenticationPending,
+            LoonioTransactionStatus::Prepared | LoonioTransactionStatus::Pending => Self::Pending,
+            LoonioTransactionStatus::Settled | LoonioTransactionStatus::Available => Self::Charged,
+            LoonioTransactionStatus::Abandoned
+            | LoonioTransactionStatus::Rejected
+            | LoonioTransactionStatus::Failed
+            | LoonioTransactionStatus::Returned
+            | LoonioTransactionStatus::Nsf => Self::Failure,
+            LoonioTransactionStatus::Rollback => Self::Voided,
+        }
+    }
+}
+
+// Sync Response Structures
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LoonioTransactionSyncResponse {
+    pub transaction_id: String,
+    pub state: LoonioTransactionStatus,
+}
+
 #[derive(Default, Debug, Serialize)]
 pub struct LoonioRefundRequest {
-    pub amount: StringMinorUnit,
+    pub amount: FloatMajorUnit,
 }
 
 impl<F> TryFrom<&LoonioRouterData<&RefundsRouterData<F>>> for LoonioRefundRequest {
@@ -147,6 +211,32 @@ impl<F> TryFrom<&LoonioRouterData<&RefundsRouterData<F>>> for LoonioRefundReques
     }
 }
 
+impl<F, T> TryFrom<ResponseRouterData<F, LoonioTransactionSyncResponse, T, PaymentsResponseData>>
+    for RouterData<F, T, PaymentsResponseData>
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: ResponseRouterData<F, LoonioTransactionSyncResponse, T, PaymentsResponseData>,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            status: enums::AttemptStatus::from(item.response.state),
+            response: Ok(PaymentsResponseData::TransactionResponse {
+                resource_id: ResponseId::ConnectorTransactionId(
+                    item.response.transaction_id.clone(),
+                ),
+                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
+        })
+    }
+}
+
 // Type definition for Refund Response
 
 #[allow(dead_code)]
@@ -207,13 +297,9 @@ impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouter
 }
 
 //TODO: Fill the struct with respective fields
-#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Default, Debug, Serialize, Deserialize)]
 pub struct LoonioErrorResponse {
-    pub status_code: u16,
-    pub code: String,
+    pub status: u16,
+    pub error_code: Option<String>,
     pub message: String,
-    pub reason: Option<String>,
-    pub network_advice_code: Option<String>,
-    pub network_decline_code: Option<String>,
-    pub network_error_message: Option<String>,
 }
diff --git a/crates/hyperswitch_connectors/src/constants.rs b/crates/hyperswitch_connectors/src/constants.rs
index 4bfd7c90558..6cc3757a6a0 100644
--- a/crates/hyperswitch_connectors/src/constants.rs
+++ b/crates/hyperswitch_connectors/src/constants.rs
@@ -10,6 +10,8 @@ pub(crate) mod headers {
     pub(crate) const IDEMPOTENCY_KEY: &str = "Idempotency-Key";
     pub(crate) const MESSAGE_SIGNATURE: &str = "Message-Signature";
     pub(crate) const MERCHANT_ID: &str = "Merchant-ID";
+    pub(crate) const MERCHANTID: &str = "MerchantID";
+    pub(crate) const MERCHANT_TOKEN: &str = "MerchantToken";
     pub(crate) const REQUEST_ID: &str = "request-id";
     pub(crate) const NONCE: &str = "nonce";
     pub(crate) const TIMESTAMP: &str = "Timestamp";
diff --git a/crates/payment_methods/src/configs/payment_connector_required_fields.rs b/crates/payment_methods/src/configs/payment_connector_required_fields.rs
index ea0abe93f84..0981d332d9c 100644
--- a/crates/payment_methods/src/configs/payment_connector_required_fields.rs
+++ b/crates/payment_methods/src/configs/payment_connector_required_fields.rs
@@ -2328,6 +2328,18 @@ fn get_bank_redirect_required_fields(
                         vec![],
                     ),
                 ),
+                (
+                    Connector::Loonio,
+                    fields(
+                        vec![],
+                        vec![
+                            RequiredField::BillingEmail,
+                            RequiredField::BillingUserFirstName,
+                            RequiredField::BillingUserLastName,
+                        ],
+                        vec![],
+                    ),
+                ),
             ]),
         ),
     ])
diff --git a/crates/router/src/core/connector_validation.rs b/crates/router/src/core/connector_validation.rs
index 8c9ef01017c..009c3612d8d 100644
--- a/crates/router/src/core/connector_validation.rs
+++ b/crates/router/src/core/connector_validation.rs
@@ -326,6 +326,10 @@ impl ConnectorAuthTypeAndMetadataValidation<'_> {
                 )?;
                 Ok(())
             }
+            api_enums::Connector::Loonio => {
+                loonio::transformers::LoonioAuthType::try_from(self.auth_type)?;
+                Ok(())
+            }
             api_enums::Connector::Mifinity => {
                 mifinity::transformers::MifinityAuthType::try_from(self.auth_type)?;
                 mifinity::transformers::MifinityConnectorMetadataObject::try_from(
diff --git a/crates/router/src/types/api/connector_mapping.rs b/crates/router/src/types/api/connector_mapping.rs
index 61dcf050479..3cf6ac51a72 100644
--- a/crates/router/src/types/api/connector_mapping.rs
+++ b/crates/router/src/types/api/connector_mapping.rs
@@ -309,6 +309,9 @@ impl ConnectorData {
                 enums::Connector::Klarna => {
                     Ok(ConnectorEnum::Old(Box::new(connector::Klarna::new())))
                 }
+                enums::Connector::Loonio => {
+                    Ok(ConnectorEnum::Old(Box::new(connector::Loonio::new())))
+                }
                 enums::Connector::Mollie => {
                     // enums::Connector::Moneris => Ok(ConnectorEnum::Old(Box::new(connector::Moneris))),
                     Ok(ConnectorEnum::Old(Box::new(connector::Mollie::new())))
diff --git a/crates/router/src/types/api/feature_matrix.rs b/crates/router/src/types/api/feature_matrix.rs
index 4537b42452f..5063abab7ab 100644
--- a/crates/router/src/types/api/feature_matrix.rs
+++ b/crates/router/src/types/api/feature_matrix.rs
@@ -227,6 +227,9 @@ impl FeatureMatrixConnectorData {
                 enums::Connector::Klarna => {
                     Ok(ConnectorEnum::Old(Box::new(connector::Klarna::new())))
                 }
+                enums::Connector::Loonio => {
+                    Ok(ConnectorEnum::Old(Box::new(connector::Loonio::new())))
+                }
                 enums::Connector::Mollie => {
                     // enums::Connector::Moneris => Ok(ConnectorEnum::Old(Box::new(connector::Moneris))),
                     Ok(ConnectorEnum::Old(Box::new(connector::Mollie::new())))
diff --git a/crates/router/src/types/connector_transformers.rs b/crates/router/src/types/connector_transformers.rs
index 7cc41f7bc79..ef7fa0e33df 100644
--- a/crates/router/src/types/connector_transformers.rs
+++ b/crates/router/src/types/connector_transformers.rs
@@ -93,6 +93,7 @@ impl ForeignTryFrom<api_enums::Connector> for common_enums::RoutableConnectors {
                 })?
             }
             api_enums::Connector::Klarna => Self::Klarna,
+            api_enums::Connector::Loonio => Self::Loonio,
             api_enums::Connector::Mifinity => Self::Mifinity,
             api_enums::Connector::Mollie => Self::Mollie,
             api_enums::Connector::Moneris => Self::Moneris,
diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml
index d01fe5e956e..536d23b8578 100644
--- a/loadtest/config/development.toml
+++ b/loadtest/config/development.toml
@@ -146,7 +146,7 @@ juspaythreedsserver.base_url = "http://localhost:8000"
 katapult.base_url = "https://sandbox.katapult.com/api/v3"
 jpmorgan.secondary_base_url = "https://id.payments.jpmorgan.com"
 klarna.base_url = "https://api{{klarna_region}}.playground.klarna.com/"
-loonio.base_url = "https://loonio.ca/"
+loonio.base_url = "https://integration.loonio.ca/"
 mifinity.base_url = "https://demo.mifinity.com/"
 mollie.base_url = "https://api.mollie.com/v2/"
 moneris.base_url = "https://api.sb.moneris.io"
@@ -598,6 +598,9 @@ klarna = { country = "AU,AT,BE,CA,CZ,DK,FI,FR,DE,GR,IE,IT,NL,NZ,NO,PL,PT,ES,SE,C
 [pm_filters.gigadat]
 interac = { currency = "CAD"}
 
+[pm_filters.loonio]
+interac = { currency = "CAD"}
+
 [pm_filters.authorizedotnet]
 credit = { currency = "CAD,USD" }
 debit = { currency = "CAD,USD" }

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

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

## Description
Implement interac Bank Redirect Payment Method
- Payments
- Psync


### 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?
1. Create MCA for Loonio
```
curl --location 'http://localhost:8080/account/merchant_1759170450/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: _' \
--data '{
    "connector_type": "payment_processor",
    "business_country": "US",
    "business_label": "food",
    "connector_name": "loonio",
    "connector_account_details": {
        "auth_type": "BodyKey",
        "api_key": "",
        "key1": "_"
    },
    "test_mode": false,
    "disabled": false,
    "payment_methods_enabled": [
        {
            "payment_method": "bank_redirect",
            "payment_method_types": [
                {
                    "payment_method_type": "interac",
                    "payment_experience": "invoke_sdk_client",
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        }
    ]
}'
```

2. Create a Interac Payment
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: _' \
--data-raw '{
    "amount": 1500,
    "currency": "CAD",
    "confirm": true,
    "capture_method": "automatic",
    "customer_id": "aaaa",
    "profile_id": "pro_C15ZRcjRQncWBGB2yuqm",
    "authentication_type": "three_ds",
    "payment_method": "bank_redirect",
    "payment_method_type": "interac",
    "payment_method_data": {
        "bank_redirect": {
            "interac": {}
        }
    },
    "billing": {
        "address": {
            "line1": "Singapore Changi Airport. 2nd flr",
            "line2": "",
            "line3": "",
            "city": "Downtown Core",
            "state": "Central Indiana America",
            "zip": "039393",
            "country": "SG",
            "first_name": "Swangi",
            "last_name": "Kumari"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": "swangi.kumari@juspay.in"
    },
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "127.0.0.1"
    }
}'
```
Response
```
{
    "payment_id": "pay_pDnVks1Ok2xqEiTKSc3L",
    "merchant_id": "merchant_1759170450",
    "status": "failed",
    "amount": 1500,
    "net_amount": 1500,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": "loonio",
    "client_secret": "pay_pDnVks1Ok2xqEiTKSc3L_secret_BOt98GDVh1YUREeBj49y",
    "created": "2025-09-30T09:06:47.208Z",
    "currency": "CAD",
    "customer_id": "aaaa",
    "customer": {
        "id": "aaaa",
        "name": null,
        "email": null,
        "phone": null,
        "phone_country_code": null
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "bank_redirect",
    "payment_method_data": {
        "bank_redirect": {
            "type": "BankRedirectResponse",
            "bank_name": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "Downtown Core",
            "country": "SG",
            "line1": "Singapore Changi Airport. 2nd flr",
            "line2": "",
            "line3": "",
            "zip": "039393",
            "state": "Central Indiana America",
            "first_name": "Swangi",
            "last_name": "Kumari",
            "origin_zip": null
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": "swangi.kumari@juspay.in"
    },
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "return_url": null,
    "authentication_type": "three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": "BSC02005",
    "error_message": "Input field validation error: 'Missed required field 'transaction_id'.'.",
    "unified_code": "UE_9000",
    "unified_message": "Something went wrong",
    "payment_experience": null,
    "payment_method_type": "interac",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "aaaa",
        "created_at": 1759223207,
        "expires": 1759226807,
        "secret": "epk_e7a1dc4e967a490781a35fe9d93dcf9a"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": null,
        "gateway_system": "direct"
    },
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_C15ZRcjRQncWBGB2yuqm",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_1D5PxJd9ci3fD8Nj9hKL",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-09-30T09:21:47.208Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "127.0.0.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1536,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 723,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": null,
    "network_transaction_id": null,
    "payment_method_status": null,
    "updated": "2025-09-30T09:06:48.505Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "request_extended_authorization": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": null,
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null,
    "enable_partial_authorization": null,
    "enable_overcapture": null,
    "is_overcapture_enabled": null,
    "network_details": {
        "network_advice_code": null
    }
}
```
Complete payment using redirect_url


It takes about 1 minute after the redirection for the status to change to succeeded.
3. Do force sync for status get 
```
curl --location 'http://localhost:8080/payments/pay_pDnVks1Ok2xqEiTKSc3L?force_sync=true' \
--header 'Accept: application/json' \
--header 'api-key: _'
```

Response
```
{
    "payment_id": "pay_hJ7WTdtJEsXcY53E7n0W",
    "merchant_id": "merchant_1759170450",
    "status": "succeeded",
    "amount": 1500,
    "net_amount": 1500,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 1500,
    "connector": "loonio",
    "client_secret": "pay_hJ7WTdtJEsXcY53E7n0W_secret_OzW8vHtTkedDIW8yt9Sn",
    "created": "2025-09-30T08:59:59.957Z",
    "currency": "CAD",
    "customer_id": "aaaa",
    "customer": {
        "id": "aaaa",
        "name": null,
        "email": null,
        "phone": null,
        "phone_country_code": null
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "bank_redirect",
    "payment_method_data": {
        "bank_redirect": {
            "type": "BankRedirectResponse",
            "bank_name": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "Downtown Core",
            "country": "SG",
            "line1": "Singapore Changi Airport. 2nd flr",
            "line2": "",
            "line3": "",
            "zip": "039393",
            "state": "Central Indiana America",
            "first_name": "Swangi",
            "last_name": "Kumari",
            "origin_zip": null
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": "swangi.kumari@juspay.in"
    },
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "return_url": null,
    "authentication_type": "three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "interac",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": null,
    "connector_transaction_id": "pay_hJ7WTdtJEsXcY53E7n0W_1",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": null,
        "gateway_system": "direct"
    },
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_C15ZRcjRQncWBGB2yuqm",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_1D5PxJd9ci3fD8Nj9hKL",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-09-30T09:14:59.957Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "127.0.0.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1536,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 723,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": null,
    "network_transaction_id": null,
    "payment_method_status": null,
    "updated": "2025-09-30T09:00:55.783Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "request_extended_authorization": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": null,
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null,
    "enable_partial_authorization": null,
    "enable_overcapture": null,
    "is_overcapture_enabled": null,
    "network_details": null
}
```


## 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
