Bug: [FEATURE] [DEUTSCHEBANK] Implement subsequent mandate payments via SEPA



### Feature Description

Implement SEPA mandate payments for Deutschebank.

### Possible Implementation

Implement SEPA mandate payments for Deutschebank.

### 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/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index b0866cfb265..535a5abffce 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -1042,6 +1042,7 @@ pub struct ConnectorMandateReferenceId {
     pub connector_mandate_id: Option<String>,
     pub payment_method_id: Option<String>,
     pub update_history: Option<Vec<UpdateHistory>>,
+    pub mandate_metadata: Option<serde_json::Value>,
 }
 
 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Eq, PartialEq)]
diff --git a/crates/hyperswitch_connectors/src/connectors/deutschebank.rs b/crates/hyperswitch_connectors/src/connectors/deutschebank.rs
index 30e67babe89..a861155afb3 100644
--- a/crates/hyperswitch_connectors/src/connectors/deutschebank.rs
+++ b/crates/hyperswitch_connectors/src/connectors/deutschebank.rs
@@ -50,7 +50,10 @@ use transformers as deutschebank;
 use crate::{
     constants::headers,
     types::ResponseRouterData,
-    utils::{self, PaymentsCompleteAuthorizeRequestData, RefundsRequestData},
+    utils::{
+        self, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData,
+        RefundsRequestData,
+    },
 };
 
 #[derive(Clone)]
@@ -182,6 +185,16 @@ impl ConnectorValidation for Deutschebank {
             ),
         }
     }
