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
