Bug: [FEATURE] [INESPAY] Implement Sepa Bank Debit Flow



### Feature Description

Implement Sepa Bank Debit Flow

### Possible Implementation

Implement Sepa Bank Debit Flow

### 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/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json
index 41b2c0f80e4..330e504c272 100644
--- a/api-reference-v2/openapi_spec.json
+++ b/api-reference-v2/openapi_spec.json
@@ -6622,6 +6622,7 @@
           "gocardless",
           "gpayments",
           "helcim",
+          "inespay",
           "iatapay",
           "itaubank",
           "jpmorgan",
@@ -19385,6 +19386,7 @@
           "gocardless",
           "helcim",
           "iatapay",
+          "inespay",
           "itaubank",
           "jpmorgan",
           "klarna",
diff --git a/config/development.toml b/config/development.toml
index 08520a2a859..c5986c7cd94 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -567,6 +567,9 @@ debit = { currency = "USD" }
 [pm_filters.fiuu]
 duit_now = { country = "MY", currency = "MYR" }
 
+[pm_filters.inespay]
+sepa = { currency = "EUR" }
+
 [tokenization]
 stripe = { long_lived_token = false, payment_method = "wallet", payment_method_type = { type = "disable_only", list = "google_pay" } }
 checkout = { long_lived_token = false, payment_method = "wallet", apple_pay_pre_decrypt_flow = "network_tokenization" }
diff --git a/crates/common_enums/src/connector_enums.rs b/crates/common_enums/src/connector_enums.rs
index 0402ae06459..f19c0f2aa8c 100644
--- a/crates/common_enums/src/connector_enums.rs
+++ b/crates/common_enums/src/connector_enums.rs
@@ -84,7 +84,7 @@ pub enum RoutableConnectors {
     Gocardless,
     Helcim,
     Iatapay,
-    // Inespay,
+    Inespay,
     Itaubank,
     Jpmorgan,
     Klarna,
@@ -219,7 +219,7 @@ pub enum Connector {
     Gocardless,
     Gpayments,
     Helcim,
-    // Inespay,
+    Inespay,
     Iatapay,
     Itaubank,
     Jpmorgan,
@@ -367,7 +367,7 @@ impl Connector {
             | Self::Gpayments
             | Self::Helcim
             | Self::Iatapay
-			// | Self::Inespay
+			| Self::Inespay
             | Self::Itaubank
             | Self::Jpmorgan
             | Self::Klarna
@@ -537,6 +537,7 @@ impl From<RoutableConnectors> for Connector {
             RoutableConnectors::Plaid => Self::Plaid,
             RoutableConnectors::Zsl => Self::Zsl,
             RoutableConnectors::Xendit => Self::Xendit,
+            RoutableConnectors::Inespay => Self::Inespay,
         }
     }
 }
diff --git a/crates/connector_configs/src/connector.rs b/crates/connector_configs/src/connector.rs
index 791a0679ea3..3175bbde8f2 100644
--- a/crates/connector_configs/src/connector.rs
+++ b/crates/connector_configs/src/connector.rs
@@ -196,7 +196,7 @@ pub struct ConnectorConfig {
     pub gocardless: Option<ConnectorTomlConfig>,
     pub gpayments: Option<ConnectorTomlConfig>,
     pub helcim: Option<ConnectorTomlConfig>,
-    // pub inespay: Option<ConnectorTomlConfig>,
+    pub inespay: Option<ConnectorTomlConfig>,
     pub jpmorgan: Option<ConnectorTomlConfig>,
     pub klarna: Option<ConnectorTomlConfig>,
     pub mifinity: Option<ConnectorTomlConfig>,
@@ -358,7 +358,7 @@ impl ConnectorConfig {
             Connector::Gocardless => Ok(connector_data.gocardless),
             Connector::Gpayments => Ok(connector_data.gpayments),
             Connector::Helcim => Ok(connector_data.helcim),
-            // Connector::Inespay => Ok(connector_data.inespay),
+            Connector::Inespay => Ok(connector_data.inespay),
             Connector::Jpmorgan => Ok(connector_data.jpmorgan),
             Connector::Klarna => Ok(connector_data.klarna),
             Connector::Mifinity => Ok(connector_data.mifinity),
diff --git a/crates/hyperswitch_connectors/src/connectors/inespay.rs b/crates/hyperswitch_connectors/src/connectors/inespay.rs
index 3d3ea346b78..41ae798ade3 100644
--- a/crates/hyperswitch_connectors/src/connectors/inespay.rs
+++ b/crates/hyperswitch_connectors/src/connectors/inespay.rs
@@ -1,12 +1,15 @@
 pub mod transformers;
 
+use base64::Engine;
 use common_utils::{
+    consts::BASE64_ENGINE,
+    crypto,
     errors::CustomResult,
-    ext_traits::BytesExt,
+    ext_traits::{ByteSliceExt, BytesExt},
     request::{Method, Request, RequestBuilder, RequestContent},
     types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector},
 };
-use error_stack::{report, ResultExt};
+use error_stack::ResultExt;
 use hyperswitch_domain_models::{
     router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
     router_flow_types::{
@@ -36,7 +39,8 @@ use hyperswitch_interfaces::{
     types::{self, Response},
     webhooks,
 };
-use masking::{ExposeInterface, Mask};
+use masking::{ExposeInterface, Mask, Secret};
+use ring::hmac;
 use transformers as inespay;
 
 use crate::{constants::headers, types::ResponseRouterData, utils};
@@ -86,8 +90,8 @@ where
             headers::CONTENT_TYPE.to_string(),
             self.get_content_type().to_string().into(),
         )];
-        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
-        header.append(&mut api_key);
+        let mut auth_headers = self.get_auth_header(&req.connector_auth_type)?;
+        header.append(&mut auth_headers);
         Ok(header)
     }
 }