+
+    fn validate_mandate_payment(
+        &self,
+        pm_type: Option<enums::PaymentMethodType>,
+        pm_data: hyperswitch_domain_models::payment_method_data::PaymentMethodData,
+    ) -> CustomResult<(), errors::ConnectorError> {
+        let mandate_supported_pmd =
+            std::collections::HashSet::from([utils::PaymentMethodDataType::SepaBankDebit]);
+        utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id())
+    }
 }
 
 impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Deutschebank {
@@ -302,13 +315,26 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
 
     fn get_url(
         &self,
-        _req: &PaymentsAuthorizeRouterData,
+        req: &PaymentsAuthorizeRouterData,
         connectors: &Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
-        Ok(format!(
-            "{}/services/v2.1/managedmandate",
-            self.base_url(connectors)
-        ))
+        if req.request.connector_mandate_id().is_none() {
+            Ok(format!(
+                "{}/services/v2.1/managedmandate",
+                self.base_url(connectors)
+            ))
+        } else {
+            let event_id = req.connector_request_reference_id.clone();
+            let tx_action = if req.request.is_auto_capture()? {
+                "authorization"
+            } else {
+                "preauthorization"
+            };
+            Ok(format!(
+                "{}/services/v2.1/payment/event/{event_id}/directdebit/{tx_action}",
+                self.base_url(connectors)
+            ))
+        }
     }
 
     fn get_request_body(
@@ -356,17 +382,31 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
         event_builder: Option<&mut ConnectorEvent>,
         res: Response,
     ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
-        let response: deutschebank::DeutschebankMandatePostResponse = res
-            .response
-            .parse_struct("Deutschebank PaymentsAuthorizeResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        event_builder.map(|i| i.set_response_body(&response));
-        router_env::logger::info!(connector_response=?response);
-        RouterData::try_from(ResponseRouterData {
-            response,
-            data: data.clone(),
-            http_code: res.status_code,
-        })
+        if data.request.connector_mandate_id().is_none() {
+            let response: deutschebank::DeutschebankMandatePostResponse = res
+                .response
+                .parse_struct("DeutschebankMandatePostResponse")
+                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+            event_builder.map(|i| i.set_response_body(&response));
+            router_env::logger::info!(connector_response=?response);
+            RouterData::try_from(ResponseRouterData {
+                response,
+                data: data.clone(),
+                http_code: res.status_code,
+            })
+        } else {
+            let response: deutschebank::DeutschebankPaymentsResponse = res
+                .response
+                .parse_struct("DeutschebankPaymentsAuthorizeResponse")
+                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+            event_builder.map(|i| i.set_response_body(&response));
+            router_env::logger::info!(connector_response=?response);
+            RouterData::try_from(ResponseRouterData {
+                response,
+                data: data.clone(),
+                http_code: res.status_code,
+            })
+        }
     }
 
     fn get_error_response(
diff --git a/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs b/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs
index dc146dc38d4..8b3837edd63 100644
--- a/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/deutschebank/transformers.rs
@@ -1,7 +1,8 @@
 use std::collections::HashMap;
 
 use common_enums::enums;
-use common_utils::{pii::Email, types::MinorUnit};
+use common_utils::{ext_traits::ValueExt, pii::Email, types::MinorUnit};
+use error_stack::ResultExt;
 use hyperswitch_domain_models::{
     payment_method_data::{BankDebitData, PaymentMethodData},
     router_data::{AccessToken, ConnectorAuthType, RouterData},
@@ -13,7 +14,9 @@ use hyperswitch_domain_models::{
         CompleteAuthorizeData, PaymentsAuthorizeData, PaymentsCaptureData, PaymentsSyncData,
         ResponseId,
     },
-    router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData},
+    router_response_types::{
+        MandateReference, PaymentsResponseData, RedirectForm, RefundsResponseData,
+    },
     types::{
         PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
         PaymentsCompleteAuthorizeRouterData, RefundsRouterData,
@@ -26,8 +29,8 @@ use serde::{Deserialize, Serialize};
 use crate::{
     types::{PaymentsCancelResponseRouterData, RefundsResponseRouterData, ResponseRouterData},
     utils::{
-        AddressDetailsData, PaymentsAuthorizeRequestData, PaymentsCompleteAuthorizeRequestData,
-        RefundsRequestData, RouterData as OtherRouterData,
+        self, AddressDetailsData, PaymentsAuthorizeRequestData,
+        PaymentsCompleteAuthorizeRequestData, RefundsRequestData, RouterData as OtherRouterData,
     },
 };
 
@@ -113,7 +116,7 @@ pub enum DeutschebankSEPAApproval {
 }
 
 #[derive(Debug, Serialize, PartialEq)]
-pub struct DeutschebankPaymentsRequest {
+pub struct DeutschebankMandatePostRequest {
     approval_by: DeutschebankSEPAApproval,
     email_address: Email,
     iban: Secret<String>,
@@ -121,6 +124,13 @@ pub struct DeutschebankPaymentsRequest {
     last_name: Secret<String>,
 }
 
+#[derive(Debug, Serialize)]
+#[serde(untagged)]
+pub enum DeutschebankPaymentsRequest {
+    MandatePost(DeutschebankMandatePostRequest),
+    DirectDebit(DeutschebankDirectDebitRequest),
+}
+
 impl TryFrom<&DeutschebankRouterData<&PaymentsAuthorizeRouterData>>
     for DeutschebankPaymentsRequest
 {
@@ -128,16 +138,71 @@ impl TryFrom<&DeutschebankRouterData<&PaymentsAuthorizeRouterData>>
     fn try_from(
         item: &DeutschebankRouterData<&PaymentsAuthorizeRouterData>,
     ) -> Result<Self, Self::Error> {
-        let billing_address = item.router_data.get_billing_address()?;
-        match item.router_data.request.payment_method_data.clone() {
-            PaymentMethodData::BankDebit(BankDebitData::SepaBankDebit { iban, .. }) => Ok(Self {
-                approval_by: DeutschebankSEPAApproval::Click,
-                email_address: item.router_data.request.get_email()?,
-                iban,
-                first_name: billing_address.get_first_name()?.clone(),
-                last_name: billing_address.get_last_name()?.clone(),
-            }),
-            _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
+        match item
+            .router_data
+            .request
+            .mandate_id
+            .clone()
+            .and_then(|mandate_id| mandate_id.mandate_reference_id)
+        {
+            None => {
+                if item.router_data.request.is_mandate_payment() {
+                    match item.router_data.request.payment_method_data.clone() {
+                        PaymentMethodData::BankDebit(BankDebitData::SepaBankDebit {
+                            iban, ..
+                        }) => {
+                            let billing_address = item.router_data.get_billing_address()?;
+                            Ok(Self::MandatePost(DeutschebankMandatePostRequest {
+                                approval_by: DeutschebankSEPAApproval::Click,
+                                email_address: item.router_data.request.get_email()?,
+                                iban,
+                                first_name: billing_address.get_first_name()?.clone(),
+                                last_name: billing_address.get_last_name()?.clone(),
+                            }))
+                        }
+                        _ => Err(errors::ConnectorError::NotImplemented(
+                            utils::get_unimplemented_payment_method_error_message("deutschebank"),
+                        )
+                        .into()),
+                    }
+                } else {
+                    Err(errors::ConnectorError::MissingRequiredField {
+                        field_name: "setup_future_usage or customer_acceptance.acceptance_type",
+                    }
+                    .into())
+                }
+            }
+            Some(api_models::payments::MandateReferenceId::ConnectorMandateId(mandate_data)) => {
+                let mandate_metadata: DeutschebankMandateMetadata = mandate_data
+                    .mandate_metadata
+                    .ok_or(errors::ConnectorError::MissingConnectorMandateMetadata)?
+                    .clone()
+                    .parse_value("DeutschebankMandateMetadata")
+                    .change_context(errors::ConnectorError::ParsingFailed)?;
+                Ok(Self::DirectDebit(DeutschebankDirectDebitRequest {
+                    amount_total: DeutschebankAmount {
+                        amount: item.amount,
+                        currency: item.router_data.request.currency,
+                    },
+                    means_of_payment: DeutschebankMeansOfPayment {
+                        bank_account: DeutschebankBankAccount {
+                            account_holder: mandate_metadata.account_holder,
+                            iban: mandate_metadata.iban,
+                        },
+                    },
+                    mandate: DeutschebankMandate {
+                        reference: mandate_metadata.reference,
+                        signed_on: mandate_metadata.signed_on,
+                    },
+                }))
+            }
+            Some(api_models::payments::MandateReferenceId::NetworkTokenWithNTI(_))
+            | Some(api_models::payments::MandateReferenceId::NetworkMandateId(_)) => {
+                Err(errors::ConnectorError::NotImplemented(
+                    utils::get_unimplemented_payment_method_error_message("deutschebank"),
+                )
+                .into())
+            }
         }
     }
 }
@@ -176,6 +241,14 @@ impl From<DeutschebankSEPAMandateStatus> for common_enums::AttemptStatus {
     }
 }
 
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+pub struct DeutschebankMandateMetadata {
+    account_holder: Secret<String>,
+    iban: Secret<String>,
+    reference: Secret<String>,
+    signed_on: String,
+}
+
 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
 pub struct DeutschebankMandatePostResponse {
     rc: String,
@@ -207,14 +280,14 @@ impl
             PaymentsResponseData,
         >,
     ) -> Result<Self, Self::Error> {
-        let signed_on = match item.response.approval_date {
+        let signed_on = match item.response.approval_date.clone() {
             Some(date) => date.chars().take(10).collect(),
             None => time::OffsetDateTime::now_utc().date().to_string(),
         };
-        match item.response.reference {
+        match item.response.reference.clone() {
             Some(reference) => Ok(Self {
                 status: if item.response.rc == "0" {
-                    match item.response.state {
+                    match item.response.state.clone() {
                         Some(state) => common_enums::AttemptStatus::from(state),
                         None => common_enums::AttemptStatus::Failure,
                     }
@@ -227,11 +300,29 @@ impl
                         endpoint: item.data.request.get_complete_authorize_url()?,
                         method: common_utils::request::Method::Get,
                         form_fields: HashMap::from([
-                            ("reference".to_string(), reference),
-                            ("signed_on".to_string(), signed_on),
+                            ("reference".to_string(), reference.clone()),
+                            ("signed_on".to_string(), signed_on.clone()),
                         ]),
                     }),
-                    mandate_reference: None,
+                    mandate_reference: Some(MandateReference {
+                        connector_mandate_id: item.response.mandate_id,
+                        payment_method_id: None,
+                        mandate_metadata: Some(serde_json::json!(DeutschebankMandateMetadata {
+                            account_holder: item.data.get_billing_address()?.get_full_name()?,
+                            iban: match item.data.request.payment_method_data.clone() {
+                                PaymentMethodData::BankDebit(BankDebitData::SepaBankDebit {
+                                    iban,
+                                    ..
+                                }) => Ok(iban),
+                                _ => Err(errors::ConnectorError::MissingRequiredField {
+                                    field_name:
+                                        "payment_method_data.bank_debit.sepa_bank_debit.iban"
+                                }),
+                            }?,
+                            reference: Secret::from(reference),
+                            signed_on,
+                        })),
+                    }),
                     connector_metadata: None,
                     network_txn_id: None,
                     connector_response_reference_id: None,
@@ -248,6 +339,49 @@ impl
     }
 }
 
+impl
+    TryFrom<
+        ResponseRouterData<
+            Authorize,
+            DeutschebankPaymentsResponse,
+            PaymentsAuthorizeData,
+            PaymentsResponseData,
+        >,
+    > for RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: ResponseRouterData<
+            Authorize,
+            DeutschebankPaymentsResponse,
+            PaymentsAuthorizeData,
+            PaymentsResponseData,
+        >,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            status: if item.response.rc == "0" {
+                match item.data.request.is_auto_capture()? {
+                    true => common_enums::AttemptStatus::Charged,
+                    false => common_enums::AttemptStatus::Authorized,
+                }
+            } else {
+                common_enums::AttemptStatus::Failure
+            },
+            response: Ok(PaymentsResponseData::TransactionResponse {
+                resource_id: ResponseId::ConnectorTransactionId(item.response.tx_id),
+                redirection_data: None,
+                mandate_reference: None,
+                connector_metadata: None,
+                network_txn_id: None,
+                connector_response_reference_id: None,
+                incremental_authorization_allowed: None,
+                charge_id: None,
+            }),
+            ..item.data
+        })
+    }
+}
+
 #[derive(Debug, Serialize, Deserialize, PartialEq)]
 pub struct DeutschebankAmount {
     amount: MinorUnit,
@@ -268,7 +402,7 @@ pub struct DeutschebankBankAccount {
 #[derive(Debug, Serialize, PartialEq)]
 pub struct DeutschebankMandate {
     reference: Secret<String>,
-    signed_on: Secret<String>,
+    signed_on: String,
 }
 
 #[derive(Debug, Serialize, PartialEq)]
@@ -319,14 +453,12 @@ impl TryFrom<&DeutschebankRouterData<&PaymentsCompleteAuthorizeRouterData>>
                 })?
                 .to_owned(),
         );
-        let signed_on = Secret::from(
-            queries_params
-                .get("signed_on")
-                .ok_or(errors::ConnectorError::MissingRequiredField {
-                    field_name: "signed_on",
-                })?
-                .to_owned(),
-        );
+        let signed_on = queries_params
+            .get("signed_on")
+            .ok_or(errors::ConnectorError::MissingRequiredField {
+                field_name: "signed_on",
+            })?
+            .to_owned();
 
         match item.router_data.request.payment_method_data.clone() {
             Some(PaymentMethodData::BankDebit(BankDebitData::SepaBankDebit { iban, .. })) => {
@@ -349,7 +481,10 @@ impl TryFrom<&DeutschebankRouterData<&PaymentsCompleteAuthorizeRouterData>>
                     },
                 })
             }
-            _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
+            _ => Err(errors::ConnectorError::NotImplemented(
+                utils::get_unimplemented_payment_method_error_message("deutschebank"),
+            )
+            .into()),
         }
     }
 }
