Bug: [FEATURE] Hyperswitch <|> UCS Mandate flow integration



Add UCS integration for SetupMandate and RepeatPayment (recurring) flows.
diff --git a/Cargo.lock b/Cargo.lock
index f65a0fd4be0..d835074cfe2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3363,8 +3363,7 @@ dependencies = [
 [[package]]
 name = "g2h"
 version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0aece561ff748cdd2a37c8ee938a47bbf9b2c03823b393a332110599b14ee827"
+source = "git+https://github.com/NishantJoshi00/g2h?branch=fixing-response-serializing#fd2c856b2c6c88a85d6fe51d95b4d3342b788d31"
 dependencies = [
  "cargo_metadata 0.19.2",
  "heck 0.5.0",
@@ -3526,7 +3525,7 @@ dependencies = [
 [[package]]
 name = "grpc-api-types"
 version = "0.1.0"
-source = "git+https://github.com/juspay/connector-service?rev=4918efedd5ea6c33e4a1600b988b2cf4948bed10#4918efedd5ea6c33e4a1600b988b2cf4948bed10"
+source = "git+https://github.com/juspay/connector-service?rev=a9f7cd96693fa034ea69d8e21125ea0f76182fae#a9f7cd96693fa034ea69d8e21125ea0f76182fae"
 dependencies = [
  "axum 0.8.4",
  "error-stack 0.5.0",
@@ -6900,7 +6899,7 @@ dependencies = [
 [[package]]
 name = "rust-grpc-client"
 version = "0.1.0"
-source = "git+https://github.com/juspay/connector-service?rev=4918efedd5ea6c33e4a1600b988b2cf4948bed10#4918efedd5ea6c33e4a1600b988b2cf4948bed10"
+source = "git+https://github.com/juspay/connector-service?rev=a9f7cd96693fa034ea69d8e21125ea0f76182fae#a9f7cd96693fa034ea69d8e21125ea0f76182fae"
 dependencies = [
  "grpc-api-types",
 ]
diff --git a/crates/external_services/Cargo.toml b/crates/external_services/Cargo.toml
index 30ee8ee5a2c..d7fa5897526 100644
--- a/crates/external_services/Cargo.toml
+++ b/crates/external_services/Cargo.toml
@@ -53,7 +53,7 @@ reqwest = { version = "0.11.27", features = ["rustls-tls"] }
 http = "0.2.12"
 url = { version = "2.5.4", features = ["serde"] }
 quick-xml = { version = "0.31.0", features = ["serialize"] }
-unified-connector-service-client = { git = "https://github.com/juspay/connector-service", rev = "4918efedd5ea6c33e4a1600b988b2cf4948bed10", package = "rust-grpc-client" }
+unified-connector-service-client = { git = "https://github.com/juspay/connector-service", rev = "a9f7cd96693fa034ea69d8e21125ea0f76182fae", package = "rust-grpc-client" }
 
 
 # First party crates
diff --git a/crates/external_services/src/grpc_client/unified_connector_service.rs b/crates/external_services/src/grpc_client/unified_connector_service.rs
index 5a4a912b798..bac66a3bb50 100644
--- a/crates/external_services/src/grpc_client/unified_connector_service.rs
+++ b/crates/external_services/src/grpc_client/unified_connector_service.rs
@@ -88,6 +88,14 @@ pub enum UnifiedConnectorServiceError {
     /// Failed to perform Payment Get from gRPC Server
     #[error("Failed to perform Payment Get from gRPC Server")]
     PaymentGetFailure,
+
+    /// Failed to perform Payment Setup Mandate from gRPC Server
+    #[error("Failed to perform Setup Mandate from gRPC Server")]
+    PaymentRegisterFailure,
+
+    /// Failed to perform Payment Repeat Payment from gRPC Server
+    #[error("Failed to perform Repeat Payment from gRPC Server")]
+    PaymentRepeatEverythingFailure,
 }
 
 /// Result type for Dynamic Routing
@@ -160,7 +168,10 @@ impl UnifiedConnectorServiceClient {
                 .await;
 
                 match connect_result {
-                    Ok(Ok(client)) => Some(Self { client }),
+                    Ok(Ok(client)) => {
+                        logger::info!("Successfully connected to Unified Connector Service");
+                        Some(Self { client })
+                    }
                     Ok(Err(err)) => {
                         logger::error!(error = ?err, "Failed to connect to Unified Connector Service");
                         None
@@ -217,6 +228,51 @@ impl UnifiedConnectorServiceClient {
             .change_context(UnifiedConnectorServiceError::PaymentGetFailure)
             .inspect_err(|error| logger::error!(?error))
     }
+
+    /// Performs Payment Setup Mandate
+    pub async fn payment_setup_mandate(
+        &self,
+        payment_register_request: payments_grpc::PaymentServiceRegisterRequest,
+        connector_auth_metadata: ConnectorAuthMetadata,
+        grpc_headers: GrpcHeaders,
+    ) -> UnifiedConnectorServiceResult<tonic::Response<payments_grpc::PaymentServiceRegisterResponse>>
+    {
+        let mut request = tonic::Request::new(payment_register_request);
+
+        let metadata =
+            build_unified_connector_service_grpc_headers(connector_auth_metadata, grpc_headers)?;
+        *request.metadata_mut() = metadata;
+
+        self.client
+            .clone()
+            .register(request)
+            .await
+            .change_context(UnifiedConnectorServiceError::PaymentRegisterFailure)
+            .inspect_err(|error| logger::error!(?error))
+    }
+
+    /// Performs Payment repeat (MIT - Merchant Initiated Transaction).
+    pub async fn payment_repeat(
+        &self,
+        payment_repeat_request: payments_grpc::PaymentServiceRepeatEverythingRequest,
+        connector_auth_metadata: ConnectorAuthMetadata,
+        grpc_headers: GrpcHeaders,
+    ) -> UnifiedConnectorServiceResult<
+        tonic::Response<payments_grpc::PaymentServiceRepeatEverythingResponse>,
+    > {
+        let mut request = tonic::Request::new(payment_repeat_request);
+
+        let metadata =
+            build_unified_connector_service_grpc_headers(connector_auth_metadata, grpc_headers)?;
+        *request.metadata_mut() = metadata;
+
+        self.client
+            .clone()
+            .repeat_everything(request)
+            .await
+            .change_context(UnifiedConnectorServiceError::PaymentRepeatEverythingFailure)
+            .inspect_err(|error| logger::error!(?error))
+    }
 }
 
 /// Build the gRPC Headers for Unified Connector Service Request
diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml
index 8b80d22dc2a..9399c0d3b3a 100644
--- a/crates/router/Cargo.toml
+++ b/crates/router/Cargo.toml
@@ -88,7 +88,7 @@ reqwest = { version = "0.11.27", features = ["json", "rustls-tls", "gzip", "mult
 ring = "0.17.14"
 rust_decimal = { version = "1.37.1", features = ["serde-with-float", "serde-with-str"] }
 rust-i18n = { git = "https://github.com/kashif-m/rust-i18n", rev = "f2d8096aaaff7a87a847c35a5394c269f75e077a" }
-unified-connector-service-client = { git = "https://github.com/juspay/connector-service", rev = "4918efedd5ea6c33e4a1600b988b2cf4948bed10", package = "rust-grpc-client" }
+unified-connector-service-client = { git = "https://github.com/juspay/connector-service", rev = "a9f7cd96693fa034ea69d8e21125ea0f76182fae", package = "rust-grpc-client" }
 rustc-hash = "1.1.0"
 rustls = "0.22"
 rustls-pemfile = "2"
diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs
index 21215ea7235..e077362cc1f 100644
--- a/crates/router/src/core/payments/flows/authorize_flow.rs
+++ b/crates/router/src/core/payments/flows/authorize_flow.rs
@@ -20,6 +20,7 @@ use crate::{
         unified_connector_service::{
             build_unified_connector_service_auth_metadata,
             handle_unified_connector_service_response_for_payment_authorize,
+            handle_unified_connector_service_response_for_payment_repeat,
         },
     },
     logger,
@@ -515,51 +516,23 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
         merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
         merchant_context: &domain::MerchantContext,
     ) -> RouterResult<()> {
-        let client = state
-            .grpc_client
-            .unified_connector_service_client
-            .clone()
-            .ok_or(ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed to fetch Unified Connector Service client")?;
-
-        let payment_authorize_request =
-            payments_grpc::PaymentServiceAuthorizeRequest::foreign_try_from(self)
-                .change_context(ApiErrorResponse::InternalServerError)
-                .attach_printable("Failed to construct Payment Authorize Request")?;
-
-        let connector_auth_metadata = build_unified_connector_service_auth_metadata(
-            merchant_connector_account,
-            merchant_context,
-        )
-        .change_context(ApiErrorResponse::InternalServerError)
-        .attach_printable("Failed to construct request metadata")?;
-
-        let response = client
-            .payment_authorize(
-                payment_authorize_request,
-                connector_auth_metadata,
-                state.get_grpc_headers(),
+        if self.request.mandate_id.is_some() {
+            call_unified_connector_service_repeat_payment(
+                self,
+                state,
+                merchant_connector_account,
+                merchant_context,
             )
             .await
-            .change_context(ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed to authorize payment")?;
-
-        let payment_authorize_response = response.into_inner();
-
-        let (status, router_data_response) =
-            handle_unified_connector_service_response_for_payment_authorize(
-                payment_authorize_response.clone(),
+        } else {
+            call_unified_connector_service_authorize(
+                self,
+                state,
+                merchant_connector_account,
+                merchant_context,
             )
-            .change_context(ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed to deserialize UCS response")?;
-
-        self.status = status;
-        self.response = router_data_response;
-        self.raw_connector_response = payment_authorize_response
-            .raw_connector_response
-            .map(Secret::new);
-
-        Ok(())
+            .await
+        }
     }
 }
 
@@ -846,3 +819,115 @@ async fn process_capture_flow(
     router_data.response = Ok(updated_response);
     Ok(router_data)
 }
+
+async fn call_unified_connector_service_authorize(
+    router_data: &mut types::RouterData<
+        api::Authorize,
+        types::PaymentsAuthorizeData,
+        types::PaymentsResponseData,
+    >,
+    state: &SessionState,
+    #[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
+    #[cfg(feature = "v2")] merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
+    merchant_context: &domain::MerchantContext,
+) -> RouterResult<()> {
+    let client = state
+        .grpc_client
+        .unified_connector_service_client
+        .clone()
+        .ok_or(ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to fetch Unified Connector Service client")?;
+
+    let payment_authorize_request =
+        payments_grpc::PaymentServiceAuthorizeRequest::foreign_try_from(router_data)
+            .change_context(ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to construct Payment Authorize Request")?;
+
+    let connector_auth_metadata =
+        build_unified_connector_service_auth_metadata(merchant_connector_account, merchant_context)
+            .change_context(ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to construct request metadata")?;
+
+    let response = client
+        .payment_authorize(
+            payment_authorize_request,
+            connector_auth_metadata,
+            state.get_grpc_headers(),
+        )
+        .await
+        .change_context(ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to authorize payment")?;
+
+    let payment_authorize_response = response.into_inner();
+
+    let (status, router_data_response) =
+        handle_unified_connector_service_response_for_payment_authorize(
+            payment_authorize_response.clone(),
+        )
+        .change_context(ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to deserialize UCS response")?;
+
+    router_data.status = status;
+    router_data.response = router_data_response;
+    router_data.raw_connector_response = payment_authorize_response
+        .raw_connector_response
+        .map(Secret::new);
+
+    Ok(())
+}
+
+async fn call_unified_connector_service_repeat_payment(
+    router_data: &mut types::RouterData<
+        api::Authorize,
+        types::PaymentsAuthorizeData,
+        types::PaymentsResponseData,
+    >,
+    state: &SessionState,
+    #[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
+    #[cfg(feature = "v2")] merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
+    merchant_context: &domain::MerchantContext,
+) -> RouterResult<()> {
+    let client = state
+        .grpc_client
+        .unified_connector_service_client
+        .clone()
+        .ok_or(ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to fetch Unified Connector Service client")?;
+
+    let payment_repeat_request =
+        payments_grpc::PaymentServiceRepeatEverythingRequest::foreign_try_from(router_data)
+            .change_context(ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to construct Payment Authorize Request")?;
+
+    let connector_auth_metadata =
+        build_unified_connector_service_auth_metadata(merchant_connector_account, merchant_context)
+            .change_context(ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to construct request metadata")?;
+
+    let response = client
+        .payment_repeat(
+            payment_repeat_request,
+            connector_auth_metadata,
+            state.get_grpc_headers(),
+        )
+        .await
+        .change_context(ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to authorize payment")?;
+
+    let payment_repeat_response = response.into_inner();
+
+    let (status, router_data_response) =
+        handle_unified_connector_service_response_for_payment_repeat(
+            payment_repeat_response.clone(),
+        )
+        .change_context(ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to deserialize UCS response")?;
+
+    router_data.status = status;
+    router_data.response = router_data_response;
+    router_data.raw_connector_response = payment_repeat_response
+        .raw_connector_response
+        .map(Secret::new);
+
+    Ok(())
+}
diff --git a/crates/router/src/core/payments/flows/setup_mandate_flow.rs b/crates/router/src/core/payments/flows/setup_mandate_flow.rs
index eb43bff64fd..6204d521680 100644
--- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs
+++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs
@@ -1,19 +1,25 @@
 use async_trait::async_trait;
 use common_types::payments as common_payments_types;
+use error_stack::ResultExt;
 use router_env::logger;
+use unified_connector_service_client::payments as payments_grpc;
 
 use super::{ConstructFlowSpecificData, Feature};
 use crate::{
     core::{
-        errors::{ConnectorErrorExt, RouterResult},
+        errors::{ApiErrorResponse, ConnectorErrorExt, RouterResult},
         mandate,
         payments::{
             self, access_token, customers, helpers, tokenization, transformers, PaymentData,
         },
+        unified_connector_service::{
+            build_unified_connector_service_auth_metadata,
+            handle_unified_connector_service_response_for_payment_register,
+        },
     },
     routes::SessionState,
     services,
-    types::{self, api, domain},
+    types::{self, api, domain, transformers::ForeignTryFrom},
 };
 
 #[cfg(feature = "v1")]
@@ -200,6 +206,62 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
             _ => Ok((None, true)),
         }
     }
+
+    async fn call_unified_connector_service<'a>(
+        &mut self,
+        state: &SessionState,
+        #[cfg(feature = "v1")] merchant_connector_account: helpers::MerchantConnectorAccountType,
+        #[cfg(feature = "v2")]
+        merchant_connector_account: domain::MerchantConnectorAccountTypeDetails,
+        merchant_context: &domain::MerchantContext,
+    ) -> RouterResult<()> {
+        let client = state
+            .grpc_client
+            .unified_connector_service_client
+            .clone()
+            .ok_or(ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to fetch Unified Connector Service client")?;
+
+        let payment_register_request =
+            payments_grpc::PaymentServiceRegisterRequest::foreign_try_from(self)
+                .change_context(ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed to construct Payment Setup Mandate Request")?;
+
+        let connector_auth_metadata = build_unified_connector_service_auth_metadata(
+            merchant_connector_account,
+            merchant_context,
+        )
+        .change_context(ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to construct request metadata")?;
+
+        let response = client
+            .payment_setup_mandate(
+                payment_register_request,
+                connector_auth_metadata,
+                state.get_grpc_headers(),
+            )
+            .await
+            .change_context(ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to Setup Mandate payment")?;
+
+        let payment_register_response = response.into_inner();
+
+        let (status, router_data_response) =
+            handle_unified_connector_service_response_for_payment_register(
+                payment_register_response.clone(),
+            )
+            .change_context(ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to deserialize UCS response")?;
+
+        self.status = status;
+        self.response = router_data_response;
+        // UCS does not return raw connector response for setup mandate right now
+        // self.raw_connector_response = payment_register_response
+        //     .raw_connector_response
+        //     .map(Secret::new);
+
+        Ok(())
+    }
 }
 
 impl mandate::MandateBehaviour for types::SetupMandateRequestData {
diff --git a/crates/router/src/core/unified_connector_service.rs b/crates/router/src/core/unified_connector_service.rs
index 14836ff20c6..badd424abcf 100644
--- a/crates/router/src/core/unified_connector_service.rs
+++ b/crates/router/src/core/unified_connector_service.rs
@@ -10,7 +10,7 @@ use hyperswitch_domain_models::merchant_connector_account::MerchantConnectorAcco
 use hyperswitch_domain_models::{
     merchant_context::MerchantContext,
     router_data::{ConnectorAuthType, ErrorResponse, RouterData},
-    router_response_types::{PaymentsResponseData, RedirectForm},
+    router_response_types::PaymentsResponseData,
 };
 use masking::{ExposeInterface, PeekInterface, Secret};
 use unified_connector_service_client::payments::{
@@ -226,85 +226,8 @@ pub fn handle_unified_connector_service_response_for_payment_authorize(
 > {
     let status = AttemptStatus::foreign_try_from(response.status())?;
 
-    let connector_response_reference_id =
-        response.response_ref_id.as_ref().and_then(|identifier| {
-            identifier
-                .id_type
-                .clone()
-                .and_then(|id_type| match id_type {
-                    payments_grpc::identifier::IdType::Id(id) => Some(id),
-                    payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
-                        Some(encoded_data)
-                    }
-                    payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
-                })
-        });
-
-    let transaction_id = response.transaction_id.as_ref().and_then(|id| {
-        id.id_type.clone().and_then(|id_type| match id_type {
-            payments_grpc::identifier::IdType::Id(id) => Some(id),
-            payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some(encoded_data),
-            payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
-        })
-    });
-
-    let router_data_response = match status {
-        AttemptStatus::Charged |
-                AttemptStatus::Authorized |
-                AttemptStatus::AuthenticationPending |
-                AttemptStatus::DeviceDataCollectionPending |
-                AttemptStatus::Started |
-                AttemptStatus::AuthenticationSuccessful |
-                AttemptStatus::Authorizing |
-                AttemptStatus::ConfirmationAwaited |
-                AttemptStatus::Pending => Ok(PaymentsResponseData::TransactionResponse {
-                    resource_id: match transaction_id.as_ref() {
-                        Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()),
-                        None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
-                    },
-                    redirection_data: Box::new(
-                        response
-                            .redirection_data
-                            .clone()
-                            .map(RedirectForm::foreign_try_from)
-                            .transpose()?
-                    ),
-                    mandate_reference: Box::new(None),
-                    connector_metadata: None,
-                    network_txn_id: response.network_txn_id.clone(),
-                    connector_response_reference_id,
-                    incremental_authorization_allowed: response.incremental_authorization_allowed,
-                    charges: None,
-                }),
-        AttemptStatus::AuthenticationFailed
-                | AttemptStatus::AuthorizationFailed
-                | AttemptStatus::Unresolved
-                | AttemptStatus::Failure => Err(ErrorResponse {
-                    code: response.error_code().to_owned(),
-                    message: response.error_message().to_owned(),
-                    reason: Some(response.error_message().to_owned()),
-                    status_code: 500,
-                    attempt_status: Some(status),
-                    connector_transaction_id: connector_response_reference_id,
-                    network_decline_code: None,
-                    network_advice_code: None,
-                    network_error_message: None,
-                }),
-        AttemptStatus::RouterDeclined |
-                    AttemptStatus::CodInitiated |
-                    AttemptStatus::Voided |
-                    AttemptStatus::VoidInitiated |
-                    AttemptStatus::CaptureInitiated |
-                    AttemptStatus::VoidFailed |
-                    AttemptStatus::AutoRefunded |
-                    AttemptStatus::PartialCharged |
-                    AttemptStatus::PartialChargedAndChargeable |
-                    AttemptStatus::PaymentMethodAwaited |
-                    AttemptStatus::CaptureFailed |
-                    AttemptStatus::IntegrityFailure => return Err(UnifiedConnectorServiceError::NotImplemented(format!(
-                        "AttemptStatus {status:?} is not implemented for Unified Connector Service"
-                    )).into()),
-                };
+    let router_data_response =
+        Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
 
     Ok((status, router_data_response))
 }
@@ -317,75 +240,36 @@ pub fn handle_unified_connector_service_response_for_payment_get(
 > {
     let status = AttemptStatus::foreign_try_from(response.status())?;
 
-    let connector_response_reference_id =
-        response.response_ref_id.as_ref().and_then(|identifier| {
-            identifier
-                .id_type
-                .clone()
-                .and_then(|id_type| match id_type {
-                    payments_grpc::identifier::IdType::Id(id) => Some(id),
-                    payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
-                        Some(encoded_data)
-                    }
-                    payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
-                })
-        });
+    let router_data_response =
+        Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
 
-    let router_data_response = match status {
-        AttemptStatus::Charged |
-                AttemptStatus::Authorized |
-                AttemptStatus::AuthenticationPending |
-                AttemptStatus::DeviceDataCollectionPending |
-                AttemptStatus::Started |
-                AttemptStatus::AuthenticationSuccessful |
-                AttemptStatus::Authorizing |
-                AttemptStatus::ConfirmationAwaited |
-                AttemptStatus::Pending => Ok(
-            PaymentsResponseData::TransactionResponse {
-                resource_id: match connector_response_reference_id.as_ref() {
-                Some(connector_response_reference_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(connector_response_reference_id.clone()),
-                None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
-            },
-                redirection_data: Box::new(
-                    None
-                ),
-                mandate_reference: Box::new(None),
-                connector_metadata: None,
-                network_txn_id: response.network_txn_id.clone(),
-                connector_response_reference_id,
-                incremental_authorization_allowed: None,
-                charges: None,
-            }
-        ),
-        AttemptStatus::AuthenticationFailed
-                | AttemptStatus::AuthorizationFailed
-                | AttemptStatus::Failure => Err(ErrorResponse {
-            code: response.error_code().to_owned(),
-            message: response.error_message().to_owned(),
-            reason: Some(response.error_message().to_owned()),
-            status_code: 500,
-            attempt_status: Some(status),
-            connector_transaction_id: connector_response_reference_id,
-            network_decline_code: None,
-            network_advice_code: None,
-            network_error_message: None,
-        }),
-        AttemptStatus::RouterDeclined |
-                    AttemptStatus::CodInitiated |
-                    AttemptStatus::Voided |
-                    AttemptStatus::VoidInitiated |
-                    AttemptStatus::CaptureInitiated |
-                    AttemptStatus::VoidFailed |
-                    AttemptStatus::AutoRefunded |
-                    AttemptStatus::PartialCharged |
-                    AttemptStatus::PartialChargedAndChargeable |
-                    AttemptStatus::Unresolved |
-                    AttemptStatus::PaymentMethodAwaited |
-                    AttemptStatus::CaptureFailed |
-                    AttemptStatus::IntegrityFailure => return Err(UnifiedConnectorServiceError::NotImplemented(format!(
-                        "AttemptStatus {status:?} is not implemented for Unified Connector Service"
-                    )).into()),
-    };
+    Ok((status, router_data_response))
+}
+
+pub fn handle_unified_connector_service_response_for_payment_register(
+    response: payments_grpc::PaymentServiceRegisterResponse,
+) -> CustomResult<
+    (AttemptStatus, Result<PaymentsResponseData, ErrorResponse>),
+    UnifiedConnectorServiceError,
+> {
+    let status = AttemptStatus::foreign_try_from(response.status())?;
+
+    let router_data_response =
+        Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
+
+    Ok((status, router_data_response))
+}
+
+pub fn handle_unified_connector_service_response_for_payment_repeat(
+    response: payments_grpc::PaymentServiceRepeatEverythingResponse,
+) -> CustomResult<
+    (AttemptStatus, Result<PaymentsResponseData, ErrorResponse>),
+    UnifiedConnectorServiceError,
+> {
+    let status = AttemptStatus::foreign_try_from(response.status())?;
+
+    let router_data_response =
+        Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
 
     Ok((status, router_data_response))
 }
diff --git a/crates/router/src/core/unified_connector_service/transformers.rs b/crates/router/src/core/unified_connector_service/transformers.rs
index e937a7e7d2d..719b82ffd12 100644
--- a/crates/router/src/core/unified_connector_service/transformers.rs
+++ b/crates/router/src/core/unified_connector_service/transformers.rs
@@ -6,9 +6,11 @@ use diesel_models::enums as storage_enums;
 use error_stack::ResultExt;
 use external_services::grpc_client::unified_connector_service::UnifiedConnectorServiceError;
 use hyperswitch_domain_models::{
-    router_data::RouterData,
-    router_flow_types::payments::{Authorize, PSync},
-    router_request_types::{AuthenticationData, PaymentsAuthorizeData, PaymentsSyncData},
+    router_data::{ErrorResponse, RouterData},
+    router_flow_types::payments::{Authorize, PSync, SetupMandate},
+    router_request_types::{
+        AuthenticationData, PaymentsAuthorizeData, PaymentsSyncData, SetupMandateRequestData,
+    },
     router_response_types::{PaymentsResponseData, RedirectForm},
 };
 use masking::{ExposeInterface, PeekInterface};
@@ -167,6 +169,443 @@ impl ForeignTryFrom<&RouterData<Authorize, PaymentsAuthorizeData, PaymentsRespon
     }
 }
 
+impl ForeignTryFrom<&RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>>
+    for payments_grpc::PaymentServiceRegisterRequest
+{
+    type Error = error_stack::Report<UnifiedConnectorServiceError>;
+
+    fn foreign_try_from(
+        router_data: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
+    ) -> Result<Self, Self::Error> {
+        let currency = payments_grpc::Currency::foreign_try_from(router_data.request.currency)?;
+        let payment_method = router_data
+            .request
+            .payment_method_type
+            .map(|payment_method_type| {
+                build_unified_connector_service_payment_method(
+                    router_data.request.payment_method_data.clone(),
+                    payment_method_type,
+                )
+            })
+            .transpose()?;
+        let address = payments_grpc::PaymentAddress::foreign_try_from(router_data.address.clone())?;
+        let auth_type = payments_grpc::AuthenticationType::foreign_try_from(router_data.auth_type)?;
+        let browser_info = router_data
+            .request
+            .browser_info
+            .clone()
+            .map(payments_grpc::BrowserInformation::foreign_try_from)
+            .transpose()?;
+        let setup_future_usage = router_data
+            .request
+            .setup_future_usage
+            .map(payments_grpc::FutureUsage::foreign_try_from)
+            .transpose()?;
+        let customer_acceptance = router_data
+            .request
+            .customer_acceptance
+            .clone()
+            .map(payments_grpc::CustomerAcceptance::foreign_try_from)
+            .transpose()?;
+
+        Ok(Self {
+            request_ref_id: Some(Identifier {
+                id_type: Some(payments_grpc::identifier::IdType::Id(
+                    router_data.connector_request_reference_id.clone(),
+                )),
+            }),
+            currency: currency.into(),
+            payment_method,
+            minor_amount: router_data.request.amount,
+            email: router_data
+                .request
+                .email
+                .clone()
+                .map(|e| e.expose().expose()),
+            customer_name: router_data
+                .request
+                .customer_name
+                .clone()
+                .map(|customer_name| customer_name.peek().to_owned()),
+            connector_customer_id: router_data
+                .request
+                .customer_id
+                .as_ref()
+                .map(|id| id.get_string_repr().to_string()),
+            address: Some(address),
+            auth_type: auth_type.into(),
+            enrolled_for_3ds: false,
+            authentication_data: None,
+            metadata: router_data
+                .request
+                .metadata
+                .as_ref()
+                .map(|secret| secret.peek())
+                .and_then(|val| val.as_object()) //secret
+                .map(|map| {
+                    map.iter()
+                        .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
+                        .collect::<HashMap<String, String>>()
+                })
+                .unwrap_or_default(),
+            return_url: router_data.request.router_return_url.clone(),
+            webhook_url: router_data.request.webhook_url.clone(),
+            complete_authorize_url: router_data.request.complete_authorize_url.clone(),
+            access_token: None,
+            session_token: None,
+            order_tax_amount: None,
+            order_category: None,
+            merchant_order_reference_id: None,
+            shipping_cost: router_data
+                .request
+                .shipping_cost
+                .map(|cost| cost.get_amount_as_i64()),
+            setup_future_usage: setup_future_usage.map(|s| s.into()),
+            off_session: router_data.request.off_session,
+            request_incremental_authorization: router_data
+                .request
+                .request_incremental_authorization,
+            request_extended_authorization: None,
+            customer_acceptance,
+            browser_info,
+            payment_experience: None,
+        })
+    }
+}
+
+impl ForeignTryFrom<&RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>>
+    for payments_grpc::PaymentServiceRepeatEverythingRequest
+{
+    type Error = error_stack::Report<UnifiedConnectorServiceError>;
+
+    fn foreign_try_from(
+        router_data: &RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>,
+    ) -> Result<Self, Self::Error> {
+        let currency = payments_grpc::Currency::foreign_try_from(router_data.request.currency)?;
+
+        let mandate_reference = match &router_data.request.mandate_id {
+            Some(mandate) => match &mandate.mandate_reference_id {
+                Some(api_models::payments::MandateReferenceId::ConnectorMandateId(
+                    connector_mandate_id,
+                )) => Some(payments_grpc::MandateReference {
+                    mandate_id: connector_mandate_id.get_connector_mandate_id(),
+                }),
+                _ => {
+                    return Err(UnifiedConnectorServiceError::MissingRequiredField {
+                        field_name: "connector_mandate_id",
+                    }
+                    .into())
+                }
+            },
+            None => {
+                return Err(UnifiedConnectorServiceError::MissingRequiredField {
+                    field_name: "connector_mandate_id",
+                }
+                .into())
+            }
+        };
+
+        Ok(Self {
+            request_ref_id: Some(Identifier {
+                id_type: Some(payments_grpc::identifier::IdType::Id(
+                    router_data.connector_request_reference_id.clone(),
+                )),
+            }),
+            mandate_reference,
+            amount: router_data.request.amount,
+            currency: currency.into(),
+            minor_amount: router_data.request.amount,
+            merchant_order_reference_id: router_data.request.merchant_order_reference_id.clone(),
+            metadata: router_data
+                .request
+                .metadata
+                .as_ref()
+                .and_then(|val| val.as_object())
+                .map(|map| {
+                    map.iter()
+                        .filter_map(|(k, v)| v.as_str().map(|s| (k.clone(), s.to_string())))
+                        .collect::<HashMap<String, String>>()
+                })
+                .unwrap_or_default(),
+            webhook_url: router_data.request.webhook_url.clone(),
+        })
+    }
+}
+
+impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
+    for Result<PaymentsResponseData, ErrorResponse>
+{
+    type Error = error_stack::Report<UnifiedConnectorServiceError>;
+
+    fn foreign_try_from(
+        response: payments_grpc::PaymentServiceAuthorizeResponse,
+    ) -> Result<Self, Self::Error> {
+        let status = AttemptStatus::foreign_try_from(response.status())?;
+
+        let connector_response_reference_id =
+            response.response_ref_id.as_ref().and_then(|identifier| {
+                identifier
+                    .id_type
+                    .clone()
+                    .and_then(|id_type| match id_type {
+                        payments_grpc::identifier::IdType::Id(id) => Some(id),
+                        payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
+                            Some(encoded_data)
+                        }
+                        payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
+                    })
+            });
+
+        let transaction_id = response.transaction_id.as_ref().and_then(|id| {
+            id.id_type.clone().and_then(|id_type| match id_type {
+                payments_grpc::identifier::IdType::Id(id) => Some(id),
+                payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some(encoded_data),
+                payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
+            })
+        });
+
+        let response = if response.error_code.is_some() {
+            Err(ErrorResponse {
+                code: response.error_code().to_owned(),
+                message: response.error_message().to_owned(),
+                reason: Some(response.error_message().to_owned()),
+                status_code: 500, //TODO: To be handled once UCS sends proper status codes
+                attempt_status: Some(status),
+                connector_transaction_id: connector_response_reference_id,
+                network_decline_code: None,
+                network_advice_code: None,
+                network_error_message: None,
+            })
+        } else {
+            Ok(PaymentsResponseData::TransactionResponse {
+                resource_id: match transaction_id.as_ref() {
+                    Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()),
+                    None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
+                },
+                redirection_data: Box::new(
+                    response
+                        .redirection_data
+                        .clone()
+                        .map(RedirectForm::foreign_try_from)
+                        .transpose()?
+                ),
+                mandate_reference: Box::new(None),
+                connector_metadata: None,
+                network_txn_id: response.network_txn_id.clone(),
+                connector_response_reference_id,
+                incremental_authorization_allowed: response.incremental_authorization_allowed,
+                charges: None,
+            })
+        };
+
+        Ok(response)
+    }
+}
+
+impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
+    for Result<PaymentsResponseData, ErrorResponse>
+{
+    type Error = error_stack::Report<UnifiedConnectorServiceError>;
+
+    fn foreign_try_from(
+        response: payments_grpc::PaymentServiceGetResponse,
+    ) -> Result<Self, Self::Error> {
+        let status = AttemptStatus::foreign_try_from(response.status())?;
+
+        let connector_response_reference_id =
+            response.response_ref_id.as_ref().and_then(|identifier| {
+                identifier
+                    .id_type
+                    .clone()
+                    .and_then(|id_type| match id_type {
+                        payments_grpc::identifier::IdType::Id(id) => Some(id),
+                        payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
+                            Some(encoded_data)
+                        }
+                        payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
+                    })
+            });
+
+        let response = if response.error_code.is_some() {
+            Err(ErrorResponse {
+                code: response.error_code().to_owned(),
+                message: response.error_message().to_owned(),
+                reason: Some(response.error_message().to_owned()),
+                status_code: 500, //TODO: To be handled once UCS sends proper status codes
+                attempt_status: Some(status),
+                connector_transaction_id: connector_response_reference_id,
+                network_decline_code: None,
+                network_advice_code: None,
+                network_error_message: None,
+            })
+        } else {
+            Ok(PaymentsResponseData::TransactionResponse {
+                resource_id: match connector_response_reference_id.as_ref() {
+                    Some(connector_response_reference_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(connector_response_reference_id.clone()),
+                    None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
+                },
+                redirection_data: Box::new(
+                    None
+                ),
+                mandate_reference: Box::new(None),
+                connector_metadata: None,
+                network_txn_id: response.network_txn_id.clone(),
+                connector_response_reference_id,
+                incremental_authorization_allowed: None,
+                charges: None,
+                }
+            )
+        };
+
+        Ok(response)
+    }
+}
+
+impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
+    for Result<PaymentsResponseData, ErrorResponse>
+{
+    type Error = error_stack::Report<UnifiedConnectorServiceError>;
+
+    fn foreign_try_from(
+        response: payments_grpc::PaymentServiceRegisterResponse,
+    ) -> Result<Self, Self::Error> {
+        let status = AttemptStatus::foreign_try_from(response.status())?;
+
+        let connector_response_reference_id =
+            response.response_ref_id.as_ref().and_then(|identifier| {
+                identifier
+                    .id_type
+                    .clone()
+                    .and_then(|id_type| match id_type {
+                        payments_grpc::identifier::IdType::Id(id) => Some(id),
+                        payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
+                            Some(encoded_data)
+                        }
+                        payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
+                    })
+            });
+
+        let response = if response.error_code.is_some() {
+            Err(ErrorResponse {
+                code: response.error_code().to_owned(),
+                message: response.error_message().to_owned(),
+                reason: Some(response.error_message().to_owned()),
+                status_code: 500, //TODO: To be handled once UCS sends proper status codes
+                attempt_status: Some(status),
+                connector_transaction_id: connector_response_reference_id,
+                network_decline_code: None,
+                network_advice_code: None,
+                network_error_message: None,
+            })
+        } else {
+            Ok(PaymentsResponseData::TransactionResponse {
+                resource_id: response.registration_id.as_ref().and_then(|identifier| {
+                    identifier
+                        .id_type
+                        .clone()
+                        .and_then(|id_type| match id_type {
+                            payments_grpc::identifier::IdType::Id(id) => Some(
+                                hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(id),
+                            ),
+                            payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some(
+                                hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(encoded_data),
+                            ),
+                            payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
+                        })
+                }).unwrap_or(hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId),
+                redirection_data: Box::new(
+                    response
+                        .redirection_data
+                        .clone()
+                        .map(RedirectForm::foreign_try_from)
+                        .transpose()?
+                ),
+                mandate_reference: Box::new(
+                    response.mandate_reference.map(|grpc_mandate| {
+                        hyperswitch_domain_models::router_response_types::MandateReference {
+                            connector_mandate_id: grpc_mandate.mandate_id,
+                            payment_method_id: None,
+                            mandate_metadata: None,
+                            connector_mandate_request_reference_id: None,
+                        }
+                    })
+                ),
+                connector_metadata: None,
+                network_txn_id: response.network_txn_id,
+                connector_response_reference_id,
+                incremental_authorization_allowed: response.incremental_authorization_allowed,
+                charges: None,
+            })
+        };
+
+        Ok(response)
+    }
+}
+
+impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
+    for Result<PaymentsResponseData, ErrorResponse>
+{
+    type Error = error_stack::Report<UnifiedConnectorServiceError>;
+
+    fn foreign_try_from(
+        response: payments_grpc::PaymentServiceRepeatEverythingResponse,
+    ) -> Result<Self, Self::Error> {
+        let status = AttemptStatus::foreign_try_from(response.status())?;
+
+        let connector_response_reference_id =
+            response.response_ref_id.as_ref().and_then(|identifier| {
+                identifier
+                    .id_type
+                    .clone()
+                    .and_then(|id_type| match id_type {
+                        payments_grpc::identifier::IdType::Id(id) => Some(id),
+                        payments_grpc::identifier::IdType::EncodedData(encoded_data) => {
+                            Some(encoded_data)
+                        }
+                        payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
+                    })
+            });
+
+        let transaction_id = response.transaction_id.as_ref().and_then(|id| {
+            id.id_type.clone().and_then(|id_type| match id_type {
+                payments_grpc::identifier::IdType::Id(id) => Some(id),
+                payments_grpc::identifier::IdType::EncodedData(encoded_data) => Some(encoded_data),
+                payments_grpc::identifier::IdType::NoResponseIdMarker(_) => None,
+            })
+        });
+
+        let response = if response.error_code.is_some() {
+            Err(ErrorResponse {
+                code: response.error_code().to_owned(),
+                message: response.error_message().to_owned(),
+                reason: Some(response.error_message().to_owned()),
+                status_code: 500, //TODO: To be handled once UCS sends proper status codes
+                attempt_status: Some(status),
+                connector_transaction_id: transaction_id,
+                network_decline_code: None,
+                network_advice_code: None,
+                network_error_message: None,
+            })
+        } else {
+            Ok(PaymentsResponseData::TransactionResponse {
+                resource_id: match transaction_id.as_ref() {
+                    Some(transaction_id) => hyperswitch_domain_models::router_request_types::ResponseId::ConnectorTransactionId(transaction_id.clone()),
+                    None => hyperswitch_domain_models::router_request_types::ResponseId::NoResponseId,
+                },
+                redirection_data: Box::new(None),
+                mandate_reference: Box::new(None),
+                connector_metadata: None,
+                network_txn_id: response.network_txn_id.clone(),
+                connector_response_reference_id,
+                incremental_authorization_allowed: None,
+                charges: None,
+            })
+        };
+
+        Ok(response)
+    }
+}
+
 impl ForeignTryFrom<common_enums::Currency> for payments_grpc::Currency {
     type Error = error_stack::Report<UnifiedConnectorServiceError>;
 
@@ -480,3 +919,48 @@ impl ForeignTryFrom<payments_grpc::HttpMethod> for Method {
         }
     }
 }
+
+impl ForeignTryFrom<storage_enums::FutureUsage> for payments_grpc::FutureUsage {
+    type Error = error_stack::Report<UnifiedConnectorServiceError>;
+
+    fn foreign_try_from(future_usage: storage_enums::FutureUsage) -> Result<Self, Self::Error> {
+        match future_usage {
+            storage_enums::FutureUsage::OnSession => Ok(Self::OnSession),
+            storage_enums::FutureUsage::OffSession => Ok(Self::OffSession),
+        }
+    }
+}
+
+impl ForeignTryFrom<common_types::payments::CustomerAcceptance>
+    for payments_grpc::CustomerAcceptance
+{
+    type Error = error_stack::Report<UnifiedConnectorServiceError>;
+
+    fn foreign_try_from(
+        customer_acceptance: common_types::payments::CustomerAcceptance,
+    ) -> Result<Self, Self::Error> {
+        let acceptance_type = match customer_acceptance.acceptance_type {
+            common_types::payments::AcceptanceType::Online => payments_grpc::AcceptanceType::Online,
+            common_types::payments::AcceptanceType::Offline => {
+                payments_grpc::AcceptanceType::Offline
+            }
+        };
+
+        let online_mandate_details =
+            customer_acceptance
+                .online
+                .map(|online| payments_grpc::OnlineMandate {
+                    ip_address: online.ip_address.map(|ip| ip.peek().to_string()),
+                    user_agent: online.user_agent,
+                });
+
+        Ok(Self {
+            acceptance_type: acceptance_type.into(),
+            accepted_at: customer_acceptance
+                .accepted_at
+                .map(|dt| dt.assume_utc().unix_timestamp())
+                .unwrap_or_default(),
+            online_mandate_details,
+        })
+    }
+}

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

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

## Description
<!-- Describe your changes in detail -->
This PR implements UCS(Unified Connector Service) Integration for SetupMandate and RepeatEverything (recurring payment) flows.
- Updated rust-grpc-client dependency to main branch
- Added log for Successful UCS connection

### Additional Changes

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

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

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


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

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


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Create Intent for Zero mandate
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: _' \
--data '
{
  "amount": 0,
  "confirm": false,
  "currency": "USD",
  "customer_id": "Customer123",
  "setup_future_usage": "off_session"
}'
```
Confirm CIT (Authorisedotnet via UCS)
```
curl --location 'http://localhost:8080/payments/pay_YbaKZHAfIRvsnGpeuOcH/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: _' \
--data-raw '{
    "confirm": true,
    "customer_id": "Customer123",
    "payment_type": "setup_mandate",
    "customer_acceptance": {
        "acceptance_type": "online",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "127.0.0.1",
            "user_agent": "amet irure esse"
        }
    },
    "payment_method": "card",
    "payment_method_type": "credit",
    "email": "test@novalnet.de",
    "payment_method_data": {
        "card": {
            "card_number": "4349940199004549",
            "card_exp_month": "12",
            "card_exp_year": "30",
            "card_holder_name": "joseph Doe",
            "card_cvc": "396",
            "card_network": "VISA"
        },
        "billing": {
            "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "IT",
            "first_name": "joseph",
            "last_name": "Doe"
        },
            "email": "test@novalnet.de",
            "phone": {
                "number": "8056594427",
                "country_code": "+91"
            }
        }
    },
    "all_keys_required": true
}'
```
Response
```
{
    "payment_id": "pay_2d7OcbcSgKUrkt4ETxYP",
    "merchant_id": "merchant_1753280085",
    "status": "succeeded",
    "amount": 0,
    "net_amount": 0,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": "authorizedotnet",
    "client_secret": "pay_2d7OcbcSgKUrkt4ETxYP_secret_fLFQbtHQWQGORcgUtr4l",
    "created": "2025-07-23T14:57:40.169Z",
    "currency": "USD",
    "customer_id": "Customer123",
    "customer": {
        "id": "Customer123",
        "name": null,
        "email": "test@novalnet.de",
        "phone": null,
        "phone_country_code": null
    },
    "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": "card",
    "payment_method_data": {
        "card": {
            "last4": "4549",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "434994",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "30",
            "card_holder_name": "joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": {
            "address": {
                "city": "San Fransico",
                "country": "IT",
                "line1": "1467",
                "line2": "Harrison Street",
                "line3": "Harrison Street",
                "zip": "94122",
                "state": "California",
                "first_name": "joseph",
                "last_name": "Doe"
            },
            "phone": {
                "number": "8056594427",
                "country_code": "+91"
            },
            "email": "test@novalnet.de"
        }
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "test@novalnet.de",
    "name": null,
    "phone": null,
    "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": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "523966074",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_0UBAnCbAThEENJj9KfZ0",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_XVTNsN4D9kHGw3DxkEP0",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-07-23T15:12:40.168Z",
    "fingerprint": null,
    "browser_info": {
        "os_type": null,
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "os_version": null,
        "user_agent": null,
        "color_depth": null,
        "device_model": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "accept_language": "en",
        "java_script_enabled": null
    },
    "payment_method_id": "pm_tSOU7aOBhgKLBE92628X",
    "payment_method_status": "active",
    "updated": "2025-07-23T14:58:20.071Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": "523966074-536113445",
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}
```
Card recurring payment (Authorizedotnet via UCS)
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_dAANSmNFGJ0ppE3KkF0NaFYdWmHDQReivo4zXuzWPPvMae7TSIRPRus6hDyNDTGt' \
--data '{
    "amount": 100,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "customer_id": "Customer123",
    "off_session": true,
    "recurring_details": {
        "type": "payment_method_id",
        "data": "pm_Ca7e4nuk9S8z1S7ksaF6"
    }
}'
```
Response
```
{
    "payment_id": "pay_YbaKZHAfIRvsnGpeuOcH",
    "merchant_id": "merchant_1753280085",
    "status": "succeeded",
    "amount": 100,
    "net_amount": 100,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 100,
    "connector": "authorizedotnet",
    "client_secret": "pay_YbaKZHAfIRvsnGpeuOcH_secret_hTmFPsa4amP6XdXG6g9d",
    "created": "2025-07-23T14:58:39.835Z",
    "currency": "USD",
    "customer_id": "Customer123",
    "customer": {
        "id": "Customer123",
        "name": null,
        "email": "test@novalnet.de",
        "phone": null,
        "phone_country_code": null
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": true,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "4549",
            "card_type": null,
            "card_network": "Visa",
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "434994",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "30",
            "card_holder_name": "joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "test@novalnet.de",
    "name": null,
    "phone": null,
    "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": "credit",
    "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": 1753282719,
        "expires": 1753286319,
        "secret": "epk_fd17c36b38584f0488578d1335542cbe"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "80042797687",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_0UBAnCbAThEENJj9KfZ0",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_XVTNsN4D9kHGw3DxkEP0",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-07-23T15:13:39.835Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": "pm_Ca7e4nuk9S8z1S7ksaF6",
    "payment_method_status": "active",
    "updated": "2025-07-23T14:58:40.816Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": "523965707-536113051",
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}
```

## 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`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible


Create Intent for Zero mandate
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: _' \
--data '
{
  "amount": 0,
  "confirm": false,
  "currency": "USD",
  "customer_id": "Customer123",
  "setup_future_usage": "off_session"
}'
```
Confirm CIT (Authorisedotnet via UCS)
```
curl --location 'http://localhost:8080/payments/pay_YbaKZHAfIRvsnGpeuOcH/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: _' \
--data-raw '{
    "confirm": true,
    "customer_id": "Customer123",
    "payment_type": "setup_mandate",
    "customer_acceptance": {
        "acceptance_type": "online",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "127.0.0.1",
            "user_agent": "amet irure esse"
        }
    },
    "payment_method": "card",
    "payment_method_type": "credit",
    "email": "test@novalnet.de",
    "payment_method_data": {
        "card": {
            "card_number": "4349940199004549",
            "card_exp_month": "12",
            "card_exp_year": "30",
            "card_holder_name": "joseph Doe",
            "card_cvc": "396",
            "card_network": "VISA"
        },
        "billing": {
            "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "IT",
            "first_name": "joseph",
            "last_name": "Doe"
        },
            "email": "test@novalnet.de",
            "phone": {
                "number": "8056594427",
                "country_code": "+91"
            }
        }
    },
    "all_keys_required": true
}'
```
Response
```
{
    "payment_id": "pay_2d7OcbcSgKUrkt4ETxYP",
    "merchant_id": "merchant_1753280085",
    "status": "succeeded",
    "amount": 0,
    "net_amount": 0,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": "authorizedotnet",
    "client_secret": "pay_2d7OcbcSgKUrkt4ETxYP_secret_fLFQbtHQWQGORcgUtr4l",
    "created": "2025-07-23T14:57:40.169Z",
    "currency": "USD",
    "customer_id": "Customer123",
    "customer": {
        "id": "Customer123",
        "name": null,
        "email": "test@novalnet.de",
        "phone": null,
        "phone_country_code": null
    },
    "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": "card",
    "payment_method_data": {
        "card": {
            "last4": "4549",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "434994",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "30",
            "card_holder_name": "joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": {
            "address": {
                "city": "San Fransico",
                "country": "IT",
                "line1": "1467",
                "line2": "Harrison Street",
                "line3": "Harrison Street",
                "zip": "94122",
                "state": "California",
                "first_name": "joseph",
                "last_name": "Doe"
            },
            "phone": {
                "number": "8056594427",
                "country_code": "+91"
            },
            "email": "test@novalnet.de"
        }
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "test@novalnet.de",
    "name": null,
    "phone": null,
    "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": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "523966074",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_0UBAnCbAThEENJj9KfZ0",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_XVTNsN4D9kHGw3DxkEP0",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-07-23T15:12:40.168Z",
    "fingerprint": null,
    "browser_info": {
        "os_type": null,
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "os_version": null,
        "user_agent": null,
        "color_depth": null,
        "device_model": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "accept_language": "en",
        "java_script_enabled": null
    },
    "payment_method_id": "pm_tSOU7aOBhgKLBE92628X",
    "payment_method_status": "active",
    "updated": "2025-07-23T14:58:20.071Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": "523966074-536113445",
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}
```
Card recurring payment (Authorizedotnet via UCS)
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_dAANSmNFGJ0ppE3KkF0NaFYdWmHDQReivo4zXuzWPPvMae7TSIRPRus6hDyNDTGt' \
--data '{
    "amount": 100,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "customer_id": "Customer123",
    "off_session": true,
    "recurring_details": {
        "type": "payment_method_id",
        "data": "pm_Ca7e4nuk9S8z1S7ksaF6"
    }
}'
```
Response
```
{
    "payment_id": "pay_YbaKZHAfIRvsnGpeuOcH",
    "merchant_id": "merchant_1753280085",
    "status": "succeeded",
    "amount": 100,
    "net_amount": 100,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 100,
    "connector": "authorizedotnet",
    "client_secret": "pay_YbaKZHAfIRvsnGpeuOcH_secret_hTmFPsa4amP6XdXG6g9d",
    "created": "2025-07-23T14:58:39.835Z",
    "currency": "USD",
    "customer_id": "Customer123",
    "customer": {
        "id": "Customer123",
        "name": null,
        "email": "test@novalnet.de",
        "phone": null,
        "phone_country_code": null
    },
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": true,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "4549",
            "card_type": null,
            "card_network": "Visa",
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "434994",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "30",
            "card_holder_name": "joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "test@novalnet.de",
    "name": null,
    "phone": null,
    "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": "credit",
    "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": 1753282719,
        "expires": 1753286319,
        "secret": "epk_fd17c36b38584f0488578d1335542cbe"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "80042797687",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_0UBAnCbAThEENJj9KfZ0",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_XVTNsN4D9kHGw3DxkEP0",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-07-23T15:13:39.835Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": "pm_Ca7e4nuk9S8z1S7ksaF6",
    "payment_method_status": "active",
    "updated": "2025-07-23T14:58:40.816Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": "523965707-536113051",
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}
```