@@ -98,10 +102,7 @@ impl ConnectorCommon for Inespay {
     }
 
     fn get_currency_unit(&self) -> api::CurrencyUnit {
-        api::CurrencyUnit::Base
-        //    TODO! Check connector documentation, on which unit they are processing the currency.
-        //    If the connector accepts amount in lower unit ( i.e cents for USD) then return api::CurrencyUnit::Minor,
-        //    if connector accepts amount in base unit (i.e dollars for USD) then return api::CurrencyUnit::Base
+        api::CurrencyUnit::Minor
     }
 
     fn common_get_content_type(&self) -> &'static str {
@@ -118,10 +119,16 @@ impl ConnectorCommon for Inespay {
     ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
         let auth = inespay::InespayAuthType::try_from(auth_type)
             .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
-        Ok(vec![(
-            headers::AUTHORIZATION.to_string(),
-            auth.api_key.expose().into_masked(),
-        )])
+        Ok(vec![
+            (
+                headers::AUTHORIZATION.to_string(),
+                auth.authorization.expose().into_masked(),
+            ),
+            (
+                headers::X_API_KEY.to_string(),
+                auth.api_key.expose().into_masked(),
+            ),
+        ])
     }
 
     fn build_error_response(
@@ -139,9 +146,9 @@ impl ConnectorCommon for Inespay {
 
         Ok(ErrorResponse {
             status_code: res.status_code,
-            code: response.code,
-            message: response.message,
-            reason: response.reason,
+            code: response.status,
+            message: response.status_desc,
+            reason: None,
             attempt_status: None,
             connector_transaction_id: None,
         })
@@ -176,9 +183,9 @@ 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!("{}/payins/single/init", self.base_url(connectors)))
     }
 
     fn get_request_body(
@@ -192,9 +199,19 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
             req.request.currency,
         )?;
 