diff --git a/crates/hyperswitch_connectors/src/connectors/fiservemea/transformers.rs b/crates/hyperswitch_connectors/src/connectors/fiservemea/transformers.rs
index fdec3d0e1eb..7f88903e867 100644
--- a/crates/hyperswitch_connectors/src/connectors/fiservemea/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/fiservemea/transformers.rs
@@ -170,13 +170,6 @@ pub enum ResponseType {
     UnsupportedMediaType,
 }
 
-#[derive(Debug, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub enum FiservemeaResponseType {
-    TransactionResponse,
-    ErrorResponse,
-}
-
 #[derive(Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
 pub enum FiservemeaTransactionType {
@@ -329,7 +322,7 @@ fn map_status(
 pub struct FiservemeaPaymentsResponse {
     response_type: Option<ResponseType>,
     #[serde(rename = "type")]
-    fiservemea_type: Option<FiservemeaResponseType>,
+    fiservemea_type: Option<String>,
     client_request_id: Option<String>,
     api_trace_id: Option<String>,
     ipg_transaction_id: String,
@@ -526,7 +519,7 @@ pub struct FiservemeaError {
 #[derive(Debug, Serialize, Deserialize)]
 pub struct FiservemeaErrorResponse {
     #[serde(rename = "type")]
-    fiservemea_type: Option<FiservemeaResponseType>,
+    fiservemea_type: Option<String>,
     client_request_id: Option<String>,
     api_trace_id: Option<String>,
     pub response_type: Option<String>,
diff --git a/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs b/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
index b400555305d..56da53c2873 100644
--- a/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs
@@ -787,6 +787,7 @@ impl<F>
                             MandateReference {
                                 connector_mandate_id: Some(id.clone()),
                                 payment_method_id: None,
+                                mandate_metadata: None,
                             }
                         }),
                         connector_metadata: None,
diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs
index df0b63833d9..a9451f6156a 100644
--- a/crates/hyperswitch_domain_models/src/router_data.rs
+++ b/crates/hyperswitch_domain_models/src/router_data.rs
@@ -242,6 +242,7 @@ pub struct RecurringMandatePaymentData {
     pub payment_method_type: Option<common_enums::enums::PaymentMethodType>, //required for making recurring payment using saved payment method through stripe
     pub original_payment_authorized_amount: Option<i64>,
     pub original_payment_authorized_currency: Option<common_enums::enums::Currency>,
+    pub mandate_metadata: Option<serde_json::Value>,
 }
 
 #[derive(Debug, Clone)]
diff --git a/crates/hyperswitch_domain_models/src/router_response_types.rs b/crates/hyperswitch_domain_models/src/router_response_types.rs
index cb682514c83..79a78efb538 100644
--- a/crates/hyperswitch_domain_models/src/router_response_types.rs
+++ b/crates/hyperswitch_domain_models/src/router_response_types.rs
@@ -82,6 +82,7 @@ pub struct TaxCalculationResponseData {
 pub struct MandateReference {
     pub connector_mandate_id: Option<String>,
     pub payment_method_id: Option<String>,
+    pub mandate_metadata: Option<serde_json::Value>,
 }
 
 #[derive(Debug, Clone)]
diff --git a/crates/hyperswitch_interfaces/src/errors.rs b/crates/hyperswitch_interfaces/src/errors.rs
index e36707af6b0..06f197ebf0b 100644
--- a/crates/hyperswitch_interfaces/src/errors.rs
+++ b/crates/hyperswitch_interfaces/src/errors.rs
@@ -56,6 +56,8 @@ pub enum ConnectorError {
     CaptureMethodNotSupported,
     #[error("Missing connector mandate ID")]
     MissingConnectorMandateID,
+    #[error("Missing connector mandate metadata")]
+    MissingConnectorMandateMetadata,
     #[error("Missing connector transaction ID")]
     MissingConnectorTransactionID,
     #[error("Missing connector refund ID")]
diff --git a/crates/router/src/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs
index 5842143ad44..46f312b38f2 100644
--- a/crates/router/src/connector/aci/transformers.rs
+++ b/crates/router/src/connector/aci/transformers.rs
@@ -746,6 +746,7 @@ impl<F, T>
             .map(|id| types::MandateReference {
                 connector_mandate_id: Some(id.expose()),
                 payment_method_id: None,
+                mandate_metadata: None,
             });
 
         Ok(Self {
diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs
index e915d05c358..361ebece299 100644
--- a/crates/router/src/connector/adyen/transformers.rs
+++ b/crates/router/src/connector/adyen/transformers.rs
@@ -3294,6 +3294,7 @@ pub fn get_adyen_response(
         .map(|mandate_id| types::MandateReference {
             connector_mandate_id: Some(mandate_id.expose()),
             payment_method_id: None,
+            mandate_metadata: None,
         });
     let network_txn_id = response.additional_data.and_then(|additional_data| {
         additional_data
diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs
index 57563c276f5..868409dafc7 100644
--- a/crates/router/src/connector/authorizedotnet/transformers.rs
+++ b/crates/router/src/connector/authorizedotnet/transformers.rs
@@ -398,6 +398,7 @@ impl<F, T>
                                     format!("{customer_profile_id}-{payment_profile_id}")
                                 }),
                             payment_method_id: None,
+                            mandate_metadata: None,
                         },
                     ),
                     connector_metadata: None,
@@ -1109,6 +1110,7 @@ impl<F, T>
                             },
                         ),
                         payment_method_id: None,
+                        mandate_metadata: None,
                     }
                 });
 
diff --git a/crates/router/src/connector/bamboraapac/transformers.rs b/crates/router/src/connector/bamboraapac/transformers.rs
index 3c197699309..819c918338e 100644
--- a/crates/router/src/connector/bamboraapac/transformers.rs
+++ b/crates/router/src/connector/bamboraapac/transformers.rs
@@ -280,6 +280,7 @@ impl<F>
                 Some(types::MandateReference {
                     connector_mandate_id,
                     payment_method_id: None,
+                    mandate_metadata: None,
                 })
             } else {
                 None
@@ -463,6 +464,7 @@ impl<F>
                     mandate_reference: Some(types::MandateReference {
                         connector_mandate_id: Some(connector_mandate_id),
                         payment_method_id: None,
+                        mandate_metadata: None,
                     }),
                     connector_metadata: None,
                     network_txn_id: None,
diff --git a/crates/router/src/connector/bankofamerica/transformers.rs b/crates/router/src/connector/bankofamerica/transformers.rs
index 46a522c7378..f47ab4139e8 100644
--- a/crates/router/src/connector/bankofamerica/transformers.rs
+++ b/crates/router/src/connector/bankofamerica/transformers.rs
@@ -359,6 +359,7 @@ impl<F, T>
                             .payment_instrument
                             .map(|payment_instrument| payment_instrument.id.expose()),
                         payment_method_id: None,
+                        mandate_metadata: None,
                     }
                 });
                 let mut mandate_status =
