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