-        let connector_router_data = inespay::InespayRouterData::from((amount, req));
-        let connector_req = inespay::InespayPaymentsRequest::try_from(&connector_router_data)?;
-        Ok(RequestContent::Json(Box::new(connector_req)))
+        match req.request.currency {
+            common_enums::Currency::EUR => {
+                let connector_router_data = inespay::InespayRouterData::from((amount, req));
+                let connector_req =
+                    inespay::InespayPaymentsRequest::try_from(&connector_router_data)?;
+                Ok(RequestContent::Json(Box::new(connector_req)))
+            }
+            _ => Err(errors::ConnectorError::CurrencyNotSupported {
+                message: req.request.currency.to_string(),
+                connector: "Inespay",
+            }
+            .into()),
+        }
     }
 
     fn build_request(
@@ -262,10 +279,20 @@ impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Ine
 
     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 connector_payment_id = req
+            .request
+            .connector_transaction_id
+            .get_connector_transaction_id()
+            .change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
+        Ok(format!(
+            "{}{}{}",
+            self.base_url(connectors),
+            "/payins/single/",
+            connector_payment_id,
+        ))
     }
 
     fn build_request(
@@ -289,7 +316,7 @@ impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Ine
         event_builder: Option<&mut ConnectorEvent>,
         res: Response,
     ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
-        let response: inespay::InespayPaymentsResponse = res
+        let response: inespay::InespayPSyncResponse = res
             .response
             .parse_struct("inespay PaymentsSyncResponse")
             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
@@ -406,9 +433,9 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Inespay
     fn get_url(
         &self,
         _req: &RefundsRouterData<Execute>,
-        _connectors: &Connectors,
+        connectors: &Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
+        Ok(format!("{}/refunds/init", self.base_url(connectors)))
     }
 
     fn get_request_body(
@@ -452,9 +479,9 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Inespay
         event_builder: Option<&mut ConnectorEvent>,
         res: Response,
     ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
-        let response: inespay::RefundResponse = res
+        let response: inespay::InespayRefundsResponse = res
             .response
-            .parse_struct("inespay RefundResponse")
+            .parse_struct("inespay InespayRefundsResponse")
             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
@@ -489,10 +516,20 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Inespay {
 
     fn get_url(
         &self,
-        _req: &RefundSyncRouterData,
-        _connectors: &Connectors,
+        req: &RefundSyncRouterData,
+        connectors: &Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
+        let connector_refund_id = req
+            .request
+            .connector_refund_id
+            .clone()
+            .ok_or(errors::ConnectorError::MissingConnectorRefundID)?;
+        Ok(format!(
+            "{}{}{}",
+            self.base_url(connectors),
+            "/refunds/",
+            connector_refund_id,
+        ))
     }
 
     fn build_request(
@@ -519,7 +556,7 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Inespay {
         event_builder: Option<&mut ConnectorEvent>,
         res: Response,
     ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
-        let response: inespay::RefundResponse = res
+        let response: inespay::InespayRSyncResponse = res
             .response
             .parse_struct("inespay RefundSyncResponse")
             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
@@ -541,27 +578,133 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Inespay {
     }
 }
 
+fn get_webhook_body(
+    body: &[u8],
+) -> CustomResult<inespay::InespayWebhookEventData, errors::ConnectorError> {
+    let notif_item: inespay::InespayWebhookEvent =
+        serde_urlencoded::from_bytes::<inespay::InespayWebhookEvent>(body)
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+    let encoded_data_return = notif_item.data_return;
+    let decoded_data_return = BASE64_ENGINE
+        .decode(encoded_data_return)
+        .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+    let data_return: inespay::InespayWebhookEventData = decoded_data_return
+        .parse_struct("inespay InespayWebhookEventData")
+        .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+    Ok(data_return)
+}
+
 #[async_trait::async_trait]
 impl webhooks::IncomingWebhook for Inespay {
-    fn get_webhook_object_reference_id(
+    fn get_webhook_source_verification_algorithm(
         &self,
         _request: &webhooks::IncomingWebhookRequestDetails<'_>,
+    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
+        Ok(Box::new(crypto::HmacSha256))
+    }
+
+    fn get_webhook_source_verification_signature(
+        &self,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
+        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
+    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
+        let notif_item = serde_urlencoded::from_bytes::<inespay::InespayWebhookEvent>(request.body)
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+
+        Ok(notif_item.signature_data_return.as_bytes().to_owned())
+    }
+
+    fn get_webhook_source_verification_message(
+        &self,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
+        _merchant_id: &common_utils::id_type::MerchantId,
+        _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
+    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
+        let notif_item = serde_urlencoded::from_bytes::<inespay::InespayWebhookEvent>(request.body)
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+
+        Ok(notif_item.data_return.into_bytes())
+    }
+
+    async fn verify_webhook_source(
+        &self,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
+        merchant_id: &common_utils::id_type::MerchantId,
+        connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
+        _connector_account_details: crypto::Encryptable<Secret<serde_json::Value>>,
+        connector_label: &str,
+    ) -> CustomResult<bool, errors::ConnectorError> {
+        let connector_webhook_secrets = self
+            .get_webhook_source_verification_merchant_secret(
+                merchant_id,
+                connector_label,
+                connector_webhook_details,
+            )
+            .await?;
+        let signature =
+            self.get_webhook_source_verification_signature(request, &connector_webhook_secrets)?;
+
+        let message = self.get_webhook_source_verification_message(
+            request,
+            merchant_id,
+            &connector_webhook_secrets,
+        )?;
+        let secret = connector_webhook_secrets.secret;
+
+        let signing_key = hmac::Key::new(hmac::HMAC_SHA256, &secret);
+        let signed_message = hmac::sign(&signing_key, &message);
+        let computed_signature = hex::encode(signed_message.as_ref());
+        let payload_sign = BASE64_ENGINE.encode(computed_signature);
+        Ok(payload_sign.as_bytes().eq(&signature))
+    }
+
+    fn get_webhook_object_reference_id(
+        &self,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
-        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
+        let data_return = get_webhook_body(request.body)
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+        match data_return {
+            inespay::InespayWebhookEventData::Payment(data) => {
+                Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
+                    api_models::payments::PaymentIdType::ConnectorTransactionId(
+                        data.single_payin_id,
+                    ),
+                ))
+            }
+            inespay::InespayWebhookEventData::Refund(data) => {
+                Ok(api_models::webhooks::ObjectReferenceId::RefundId(
+                    api_models::webhooks::RefundIdType::ConnectorRefundId(data.refund_id),
+                ))
+            }
+        }
     }
 
     fn get_webhook_event_type(
         &self,
-        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
-        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
+        let data_return = get_webhook_body(request.body)
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+        Ok(api_models::webhooks::IncomingWebhookEvent::from(
+            data_return,
+        ))
     }
 
     fn get_webhook_resource_object(
         &self,
-        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
-        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
+        let data_return = get_webhook_body(request.body)
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+        Ok(match data_return {
+            inespay::InespayWebhookEventData::Payment(payment_webhook_data) => {
+                Box::new(payment_webhook_data)
+            }
+            inespay::InespayWebhookEventData::Refund(refund_webhook_data) => {
+                Box::new(refund_webhook_data)
+            }
+        })
     }
 }
 
diff --git a/crates/hyperswitch_connectors/src/connectors/inespay/transformers.rs b/crates/hyperswitch_connectors/src/connectors/inespay/transformers.rs
index 296d76546c8..2739aa66bee 100644
--- a/crates/hyperswitch_connectors/src/connectors/inespay/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/inespay/transformers.rs
@@ -1,31 +1,33 @@
 use common_enums::enums;
-use common_utils::types::StringMinorUnit;
+use common_utils::{
+    request::Method,
+    types::{MinorUnit, StringMinorUnit, StringMinorUnitForConnector},
+};
+use error_stack::ResultExt;
 use hyperswitch_domain_models::{
-    payment_method_data::PaymentMethodData,
-    router_data::{ConnectorAuthType, RouterData},
+    payment_method_data::{BankDebitData, PaymentMethodData},
+    router_data::{ConnectorAuthType, ErrorResponse, 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 url::Url;
 
 use crate::{
     types::{RefundsResponseRouterData, ResponseRouterData},
-    utils::PaymentsAuthorizeRequestData,
+    utils::{self, PaymentsAuthorizeRequestData, RouterData as _},
 };
-
-//TODO: Fill the struct with respective fields
 pub struct InespayRouterData<T> {
-    pub amount: StringMinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
+    pub amount: StringMinorUnit,
     pub router_data: T,
 }
 
 impl<T> From<(StringMinorUnit, T)> for InespayRouterData<T> {
     fn from((amount, item): (StringMinorUnit, T)) -> Self {
-        //Todo :  use utils to convert the amount to the type of amount that a connector accepts
         Self {
             amount,
             router_data: item,
@@ -33,20 +35,15 @@ impl<T> From<(StringMinorUnit, T)> for InespayRouterData<T> {
     }
 }
 
-//TODO: Fill the struct with respective fields
 #[derive(Default, Debug, Serialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
 pub struct InespayPaymentsRequest {
+    description: String,
     amount: StringMinorUnit,
-    card: InespayCard,
-}
-
-#[derive(Default, Debug, Serialize, Eq, PartialEq)]
-pub struct InespayCard {
-    number: cards::CardNumber,
-    expiry_month: Secret<String>,
-    expiry_year: Secret<String>,
-    cvc: Secret<String>,
-    complete: bool,
+    reference: String,
+    debtor_account: Option<Secret<String>>,
+    success_link_redirect: Option<String>,
+    notif_url: Option<String>,
 }
 
 impl TryFrom<&InespayRouterData<&PaymentsAuthorizeRouterData>> for InespayPaymentsRequest {
@@ -55,17 +52,17 @@ impl TryFrom<&InespayRouterData<&PaymentsAuthorizeRouterData>> for InespayPaymen
         item: &InespayRouterData<&PaymentsAuthorizeRouterData>,
     ) -> Result<Self, Self::Error> {
         match item.router_data.request.payment_method_data.clone() {
-            PaymentMethodData::Card(req_card) => {
-                let card = InespayCard {
-                    number: req_card.card_number,
-                    expiry_month: req_card.card_exp_month,
-                    expiry_year: req_card.card_exp_year,
-                    cvc: req_card.card_cvc,
-                    complete: item.router_data.request.is_auto_capture()?,
-                };
+            PaymentMethodData::BankDebit(BankDebitData::SepaBankDebit { iban, .. }) => {
+                let order_id = item.router_data.connector_request_reference_id.clone();
+                let webhook_url = item.router_data.request.get_webhook_url()?;
+                let return_url = item.router_data.request.get_router_return_url()?;
                 Ok(Self {
+                    description: item.router_data.get_description()?,
                     amount: item.amount.clone(),
-                    card,
+                    reference: order_id,
+                    debtor_account: Some(iban),
+                    success_link_redirect: Some(return_url),
+                    notif_url: Some(webhook_url),
                 })
             }
             _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
@@ -73,156 +70,422 @@ impl TryFrom<&InespayRouterData<&PaymentsAuthorizeRouterData>> for InespayPaymen
     }
 }
 
-//TODO: Fill the struct with respective fields
-// Auth Struct
 pub struct InespayAuthType {
     pub(super) api_key: Secret<String>,
+    pub authorization: Secret<String>,
 }
 
 impl TryFrom<&ConnectorAuthType> for InespayAuthType {
     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 {
+            ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
                 api_key: api_key.to_owned(),
+                authorization: key1.to_owned(),
             }),
             _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
         }
     }
 }
-// PaymentsResponse
-//TODO: Append the remaining status flags
-#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "lowercase")]
-pub enum InespayPaymentStatus {
-    Succeeded,
+
+#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct InespayPaymentsResponseData {
+    status: String,
+    status_desc: String,
+    single_payin_id: String,
+    single_payin_link: String,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(untagged)]
+pub enum InespayPaymentsResponse {
+    InespayPaymentsData(InespayPaymentsResponseData),
+    InespayPaymentsError(InespayErrorResponse),
+}
+
+impl<F, T> TryFrom<ResponseRouterData<F, InespayPaymentsResponse, T, PaymentsResponseData>>
+    for RouterData<F, T, PaymentsResponseData>
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: ResponseRouterData<F, InespayPaymentsResponse, T, PaymentsResponseData>,
+    ) -> Result<Self, Self::Error> {
+        let (status, response) = match item.response {
+            InespayPaymentsResponse::InespayPaymentsData(data) => {
+                let redirection_url = Url::parse(data.single_payin_link.as_str())
+                    .change_context(errors::ConnectorError::ParsingFailed)?;
+                let redirection_data = RedirectForm::from((redirection_url, Method::Get));
+
+                (
+                    common_enums::AttemptStatus::AuthenticationPending,
+                    Ok(PaymentsResponseData::TransactionResponse {
+                        resource_id: ResponseId::ConnectorTransactionId(
+                            data.single_payin_id.clone(),
+                        ),
+                        redirection_data: Box::new(Some(redirection_data)),
+                        mandate_reference: Box::new(None),
+                        connector_metadata: None,
+                        network_txn_id: None,
+                        connector_response_reference_id: None,
+                        incremental_authorization_allowed: None,
+                        charge_id: None,
+                    }),
+                )
+            }
+            InespayPaymentsResponse::InespayPaymentsError(data) => (
+                common_enums::AttemptStatus::Failure,
+                Err(ErrorResponse {
+                    code: data.status.clone(),
+                    message: data.status_desc.clone(),
+                    reason: Some(data.status_desc.clone()),
+                    attempt_status: None,
+                    connector_transaction_id: None,
+                    status_code: item.http_code,
+                }),
+            ),
+        };
+        Ok(Self {
+            status,
+            response,
+            ..item.data
+        })
+    }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum InespayPSyncStatus {
+    Ok,
+    Created,
+    Opened,
+    BankSelected,
+    Initiated,
+    Pending,
+    Aborted,
+    Unfinished,
+    Rejected,
+    Cancelled,
+    PartiallyAccepted,
     Failed,
-    #[default]
-    Processing,
+    Settled,
+    PartRefunded,
+    Refunded,
 }
 
-impl From<InespayPaymentStatus> for common_enums::AttemptStatus {
-    fn from(item: InespayPaymentStatus) -> Self {
+impl From<InespayPSyncStatus> for common_enums::AttemptStatus {
+    fn from(item: InespayPSyncStatus) -> Self {
         match item {
-            InespayPaymentStatus::Succeeded => Self::Charged,
-            InespayPaymentStatus::Failed => Self::Failure,
-            InespayPaymentStatus::Processing => Self::Authorizing,
+            InespayPSyncStatus::Ok | InespayPSyncStatus::Settled => Self::Charged,
+            InespayPSyncStatus::Created
+            | InespayPSyncStatus::Opened
+            | InespayPSyncStatus::BankSelected
+            | InespayPSyncStatus::Initiated
+            | InespayPSyncStatus::Pending
+            | InespayPSyncStatus::Unfinished
+            | InespayPSyncStatus::PartiallyAccepted => Self::AuthenticationPending,
+            InespayPSyncStatus::Aborted
+            | InespayPSyncStatus::Rejected
+            | InespayPSyncStatus::Cancelled
+            | InespayPSyncStatus::Failed => Self::Failure,
+            InespayPSyncStatus::PartRefunded | InespayPSyncStatus::Refunded => Self::AutoRefunded,
         }
     }
 }
 
-//TODO: Fill the struct with respective fields
-#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct InespayPaymentsResponse {
-    status: InespayPaymentStatus,
-    id: String,
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct InespayPSyncResponseData {
+    cod_status: InespayPSyncStatus,
+    status_desc: String,
+    single_payin_id: String,
+    single_payin_link: String,
 }
 
-impl<F, T> TryFrom<ResponseRouterData<F, InespayPaymentsResponse, T, PaymentsResponseData>>
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(untagged)]
+pub enum InespayPSyncResponse {
+    InespayPSyncData(InespayPSyncResponseData),
+    InespayPSyncWebhook(InespayPaymentWebhookData),
+    InespayPSyncError(InespayErrorResponse),
+}
+
+impl<F, T> TryFrom<ResponseRouterData<F, InespayPSyncResponse, T, PaymentsResponseData>>
     for RouterData<F, T, PaymentsResponseData>
 {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(
-        item: ResponseRouterData<F, InespayPaymentsResponse, T, PaymentsResponseData>,
+        item: ResponseRouterData<F, InespayPSyncResponse, T, PaymentsResponseData>,
     ) -> Result<Self, Self::Error> {
-        Ok(Self {
-            status: common_enums::AttemptStatus::from(item.response.status),
-            response: Ok(PaymentsResponseData::TransactionResponse {
-                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
-                redirection_data: Box::new(None),
-                mandate_reference: Box::new(None),
-                connector_metadata: None,
-                network_txn_id: None,
-                connector_response_reference_id: None,
-                incremental_authorization_allowed: None,
-                charge_id: None,
+        match item.response {
+            InespayPSyncResponse::InespayPSyncData(data) => {
+                let redirection_url = Url::parse(data.single_payin_link.as_str())
+                    .change_context(errors::ConnectorError::ParsingFailed)?;
+                let redirection_data = RedirectForm::from((redirection_url, Method::Get));
+
+                Ok(Self {
+                    status: common_enums::AttemptStatus::from(data.cod_status),
+                    response: Ok(PaymentsResponseData::TransactionResponse {
+                        resource_id: ResponseId::ConnectorTransactionId(
+                            data.single_payin_id.clone(),
+                        ),
+                        redirection_data: Box::new(Some(redirection_data)),
+                        mandate_reference: Box::new(None),
+                        connector_metadata: None,
+                        network_txn_id: None,
+                        connector_response_reference_id: None,
+                        incremental_authorization_allowed: None,
+                        charge_id: None,
+                    }),
+                    ..item.data
+                })
+            }
+            InespayPSyncResponse::InespayPSyncWebhook(data) => {
+                let status = enums::AttemptStatus::from(data.cod_status);
+                Ok(Self {
+                    status,
+                    response: Ok(PaymentsResponseData::TransactionResponse {
+                        resource_id: ResponseId::ConnectorTransactionId(
+                            data.single_payin_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,
+                        charge_id: None,
+                    }),
+                    ..item.data
+                })
+            }
+            InespayPSyncResponse::InespayPSyncError(data) => Ok(Self {
+                response: Err(ErrorResponse {
+                    code: data.status.clone(),
+                    message: data.status_desc.clone(),
+                    reason: Some(data.status_desc.clone()),
+                    attempt_status: None,
+                    connector_transaction_id: None,
+                    status_code: item.http_code,
+                }),
+                ..item.data
             }),
-            ..item.data
-        })
+        }
     }
 }
 
-//TODO: Fill the struct with respective fields
-// REFUND :
-// Type definition for RefundRequest
-#[derive(Default, Debug, Serialize)]
+#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
 pub struct InespayRefundRequest {
-    pub amount: StringMinorUnit,
+    single_payin_id: String,
+    amount: Option<MinorUnit>,
 }
 
 impl<F> TryFrom<&InespayRouterData<&RefundsRouterData<F>>> for InespayRefundRequest {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(item: &InespayRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
+        let amount = utils::convert_back_amount_to_minor_units(
+            &StringMinorUnitForConnector,
+            item.amount.to_owned(),
+            item.router_data.request.currency,
+        )?;
         Ok(Self {
-            amount: item.amount.to_owned(),
+            single_payin_id: item.router_data.request.connector_transaction_id.clone(),
+            amount: Some(amount),
         })
     }
 }
 
-// Type definition for Refund Response
-
-#[allow(dead_code)]
-#[derive(Debug, Serialize, Default, Deserialize, Clone)]
-pub enum RefundStatus {
-    Succeeded,
-    Failed,
+#[derive(Debug, Serialize, Default, Deserialize, Clone, PartialEq)]
+#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
+pub enum InespayRSyncStatus {
+    Confirmed,
     #[default]
-    Processing,
+    Pending,
+    Rejected,
+    Denied,
+    Reversed,
+    Mistake,
 }
 
-impl From<RefundStatus> for enums::RefundStatus {
-    fn from(item: RefundStatus) -> Self {
+impl From<InespayRSyncStatus> for enums::RefundStatus {
+    fn from(item: InespayRSyncStatus) -> Self {
         match item {
-            RefundStatus::Succeeded => Self::Success,
-            RefundStatus::Failed => Self::Failure,
-            RefundStatus::Processing => Self::Pending,
-            //TODO: Review mapping
+            InespayRSyncStatus::Confirmed => Self::Success,
+            InespayRSyncStatus::Pending => Self::Pending,
+            InespayRSyncStatus::Rejected
+            | InespayRSyncStatus::Denied
+            | InespayRSyncStatus::Reversed
+            | InespayRSyncStatus::Mistake => Self::Failure,
         }
     }
 }
 
-//TODO: Fill the struct with respective fields
 #[derive(Default, Debug, Clone, Serialize, Deserialize)]
-pub struct RefundResponse {
-    id: String,
-    status: RefundStatus,
+#[serde(rename_all = "camelCase")]
+pub struct RefundsData {
+    status: String,
+    status_desc: String,
+    refund_id: String,
 }
 
-impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>> for RefundsRouterData<Execute> {
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(untagged)]
+pub enum InespayRefundsResponse {
+    InespayRefundsData(RefundsData),
+    InespayRefundsError(InespayErrorResponse),
+}
+
+impl TryFrom<RefundsResponseRouterData<Execute, InespayRefundsResponse>>
+    for RefundsRouterData<Execute>
+{
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(
-        item: RefundsResponseRouterData<Execute, RefundResponse>,
+        item: RefundsResponseRouterData<Execute, InespayRefundsResponse>,
     ) -> Result<Self, Self::Error> {
-        Ok(Self {
-            response: Ok(RefundsResponseData {
-                connector_refund_id: item.response.id.to_string(),
-                refund_status: enums::RefundStatus::from(item.response.status),
+        match item.response {
+            InespayRefundsResponse::InespayRefundsData(data) => Ok(Self {
+                response: Ok(RefundsResponseData {
+                    connector_refund_id: data.refund_id,
+                    refund_status: enums::RefundStatus::Pending,
+                }),
+                ..item.data
             }),
-            ..item.data
-        })
+            InespayRefundsResponse::InespayRefundsError(data) => Ok(Self {
+                response: Err(ErrorResponse {
+                    code: data.status.clone(),
+                    message: data.status_desc.clone(),
+                    reason: Some(data.status_desc.clone()),
+                    attempt_status: None,
+                    connector_transaction_id: None,
+                    status_code: item.http_code,
+                }),
+                ..item.data
+            }),
+        }
     }
 }
 
-impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouterData<RSync> {
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct InespayRSyncResponseData {
+    cod_status: InespayRSyncStatus,
+    status_desc: String,
+    refund_id: String,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(untagged)]
+pub enum InespayRSyncResponse {
+    InespayRSyncData(InespayRSyncResponseData),
+    InespayRSyncWebhook(InespayRefundWebhookData),
+    InespayRSyncError(InespayErrorResponse),
+}
+
+impl TryFrom<RefundsResponseRouterData<RSync, InespayRSyncResponse>> for RefundsRouterData<RSync> {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(
-        item: RefundsResponseRouterData<RSync, RefundResponse>,
+        item: RefundsResponseRouterData<RSync, InespayRSyncResponse>,
     ) -> Result<Self, Self::Error> {
-        Ok(Self {
-            response: Ok(RefundsResponseData {
-                connector_refund_id: item.response.id.to_string(),
-                refund_status: enums::RefundStatus::from(item.response.status),
+        let response = match item.response {
+            InespayRSyncResponse::InespayRSyncData(data) => Ok(RefundsResponseData {
+                connector_refund_id: data.refund_id,
+                refund_status: enums::RefundStatus::from(data.cod_status),
+            }),
+            InespayRSyncResponse::InespayRSyncWebhook(data) => Ok(RefundsResponseData {
+                connector_refund_id: data.refund_id,
+                refund_status: enums::RefundStatus::from(data.cod_status),
+            }),
+            InespayRSyncResponse::InespayRSyncError(data) => Err(ErrorResponse {
+                code: data.status.clone(),
+                message: data.status_desc.clone(),
+                reason: Some(data.status_desc.clone()),
+                attempt_status: None,
+                connector_transaction_id: None,
+                status_code: item.http_code,
             }),
+        };
+        Ok(Self {
+            response,
             ..item.data
         })
     }
 }
 
-//TODO: Fill the struct with respective fields
+#[derive(Serialize, Deserialize, Clone, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct InespayPaymentWebhookData {
+    pub single_payin_id: String,
+    pub cod_status: InespayPSyncStatus,
+    pub description: String,
+    pub amount: MinorUnit,
+    pub reference: String,
+    pub creditor_account: Secret<String>,
+    pub debtor_name: Secret<String>,
+    pub debtor_account: Secret<String>,
+    pub custom_data: Option<String>,
+}
+
+#[derive(Serialize, Deserialize, Clone, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct InespayRefundWebhookData {
+    pub refund_id: String,
+    pub simple_payin_id: String,
+    pub cod_status: InespayRSyncStatus,
+    pub description: String,
+    pub amount: MinorUnit,
+    pub reference: String,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+#[serde(untagged)]
+pub enum InespayWebhookEventData {
+    Payment(InespayPaymentWebhookData),
+    Refund(InespayRefundWebhookData),
+}
+
+#[derive(Serialize, Deserialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct InespayWebhookEvent {
+    pub data_return: String,
+    pub signature_data_return: String,
+}
+
 #[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
 pub struct InespayErrorResponse {
-    pub status_code: u16,
-    pub code: String,
-    pub message: String,
-    pub reason: Option<String>,
+    pub status: String,
+    pub status_desc: String,
+}
+
+impl From<InespayWebhookEventData> for api_models::webhooks::IncomingWebhookEvent {
+    fn from(item: InespayWebhookEventData) -> Self {
+        match item {
+            InespayWebhookEventData::Payment(payment_data) => match payment_data.cod_status {
+                InespayPSyncStatus::Ok | InespayPSyncStatus::Settled => Self::PaymentIntentSuccess,
+                InespayPSyncStatus::Failed | InespayPSyncStatus::Rejected => {
+                    Self::PaymentIntentFailure
+                }
+                InespayPSyncStatus::Created
+                | InespayPSyncStatus::Opened
+                | InespayPSyncStatus::BankSelected
+                | InespayPSyncStatus::Initiated
+                | InespayPSyncStatus::Pending
+                | InespayPSyncStatus::Unfinished
+                | InespayPSyncStatus::PartiallyAccepted => Self::PaymentIntentProcessing,
+                InespayPSyncStatus::Aborted
+                | InespayPSyncStatus::Cancelled
+                | InespayPSyncStatus::PartRefunded
+                | InespayPSyncStatus::Refunded => Self::EventNotSupported,
+            },
+            InespayWebhookEventData::Refund(refund_data) => match refund_data.cod_status {
+                InespayRSyncStatus::Confirmed => Self::RefundSuccess,
+                InespayRSyncStatus::Rejected
+                | InespayRSyncStatus::Denied
+                | InespayRSyncStatus::Reversed
+                | InespayRSyncStatus::Mistake => Self::RefundFailure,
+                InespayRSyncStatus::Pending => Self::EventNotSupported,
+            },
+        }
+    }
 }
diff --git a/crates/router/src/core/admin.rs b/crates/router/src/core/admin.rs
index fd9f08089af..0d5d1a3fc7a 100644
--- a/crates/router/src/core/admin.rs
+++ b/crates/router/src/core/admin.rs
@@ -1395,10 +1395,10 @@ impl ConnectorAuthTypeAndMetadataValidation<'_> {
                 iatapay::transformers::IatapayAuthType::try_from(self.auth_type)?;
                 Ok(())
             }
-            // api_enums::Connector::Inespay => {
-            //     inespay::transformers::InespayAuthType::try_from(self.auth_type)?;
-            //     Ok(())
-            // }
+            api_enums::Connector::Inespay => {
+                inespay::transformers::InespayAuthType::try_from(self.auth_type)?;
+                Ok(())
+            }
             api_enums::Connector::Itaubank => {
                 itaubank::transformers::ItaubankAuthType::try_from(self.auth_type)?;
                 Ok(())
diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs
index 243b6116e72..add1bd95b56 100644
--- a/crates/router/src/types/api.rs
+++ b/crates/router/src/types/api.rs
@@ -441,9 +441,9 @@ impl ConnectorData {
                 enums::Connector::Iatapay => {
                     Ok(ConnectorEnum::Old(Box::new(connector::Iatapay::new())))
                 }
-                // enums::Connector::Inespay => {
-                //     Ok(ConnectorEnum::Old(Box::new(connector::Inespay::new())))
-                // }
+                enums::Connector::Inespay => {
+                    Ok(ConnectorEnum::Old(Box::new(connector::Inespay::new())))
+                }
                 enums::Connector::Itaubank => {
                     Ok(ConnectorEnum::Old(Box::new(connector::Itaubank::new())))
                 }
diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs
index 06682f596ed..4d946ca97ad 100644
--- a/crates/router/src/types/transformers.rs
+++ b/crates/router/src/types/transformers.rs
@@ -254,7 +254,7 @@ impl ForeignTryFrom<api_enums::Connector> for common_enums::RoutableConnectors {
             }
             api_enums::Connector::Helcim => Self::Helcim,
             api_enums::Connector::Iatapay => Self::Iatapay,
-            // api_enums::Connector::Inespay => Self::Inespay,
+            api_enums::Connector::Inespay => Self::Inespay,
             api_enums::Connector::Itaubank => Self::Itaubank,
             api_enums::Connector::Jpmorgan => Self::Jpmorgan,
             api_enums::Connector::Klarna => Self::Klarna,

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

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

## Description
<!-- Describe your changes in detail -->
Added payment flows (Auth, PSync, Refund, RSync, and Webhooks) for Inespay Sepa Bank Debit.


### 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)?
-->
1. Merchant Account Create
2. API Key Create
3.Inespay Connector Create:
```
curl --location 'http://localhost:8080/account/merchant_1736331946/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data '{
    "connector_type": "payment_processor",
    "connector_name": "inespay",
    "connector_account_details": {
        "auth_type": "BodyKey",
        "api_key": "abc",
        "key1": "abc"
    },
    "test_mode": false,
    "disabled": false,
    "payment_methods_enabled": [
        {
                "payment_method": "bank_debit",
                "payment_method_types": [
                    {
                        "payment_method_type": "sepa",
                        "payment_experience": "redirect_to_url",
                        "card_networks": null,
                        "accepted_currencies": null,
                        "accepted_countries": null,
                        "minimum_amount": 0,
                        "maximum_amount": 68607706,
                        "recurring_enabled": true,
                        "installment_payment_enabled": false
                    }
                ]
            }
    ],
    "connector_webhook_details": {
        "merchant_secret": "abc",
        "additional_secret": null
    }
}'
```

4. Payments Create:
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_t54RQO5Ci3L3J3sV0GFUeySuR0d3zPe66OxpRV8qKD3Th7Pyquxxro6afDNCapom' \
--data '{
  "amount": 6540,
  "currency": "EUR",
  "confirm": true,
  "amount_to_capture": 6540,
  "customer_id": "StripbmnxeCustomer",
  "description": "Its my first payment request",
  "return_url": "https://google.com",
  "payment_method": "bank_debit",
  "payment_method_type": "sepa",
  "payment_method_data": {
    "bank_debit": {
      "sepa_bank_debit": {
        "iban": "ES5031831357110123456789"
      }
    }
  }
}'
```

Response:
```
{
    "payment_id": "pay_2hUGMfU0Wv31Gn3unXgG",
    "merchant_id": "merchant_1736331946",
    "status": "requires_customer_action",
    "amount": 6540,
    "net_amount": 6540,
    "shipping_cost": null,
    "amount_capturable": 6540,
    "amount_received": null,
    "connector": "inespay",
    "client_secret": "pay_2hUGMfU0Wv31Gn3unXgG_secret_iYsSbpRHSGd4bEJ3OBET",
    "created": "2025-01-09T08:55:12.497Z",
    "currency": "EUR",
    "customer_id": "StripeCustomer",
    "customer": {
        "id": "StripeCustomer",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "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_debit",
    "payment_method_data": {
        "bank_debit": {
            "sepa": {
                "iban": "ES503**************56789",
                "bank_account_holder_name": null
            }
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "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_2hUGMfU0Wv31Gn3unXgG/merchant_1736331946/pay_2hUGMfU0Wv31Gn3unXgG_1"
    },
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "sepa",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "StripeCustomer",
        "created_at": 1736412912,
        "expires": 1736416512,
        "secret": "epk_a8553335e63d4417ba67bfe8301b8799"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": "PMWC9HMC-E37E-I83G-FZWOCP9S2GDVX8ZD",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_oPMGl04eyRD2pY0laexI",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_RTX0eIQOVWNhcTAeKXQQ",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-01-09T09:10:12.497Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-01-09T08:55:13.385Z",
    "split_payments": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}
```

5. Payments Retrieve:
```
curl --location 'http://localhost:8080/payments/pay_xoODE5mPdtuN8tr5xyMz?force_sync=true' \
--header 'Accept: application/json' \
--header 'api-key: dev_t54RQO5Ci3L3J3sV0GFUeySuR0d3zPe66OxpRV8qKD3Th7Pyquxxro6afDNCapom'
```

Response:
```
{
    "payment_id": "pay_TcadxZAWM2P3PjWJ7PRC",
    "merchant_id": "merchant_1736331946",
    "status": "requires_customer_action",
    "amount": 6540,
    "net_amount": 6540,
    "shipping_cost": null,
    "amount_capturable": 6540,
    "amount_received": null,
    "connector": "inespay",
    "client_secret": "pay_TcadxZAWM2P3PjWJ7PRC_secret_xpi5fQgZ7uqbr42h1uxt",
    "created": "2025-01-09T08:44:46.048Z",
    "currency": "EUR",
    "customer_id": "StripeCustomer",
    "customer": {
        "id": "StripeCustomer",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "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_debit",
    "payment_method_data": {
        "bank_debit": {
            "sepa": {
                "iban": "ES113**************40674",
                "bank_account_holder_name": null
            }
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "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_TcadxZAWM2P3PjWJ7PRC/merchant_1736331946/pay_TcadxZAWM2P3PjWJ7PRC_1"
    },
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "sepa",
    "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": "BKBBNZ68-17K5-B4SL-LTC0545XW13LKIBK",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_oPMGl04eyRD2pY0laexI",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_RTX0eIQOVWNhcTAeKXQQ",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-01-09T08:59:46.047Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-01-09T08:45:37.239Z",
    "split_payments": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}
```
6. Refunds:
```
curl --location 'http://localhost:8080/refunds' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_J5g19W9vemKtoeyfLV5hBEovbKns39FLpAxqj8SnuDnFdLCJcIHJX928eOVl8nkd' \
--data '{
  "payment_id": "pay_2hUGMfU0Wv31Gn3unXgG",
  "amount": 600,
  "reason": "Customer returned product",
  "refund_type": "instant",
  "metadata": {
    "udf1": "value1",
    "new_customer": "true",
    "login_date": "2019-09-10T10:11:12Z"
  }
}'
```
7. Refunds Retrieve:
```
curl --location 'http://localhost:8080/refunds/' \
--header 'Accept: application/json' \
--header 'api-key: dev_J5g19W9vemKtoeyfLV5hBEovbKns39FLpAxqj8SnuDnFdLCJcIHJX928eOVl8nkd'
```


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