@@ -1487,6 +1488,7 @@ fn get_payment_response(
                             .payment_instrument
                             .map(|payment_instrument| payment_instrument.id.expose()),
                         payment_method_id: None,
+                        mandate_metadata: None,
                     });
 
             Ok(types::PaymentsResponseData::TransactionResponse {
diff --git a/crates/router/src/connector/braintree/transformers.rs b/crates/router/src/connector/braintree/transformers.rs
index 22982ceb213..05d8c1c559d 100644
--- a/crates/router/src/connector/braintree/transformers.rs
+++ b/crates/router/src/connector/braintree/transformers.rs
@@ -443,6 +443,7 @@ impl<F>
                             MandateReference {
                                 connector_mandate_id: Some(pm.id.clone().expose()),
                                 payment_method_id: None,
+                                mandate_metadata: None,
                             }
                         }),
                         connector_metadata: None,
@@ -617,6 +618,7 @@ impl<F>
                             MandateReference {
                                 connector_mandate_id: Some(pm.id.clone().expose()),
                                 payment_method_id: None,
+                                mandate_metadata: None,
                             }
                         }),
                         connector_metadata: None,
@@ -698,6 +700,7 @@ impl<F>
                             MandateReference {
                                 connector_mandate_id: Some(pm.id.clone().expose()),
                                 payment_method_id: None,
+                                mandate_metadata: None,
                             }
                         }),
                         connector_metadata: None,
@@ -761,6 +764,7 @@ impl<F>
                             MandateReference {
                                 connector_mandate_id: Some(pm.id.clone().expose()),
                                 payment_method_id: None,
+                                mandate_metadata: None,
                             }
                         }),
                         connector_metadata: None,
diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs
index fc35cab773a..9ad4f0604a4 100644
--- a/crates/router/src/connector/cybersource/transformers.rs
+++ b/crates/router/src/connector/cybersource/transformers.rs
@@ -2227,6 +2227,7 @@ fn get_payment_response(
                             .payment_instrument
                             .map(|payment_instrument| payment_instrument.id.expose()),
                         payment_method_id: None,
+                        mandate_metadata: None,
                     });
 
             Ok(types::PaymentsResponseData::TransactionResponse {
@@ -2947,6 +2948,7 @@ impl
                         .payment_instrument
                         .map(|payment_instrument| payment_instrument.id.expose()),
                     payment_method_id: None,
+                    mandate_metadata: None,
                 });
         let mut mandate_status = enums::AttemptStatus::foreign_from((
             item.response
diff --git a/crates/router/src/connector/globalpay/transformers.rs b/crates/router/src/connector/globalpay/transformers.rs
index efc6661b447..19568ae4671 100644
--- a/crates/router/src/connector/globalpay/transformers.rs
+++ b/crates/router/src/connector/globalpay/transformers.rs
@@ -261,6 +261,7 @@ fn get_payment_response(
             .map(|id| types::MandateReference {
                 connector_mandate_id: Some(id.expose()),
                 payment_method_id: None,
+                mandate_metadata: None,
             })
     });
     match status {
diff --git a/crates/router/src/connector/gocardless/transformers.rs b/crates/router/src/connector/gocardless/transformers.rs
index f3250602dbc..ff2f9d95026 100644
--- a/crates/router/src/connector/gocardless/transformers.rs
+++ b/crates/router/src/connector/gocardless/transformers.rs
@@ -512,6 +512,7 @@ impl<F>
         let mandate_reference = Some(MandateReference {
             connector_mandate_id: Some(item.response.mandates.id.clone().expose()),
             payment_method_id: None,
+            mandate_metadata: None,
         });
         Ok(Self {
             response: Ok(types::PaymentsResponseData::TransactionResponse {
@@ -664,6 +665,7 @@ impl<F>
         let mandate_reference = MandateReference {
             connector_mandate_id: Some(item.data.request.get_connector_mandate_id()?),
             payment_method_id: None,
+            mandate_metadata: None,
         };
         Ok(Self {
             status: enums::AttemptStatus::from(item.response.payments.status),
diff --git a/crates/router/src/connector/multisafepay/transformers.rs b/crates/router/src/connector/multisafepay/transformers.rs
index c44cf14ab65..547a38ad849 100644
--- a/crates/router/src/connector/multisafepay/transformers.rs
+++ b/crates/router/src/connector/multisafepay/transformers.rs
@@ -982,6 +982,7 @@ impl<F, T>
                                 .map(|id| types::MandateReference {
                                     connector_mandate_id: Some(id.expose()),
                                     payment_method_id: None,
+                                    mandate_metadata: None,
                                 }),
                             connector_metadata: None,
                             network_txn_id: None,
diff --git a/crates/router/src/connector/nexinets/transformers.rs b/crates/router/src/connector/nexinets/transformers.rs
index 43cb4cecec8..55b2fbe4176 100644
--- a/crates/router/src/connector/nexinets/transformers.rs
+++ b/crates/router/src/connector/nexinets/transformers.rs
@@ -358,6 +358,7 @@ impl<F, T>
             .map(|id| types::MandateReference {
                 connector_mandate_id: Some(id.expose()),
                 payment_method_id: None,
+                mandate_metadata: None,
             });
         Ok(Self {
             status: enums::AttemptStatus::foreign_from((
diff --git a/crates/router/src/connector/noon/transformers.rs b/crates/router/src/connector/noon/transformers.rs
index b7df6829da4..5d987174273 100644
--- a/crates/router/src/connector/noon/transformers.rs
+++ b/crates/router/src/connector/noon/transformers.rs
@@ -574,6 +574,7 @@ impl<F, T>
                 .map(|subscription_data| types::MandateReference {
                     connector_mandate_id: Some(subscription_data.identifier.expose()),
                     payment_method_id: None,
+                    mandate_metadata: None,
                 });
         Ok(Self {
             status,
diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs
index 2547443484e..f280d3a42a2 100644
--- a/crates/router/src/connector/nuvei/transformers.rs
+++ b/crates/router/src/connector/nuvei/transformers.rs
@@ -1602,6 +1602,7 @@ where
                         .map(|id| types::MandateReference {
                             connector_mandate_id: Some(id),
                             payment_method_id: None,
+                            mandate_metadata: None,
                         }),
                     // we don't need to save session token for capture, void flow so ignoring if it is not present
                     connector_metadata: if let Some(token) = response.session_token {
diff --git a/crates/router/src/connector/payeezy/transformers.rs b/crates/router/src/connector/payeezy/transformers.rs
index 0bb10c9845a..8c2ad2ef979 100644
--- a/crates/router/src/connector/payeezy/transformers.rs
+++ b/crates/router/src/connector/payeezy/transformers.rs
@@ -418,6 +418,7 @@ impl<F, T>
             .map(|id| types::MandateReference {
                 connector_mandate_id: Some(id.expose()),
                 payment_method_id: None,
+                mandate_metadata: None,
             });
         let status = enums::AttemptStatus::foreign_from((
             item.response.transaction_status,
diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs
index c12e478b08e..e0ab598d76d 100644
--- a/crates/router/src/connector/payme/transformers.rs
+++ b/crates/router/src/connector/payme/transformers.rs
@@ -250,6 +250,7 @@ impl TryFrom<&PaymePaySaleResponse> for types::PaymentsResponseData {
             mandate_reference: value.buyer_key.clone().map(|buyer_key| MandateReference {
                 connector_mandate_id: Some(buyer_key.expose()),
                 payment_method_id: None,
+                mandate_metadata: None,
             }),
             connector_metadata: None,
             network_txn_id: None,
diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs
index 910cb94e929..2129ad327c2 100644
--- a/crates/router/src/connector/stripe/transformers.rs
+++ b/crates/router/src/connector/stripe/transformers.rs
@@ -2389,6 +2389,7 @@ impl<F, T>
             types::MandateReference {
                 connector_mandate_id,
                 payment_method_id,
+                mandate_metadata: None,
             }
         });
 
@@ -2583,6 +2584,7 @@ impl<F, T>
                 types::MandateReference {
                     connector_mandate_id,
                     payment_method_id: Some(payment_method_id),
+                    mandate_metadata: None,
                 }
             });
 
@@ -2673,6 +2675,7 @@ impl<F, T>
             types::MandateReference {
                 connector_mandate_id,
                 payment_method_id,
+                mandate_metadata: None,
             }
         });
         let status = enums::AttemptStatus::from(item.response.status);
diff --git a/crates/router/src/connector/wellsfargo/transformers.rs b/crates/router/src/connector/wellsfargo/transformers.rs
index 761fc43982b..be3cf4a1cef 100644
--- a/crates/router/src/connector/wellsfargo/transformers.rs
+++ b/crates/router/src/connector/wellsfargo/transformers.rs
@@ -1778,6 +1778,7 @@ fn get_payment_response(
                             .payment_instrument
                             .map(|payment_instrument| payment_instrument.id.expose()),
                         payment_method_id: None,
+                        mandate_metadata: None,
                     });
 
             Ok(types::PaymentsResponseData::TransactionResponse {
@@ -1963,6 +1964,7 @@ impl
                         .payment_instrument
                         .map(|payment_instrument| payment_instrument.id.expose()),
                     payment_method_id: None,
+                    mandate_metadata: None,
                 });
         let mut mandate_status = enums::AttemptStatus::foreign_from((
             item.response
diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs
index d2812447ed8..549857494f0 100644
--- a/crates/router/src/core/errors/utils.rs
+++ b/crates/router/src/core/errors/utils.rs
@@ -189,6 +189,7 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
             | errors::ConnectorError::FlowNotSupported { .. }
             | errors::ConnectorError::CaptureMethodNotSupported
             | errors::ConnectorError::MissingConnectorMandateID
+            | errors::ConnectorError::MissingConnectorMandateMetadata
             | errors::ConnectorError::MissingConnectorTransactionID
             | errors::ConnectorError::MissingConnectorRefundID
             | errors::ConnectorError::MissingApplePayTokenData
@@ -288,6 +289,7 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
                 errors::ConnectorError::FailedToObtainCertificateKey |
                 errors::ConnectorError::CaptureMethodNotSupported |
                 errors::ConnectorError::MissingConnectorMandateID |
+                errors::ConnectorError::MissingConnectorMandateMetadata |
                 errors::ConnectorError::MissingConnectorTransactionID |
                 errors::ConnectorError::MissingConnectorRefundID |
                 errors::ConnectorError::MissingApplePayTokenData |
@@ -376,6 +378,7 @@ impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError>
                 | errors::ConnectorError::FlowNotSupported { .. }
                 | errors::ConnectorError::CaptureMethodNotSupported
                 | errors::ConnectorError::MissingConnectorMandateID
+                | errors::ConnectorError::MissingConnectorMandateMetadata
                 | errors::ConnectorError::MissingConnectorTransactionID
                 | errors::ConnectorError::MissingConnectorRefundID
                 | errors::ConnectorError::MissingApplePayTokenData
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 85ae8641373..3a55bf77771 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -4093,6 +4093,9 @@ where
                                             payment_method_info.get_id().clone(),
                                         ),
                                         update_history: None,
+                                        mandate_metadata: mandate_reference_record
+                                            .mandate_metadata
+                                            .clone(),
                                     },
                                 ));
                             payment_data.set_recurring_mandate_payment_data(
@@ -4103,6 +4106,8 @@ where
                                         .original_payment_authorized_amount,
                                     original_payment_authorized_currency: mandate_reference_record
                                         .original_payment_authorized_currency,
+                                    mandate_metadata: mandate_reference_record
+                                        .mandate_metadata.clone(),
                                 });
 
                             connector_choice = Some((connector_data, mandate_reference_id.clone()));
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index e9dca13dc80..ac6c236f536 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -802,6 +802,7 @@ pub async fn get_token_for_recurring_mandate(
                 payment_method_type,
                 original_payment_authorized_amount,
                 original_payment_authorized_currency,
+                mandate_metadata: None,
             }),
             payment_method_type: payment_method.payment_method_type,
             mandate_connector: Some(mandate_connector_details),
@@ -816,6 +817,7 @@ pub async fn get_token_for_recurring_mandate(
                 payment_method_type,
                 original_payment_authorized_amount,
                 original_payment_authorized_currency,
+                mandate_metadata: None,
             }),
             payment_method_type: payment_method.payment_method_type,
             mandate_connector: Some(mandate_connector_details),
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index c75cc29ce51..658a02f7d08 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -681,6 +681,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
                                     ),
                                     payment_method_id: None,
                                     update_history: None,
+                                    mandate_metadata: None,
                                 },
                             ),
                         ),
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index 0731def9453..4b931d68f1e 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -398,7 +398,8 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
                                 api_models::payments::ConnectorMandateReferenceId{
                                     connector_mandate_id: connector_id.connector_mandate_id,
                                     payment_method_id: connector_id.payment_method_id,
-                                    update_history: None
+                                    update_history: None,
+                                    mandate_metadata: None,
                                 }
                                 ))
                             }
@@ -437,6 +438,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
                                         ),
                                         payment_method_id: None,
                                         update_history: None,
+                                        mandate_metadata: None,
                                     },
                                 ),
                             ),
diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs
index 90ca49c9746..09292224cae 100644
--- a/crates/router/src/core/payments/operations/payment_response.rs
+++ b/crates/router/src/core/payments/operations/payment_response.rs
@@ -1504,21 +1504,24 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
 
     let flow_name = core_utils::get_flow_name::<F>()?;
     if flow_name == "PSync" || flow_name == "CompleteAuthorize" {
-        let connector_mandate_id = match router_data.response.clone() {
+        let (connector_mandate_id, mandate_metadata) = match router_data.response.clone() {
             Ok(resp) => match resp {
                 types::PaymentsResponseData::TransactionResponse {
                     ref mandate_reference,
                     ..
                 } => {
                     if let Some(mandate_ref) = mandate_reference {
-                        mandate_ref.connector_mandate_id.clone()
+                        (
+                            mandate_ref.connector_mandate_id.clone(),
+                            mandate_ref.mandate_metadata.clone(),
+                        )
                     } else {
-                        None
+                        (None, None)
                     }
                 }
-                _ => None,
+                _ => (None, None),
             },
-            Err(_) => None,
+            Err(_) => (None, None),
         };
         if let Some(payment_method) = payment_data.payment_method_info.clone() {
             let connector_mandate_details =
@@ -1529,6 +1532,7 @@ async fn payment_response_update_tracker<F: Clone, T: types::Capturable>(
                     payment_data.payment_attempt.currency,
                     payment_data.payment_attempt.merchant_connector_id.clone(),
                     connector_mandate_id,
+                    mandate_metadata,
                 )?;
             payment_methods::cards::update_payment_method_connector_mandate_details(
                 state,
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index c5e7cebac34..c69595d1893 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -329,7 +329,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
                             api_models::payments::MandateIds {
                                 mandate_id: Some(mandate_obj.mandate_id),
                                 mandate_reference_id: Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
-                                    api_models::payments::ConnectorMandateReferenceId {connector_mandate_id:connector_id.connector_mandate_id,payment_method_id:connector_id.payment_method_id, update_history: None },
+                                    api_models::payments::ConnectorMandateReferenceId {connector_mandate_id:connector_id.connector_mandate_id,payment_method_id:connector_id.payment_method_id, update_history: None, mandate_metadata:connector_id.mandate_metadata, },
                                 ))
                             }
                          }),
diff --git a/crates/router/src/core/payments/tokenization.rs b/crates/router/src/core/payments/tokenization.rs
index 2d81aecb30e..ca8c6718aa7 100644
--- a/crates/router/src/core/payments/tokenization.rs
+++ b/crates/router/src/core/payments/tokenization.rs
@@ -148,18 +148,21 @@ where
                 .change_context(errors::ApiErrorResponse::InternalServerError)
                 .attach_printable("Unable to serialize customer acceptance to value")?;
 
-            let connector_mandate_id = match responses {
+            let (connector_mandate_id, mandate_metadata) = match responses {
                 types::PaymentsResponseData::TransactionResponse {
                     ref mandate_reference,
                     ..
                 } => {
                     if let Some(mandate_ref) = mandate_reference {
-                        mandate_ref.connector_mandate_id.clone()
+                        (
+                            mandate_ref.connector_mandate_id.clone(),
+                            mandate_ref.mandate_metadata.clone(),
+                        )
                     } else {
-                        None
+                        (None, None)
                     }
                 }
-                _ => None,
+                _ => (None, None),
             };
             let check_for_mit_mandates = save_payment_method_data
                 .request
@@ -178,6 +181,7 @@ where
                     currency,
                     merchant_connector_id.clone(),
                     connector_mandate_id.clone(),
+                    mandate_metadata.clone(),
                 )
             } else {
                 None
@@ -373,6 +377,7 @@ where
                                                 currency,
                                                 merchant_connector_id.clone(),
                                                 connector_mandate_id.clone(),
+                                                mandate_metadata.clone(),
                                             )?;
 
                                         payment_methods::cards::update_payment_method_connector_mandate_details(state,
@@ -479,6 +484,7 @@ where
                                                     currency,
                                                     merchant_connector_id.clone(),
                                                     connector_mandate_id.clone(),
+                                                    mandate_metadata.clone(),
                                                 )?;
 
                                             payment_methods::cards::update_payment_method_connector_mandate_details(  state,
@@ -1160,6 +1166,7 @@ pub fn add_connector_mandate_details_in_payment_method(
     authorized_currency: Option<storage_enums::Currency>,
     merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
     connector_mandate_id: Option<String>,
+    mandate_metadata: Option<serde_json::Value>,
 ) -> Option<storage::PaymentsMandateReference> {
     let mut mandate_details = HashMap::new();
 
@@ -1173,6 +1180,7 @@ pub fn add_connector_mandate_details_in_payment_method(
                 payment_method_type,
                 original_payment_authorized_amount: authorized_amount,
                 original_payment_authorized_currency: authorized_currency,
+                mandate_metadata,
             },
         );
         Some(storage::PaymentsMandateReference(mandate_details))
@@ -1188,6 +1196,7 @@ pub fn update_connector_mandate_details_in_payment_method(
     authorized_currency: Option<storage_enums::Currency>,
     merchant_connector_id: Option<id_type::MerchantConnectorAccountId>,
     connector_mandate_id: Option<String>,
+    mandate_metadata: Option<serde_json::Value>,
 ) -> RouterResult<Option<serde_json::Value>> {
     let mandate_reference = match payment_method.connector_mandate_details {
         Some(_) => {
@@ -1208,6 +1217,7 @@ pub fn update_connector_mandate_details_in_payment_method(
                     payment_method_type,
                     original_payment_authorized_amount: authorized_amount,
                     original_payment_authorized_currency: authorized_currency,
+                    mandate_metadata: mandate_metadata.clone(),
                 };
                 mandate_details.map(|mut payment_mandate_reference| {
                     payment_mandate_reference
@@ -1218,6 +1228,7 @@ pub fn update_connector_mandate_details_in_payment_method(
                             payment_method_type,
                             original_payment_authorized_amount: authorized_amount,
                             original_payment_authorized_currency: authorized_currency,
+                            mandate_metadata: mandate_metadata.clone(),
                         });
                     payment_mandate_reference
                 })
@@ -1231,6 +1242,7 @@ pub fn update_connector_mandate_details_in_payment_method(
             authorized_currency,
             merchant_connector_id,
             connector_mandate_id,
+            mandate_metadata,
         ),
     };
     let connector_mandate_details = mandate_reference
diff --git a/crates/router/src/types/storage/payment_method.rs b/crates/router/src/types/storage/payment_method.rs
index 34c5714e126..bb1b801edb6 100644
--- a/crates/router/src/types/storage/payment_method.rs
+++ b/crates/router/src/types/storage/payment_method.rs
@@ -124,6 +124,7 @@ pub struct PaymentsMandateReferenceRecord {
     pub payment_method_type: Option<common_enums::PaymentMethodType>,
     pub original_payment_authorized_amount: Option<i64>,
     pub original_payment_authorized_currency: Option<common_enums::Currency>,
+    pub mandate_metadata: Option<serde_json::Value>,
 }
 
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]

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

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

## Description
<!-- Describe your changes in detail -->
Implement SEPA mandate payments for Deutschebank.
These mandate details will be stored in the payment_methods table in the connector_mandate_details.


### 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).
-->
https://github.com/juspay/hyperswitch/issues/5924

## 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.  Payments Intent Create:

Request:
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_2QpEeK0ByPRkb2DPBxHfad4i1WxQO3hZSuVzlFcg9mTrLFUHRpGfE0SCuQwZjGEb' \
--data '{
    "amount": 1650,
    "currency": "EUR",
    "confirm": false,
    "customer_id": "customer123",
    "setup_future_usage": "off_session"
}'
```

Response:
```
{
    "payment_id": "pay_u8nPxFlL3ZUW94kkzrI1",
    "merchant_id": "merchant_1725539597",
    "status": "requires_payment_method",
    "amount": 1650,
    "net_amount": 1650,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "pay_u8nPxFlL3ZUW94kkzrI1_secret_npQbKdQHon2g7tthKxeB",
    "created": "2024-09-17T12:59:17.770Z",
    "currency": "EUR",
    "customer_id": "customer123",
    "customer": {
        "id": "customer123",
        "name": "John Doe",
        "email": "something@example.com",
        "phone": "9999999999",
        "phone_country_code": "+1"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": null,
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "something@example.com",
    "name": "John Doe",
    "phone": "9999999999",
    "return_url": null,
    "authentication_type": null,
    "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": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "customer123",
        "created_at": 1726577957,
        "expires": 1726581557,
        "secret": "epk_46a85e0e97b645a1bb2f838483b3bf70"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_EuXuxP2KVO0m1tlDWSau",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-17T13:14:17.769Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-09-17T12:59:17.902Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null
}
```

2. Payments Confirm:

Request:
```
curl --location 'http://localhost:8080/payments/pay_u8nPxFlL3ZUW94kkzrI1/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_2QpEeK0ByPRkb2DPBxHfad4i1WxQO3hZSuVzlFcg9mTrLFUHRpGfE0SCuQwZjGEb' \
--data-raw '{
    "profile_id": "pro_EuXuxP2KVO0m1tlDWSau",
    "customer_id": "customer123",
    "payment_method": "bank_debit",
    "payment_method_type": "sepa",
    "payment_method_data": {
        "bank_debit": {
            "sepa_bank_debit": {
                "iban": "DE87123456781234567890"
            }
        }
    },
    "billing": {
        "address": {
            "first_name": "joseph",
            "last_name": "Doe"
        }
    },
    "email": "something@example.com",
    "customer_acceptance": {
        "acceptance_type": "offline"
    }
}'
```

Response:
```
{
    "payment_id": "pay_u8nPxFlL3ZUW94kkzrI1",
    "merchant_id": "merchant_1725539597",
    "status": "requires_customer_action",
    "amount": 1650,
    "net_amount": 1650,
    "amount_capturable": 1650,
    "amount_received": null,
    "connector": "deutschebank",
    "client_secret": "pay_u8nPxFlL3ZUW94kkzrI1_secret_npQbKdQHon2g7tthKxeB",
    "created": "2024-09-17T12:59:17.770Z",
    "currency": "EUR",
    "customer_id": "customer123",
    "customer": {
        "id": "customer123",
        "name": "John Doe",
        "email": "something@example.com",
        "phone": "9999999999",
        "phone_country_code": "+1"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": null,
    "payment_method": "bank_debit",
    "payment_method_data": {
        "bank_debit": {
            "sepa": {
                "iban": "DE871************67890",
                "bank_account_holder_name": null
            }
        },
        "billing": null
    },
    "payment_token": "token_K3jaclrwRSo2guy2kfn1",
    "shipping": null,
    "billing": {
        "address": {
            "city": null,
            "country": null,
            "line1": null,
            "line2": null,
            "line3": null,
            "zip": null,
            "state": null,
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": "something@example.com",
    "name": "John Doe",
    "phone": "9999999999",
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": {
        "type": "redirect_to_url",
        "redirect_to_url": "http://localhost:8080/payments/redirect/pay_u8nPxFlL3ZUW94kkzrI1/merchant_1725539597/pay_u8nPxFlL3ZUW94kkzrI1_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": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_EuXuxP2KVO0m1tlDWSau",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_MZAsrTowXuzpeXl4DMj2",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-17T13:14:17.769Z",
    "fingerprint": null,
    "browser_info": {
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "user_agent": null,
        "color_depth": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "java_script_enabled": null
    },
    "payment_method_id": "pm_8qqABCQOMAznGanjmLhz",
    "payment_method_status": null,
    "updated": "2024-09-17T12:59:36.782Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null
}
```

3. Creating payment using payment_method_id:
Request:
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_2QpEeK0ByPRkb2DPBxHfad4i1WxQO3hZSuVzlFcg9mTrLFUHRpGfE0SCuQwZjGEb' \
--data '{
    "amount": 179,
    "currency": "EUR",
    "confirm": true,
    "customer_id": "customer123",
    "recurring_details": {
        "type": "payment_method_id",
        "data": "pm_8qqABCQOMAznGanjmLhz"
    },
    "off_session": true
}'
```

Response:
```
{
    "payment_id": "pay_zeindrGrgMlzJscKZdAC",
    "merchant_id": "merchant_1725539597",
    "status": "succeeded",
    "amount": 179,
    "net_amount": 179,
    "amount_capturable": 0,
    "amount_received": 179,
    "connector": "deutschebank",
    "client_secret": "pay_zeindrGrgMlzJscKZdAC_secret_W4q8bNJWw2yH7MVaC70L",
    "created": "2024-09-17T13:24:07.080Z",
    "currency": "EUR",
    "customer_id": "customer123",
    "customer": {
        "id": "customer123",
        "name": "John Doe",
        "email": "something@example.com",
        "phone": "9999999999",
        "phone_country_code": "+1"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": true,
    "capture_on": null,
    "capture_method": null,
    "payment_method": "bank_debit",
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "something@example.com",
    "name": "John Doe",
    "phone": "9999999999",
    "return_url": null,
    "authentication_type": "no_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": "sepa",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "customer123",
        "created_at": 1726579447,
        "expires": 1726583047,
        "secret": "epk_d80c49dcbeb1431cadf357b9c6d64ad9"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "nz17xcQ3x7q7kecPExgV0s",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_EuXuxP2KVO0m1tlDWSau",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_MZAsrTowXuzpeXl4DMj2",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-17T13:39:07.079Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": "pm_8qqABCQOMAznGanjmLhz",
    "payment_method_status": "active",
    "updated": "2024-09-17T13:24:08.282Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": 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


1.  Payments Intent Create:

Request:
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_2QpEeK0ByPRkb2DPBxHfad4i1WxQO3hZSuVzlFcg9mTrLFUHRpGfE0SCuQwZjGEb' \
--data '{
    "amount": 1650,
    "currency": "EUR",
    "confirm": false,
    "customer_id": "customer123",
    "setup_future_usage": "off_session"
}'
```

Response:
```
{
    "payment_id": "pay_u8nPxFlL3ZUW94kkzrI1",
    "merchant_id": "merchant_1725539597",
    "status": "requires_payment_method",
    "amount": 1650,
    "net_amount": 1650,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "pay_u8nPxFlL3ZUW94kkzrI1_secret_npQbKdQHon2g7tthKxeB",
    "created": "2024-09-17T12:59:17.770Z",
    "currency": "EUR",
    "customer_id": "customer123",
    "customer": {
        "id": "customer123",
        "name": "John Doe",
        "email": "something@example.com",
        "phone": "9999999999",
        "phone_country_code": "+1"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": null,
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "something@example.com",
    "name": "John Doe",
    "phone": "9999999999",
    "return_url": null,
    "authentication_type": null,
    "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": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "customer123",
        "created_at": 1726577957,
        "expires": 1726581557,
        "secret": "epk_46a85e0e97b645a1bb2f838483b3bf70"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_EuXuxP2KVO0m1tlDWSau",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-17T13:14:17.769Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-09-17T12:59:17.902Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null
}
```

2. Payments Confirm:

Request:
```
curl --location 'http://localhost:8080/payments/pay_u8nPxFlL3ZUW94kkzrI1/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_2QpEeK0ByPRkb2DPBxHfad4i1WxQO3hZSuVzlFcg9mTrLFUHRpGfE0SCuQwZjGEb' \
--data-raw '{
    "profile_id": "pro_EuXuxP2KVO0m1tlDWSau",
    "customer_id": "customer123",
    "payment_method": "bank_debit",
    "payment_method_type": "sepa",
    "payment_method_data": {
        "bank_debit": {
            "sepa_bank_debit": {
                "iban": "DE87123456781234567890"
            }
        }
    },
    "billing": {
        "address": {
            "first_name": "joseph",
            "last_name": "Doe"
        }
    },
    "email": "something@example.com",
    "customer_acceptance": {
        "acceptance_type": "offline"
    }
}'
```

Response:
```
{
    "payment_id": "pay_u8nPxFlL3ZUW94kkzrI1",
    "merchant_id": "merchant_1725539597",
    "status": "requires_customer_action",
    "amount": 1650,
    "net_amount": 1650,
    "amount_capturable": 1650,
    "amount_received": null,
    "connector": "deutschebank",
    "client_secret": "pay_u8nPxFlL3ZUW94kkzrI1_secret_npQbKdQHon2g7tthKxeB",
    "created": "2024-09-17T12:59:17.770Z",
    "currency": "EUR",
    "customer_id": "customer123",
    "customer": {
        "id": "customer123",
        "name": "John Doe",
        "email": "something@example.com",
        "phone": "9999999999",
        "phone_country_code": "+1"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": null,
    "payment_method": "bank_debit",
    "payment_method_data": {
        "bank_debit": {
            "sepa": {
                "iban": "DE871************67890",
                "bank_account_holder_name": null
            }
        },
        "billing": null
    },
    "payment_token": "token_K3jaclrwRSo2guy2kfn1",
    "shipping": null,
    "billing": {
        "address": {
            "city": null,
            "country": null,
            "line1": null,
            "line2": null,
            "line3": null,
            "zip": null,
            "state": null,
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": "something@example.com",
    "name": "John Doe",
    "phone": "9999999999",
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": {
        "type": "redirect_to_url",
        "redirect_to_url": "http://localhost:8080/payments/redirect/pay_u8nPxFlL3ZUW94kkzrI1/merchant_1725539597/pay_u8nPxFlL3ZUW94kkzrI1_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": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_EuXuxP2KVO0m1tlDWSau",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_MZAsrTowXuzpeXl4DMj2",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-17T13:14:17.769Z",
    "fingerprint": null,
    "browser_info": {
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "user_agent": null,
        "color_depth": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "java_script_enabled": null
    },
    "payment_method_id": "pm_8qqABCQOMAznGanjmLhz",
    "payment_method_status": null,
    "updated": "2024-09-17T12:59:36.782Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null
}
```

3. Creating payment using payment_method_id:
Request:
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_2QpEeK0ByPRkb2DPBxHfad4i1WxQO3hZSuVzlFcg9mTrLFUHRpGfE0SCuQwZjGEb' \
--data '{
    "amount": 179,
    "currency": "EUR",
    "confirm": true,
    "customer_id": "customer123",
    "recurring_details": {
        "type": "payment_method_id",
        "data": "pm_8qqABCQOMAznGanjmLhz"
    },
    "off_session": true
}'
```

Response:
```
{
    "payment_id": "pay_zeindrGrgMlzJscKZdAC",
    "merchant_id": "merchant_1725539597",
    "status": "succeeded",
    "amount": 179,
    "net_amount": 179,
    "amount_capturable": 0,
    "amount_received": 179,
    "connector": "deutschebank",
    "client_secret": "pay_zeindrGrgMlzJscKZdAC_secret_W4q8bNJWw2yH7MVaC70L",
    "created": "2024-09-17T13:24:07.080Z",
    "currency": "EUR",
    "customer_id": "customer123",
    "customer": {
        "id": "customer123",
        "name": "John Doe",
        "email": "something@example.com",
        "phone": "9999999999",
        "phone_country_code": "+1"
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": true,
    "capture_on": null,
    "capture_method": null,
    "payment_method": "bank_debit",
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "something@example.com",
    "name": "John Doe",
    "phone": "9999999999",
    "return_url": null,
    "authentication_type": "no_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": "sepa",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "customer123",
        "created_at": 1726579447,
        "expires": 1726583047,
        "secret": "epk_d80c49dcbeb1431cadf357b9c6d64ad9"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "nz17xcQ3x7q7kecPExgV0s",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_EuXuxP2KVO0m1tlDWSau",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_MZAsrTowXuzpeXl4DMj2",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-09-17T13:39:07.079Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": "pm_8qqABCQOMAznGanjmLhz",
    "payment_method_status": "active",
    "updated": "2024-09-17T13:24:08.282Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null
}
```
