Bug: [FEATURE] Implement comprehensive event logging for UCS (Unified Connector Service) operations



Currently, UCS operations lack proper event logging and observability, making it difficult to debug issues, monitor performance, and track payment flows through the unified connector service.
diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs
index 1c689943d73..b9d9b9aa27e 100644
--- a/crates/router/src/core/payments/flows/authorize_flow.rs
+++ b/crates/router/src/core/payments/flows/authorize_flow.rs
@@ -20,7 +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,
+            handle_unified_connector_service_response_for_payment_repeat, ucs_logging_wrapper,
         },
     },
     logger,
@@ -523,20 +523,20 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
         merchant_context: &domain::MerchantContext,
     ) -> RouterResult<()> {
         if self.request.mandate_id.is_some() {
-            call_unified_connector_service_repeat_payment(
+            Box::pin(call_unified_connector_service_repeat_payment(
                 self,
                 state,
                 merchant_connector_account,
                 merchant_context,
-            )
+            ))
             .await
         } else {
-            call_unified_connector_service_authorize(
+            Box::pin(call_unified_connector_service_authorize(
                 self,
                 state,
                 merchant_connector_account,
                 merchant_context,
-            )
+            ))
             .await
         }
     }
@@ -854,33 +854,46 @@ async fn call_unified_connector_service_authorize(
             .change_context(ApiErrorResponse::InternalServerError)
             .attach_printable("Failed to construct request metadata")?;
 
-    let response = client
-        .payment_authorize(
-            payment_authorize_request,
-            connector_auth_metadata,
-            None,
-            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, status_code) =
-        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);
-    router_data.connector_http_status_code = Some(status_code);
+    let updated_router_data = Box::pin(ucs_logging_wrapper(
+        router_data.clone(),
+        state,
+        payment_authorize_request,
+        |mut router_data, payment_authorize_request| async move {
+            let response = client
+                .payment_authorize(
+                    payment_authorize_request,
+                    connector_auth_metadata,
+                    None,
+                    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, status_code) =
+                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
+                .clone()
+                .map(Secret::new);
+            router_data.connector_http_status_code = Some(status_code);
+
+            Ok((router_data, payment_authorize_response))
+        },
+    ))
+    .await?;
 
+    // Copy back the updated data
+    *router_data = updated_router_data;
     Ok(())
 }
 
@@ -903,40 +916,53 @@ async fn call_unified_connector_service_repeat_payment(
         .attach_printable("Failed to fetch Unified Connector Service client")?;
 
     let payment_repeat_request =
-        payments_grpc::PaymentServiceRepeatEverythingRequest::foreign_try_from(router_data)
+        payments_grpc::PaymentServiceRepeatEverythingRequest::foreign_try_from(&*router_data)
             .change_context(ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed to construct Payment Authorize Request")?;
+            .attach_printable("Failed to construct Payment Repeat 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, status_code) =
-        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);
-    router_data.connector_http_status_code = Some(status_code);
+    let updated_router_data = Box::pin(ucs_logging_wrapper(
+        router_data.clone(),
+        state,
+        payment_repeat_request,
+        |mut router_data, payment_repeat_request| async move {
+            let response = client
+                .payment_repeat(
+                    payment_repeat_request,
+                    connector_auth_metadata.clone(),
+                    state.get_grpc_headers(),
+                )
+                .await
+                .change_context(ApiErrorResponse::InternalServerError)
+                .attach_printable("Failed to repeat payment")?;
+
+            let payment_repeat_response = response.into_inner();
+
+            let (status, router_data_response, status_code) =
+                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
+                .clone()
+                .map(Secret::new);
+            router_data.connector_http_status_code = Some(status_code);
+
+            Ok((router_data, payment_repeat_response))
+        },
+    ))
+    .await?;
 
+    // Copy back the updated data
+    *router_data = updated_router_data;
     Ok(())
 }
diff --git a/crates/router/src/core/payments/flows/external_proxy_flow.rs b/crates/router/src/core/payments/flows/external_proxy_flow.rs
index ac491685b5d..b184aa60d5e 100644
--- a/crates/router/src/core/payments/flows/external_proxy_flow.rs
+++ b/crates/router/src/core/payments/flows/external_proxy_flow.rs
@@ -15,7 +15,7 @@ use crate::{
         payments::{
             self, access_token, customers, helpers, tokenization, transformers, PaymentData,
         },
-        unified_connector_service,
+        unified_connector_service::{self, ucs_logging_wrapper},
     },
     logger,
     routes::{metrics, SessionState},
@@ -394,33 +394,45 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
             .change_context(ApiErrorResponse::InternalServerError)
             .attach_printable("Failed to construct external vault proxy metadata")?;
 
-        let response = client
-            .payment_authorize(
-                payment_authorize_request,
-                connector_auth_metadata,
-                Some(external_vault_proxy_metadata),
-                state.get_grpc_headers(),
-            )
-            .await
-            .change_context(ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed to authorize payment")?;
-
-        let payment_authorize_response = response.into_inner();
+        let updated_router_data = Box::pin(ucs_logging_wrapper(
+            self.clone(),
+            state,
+            payment_authorize_request.clone(),
+            |mut router_data, payment_authorize_request| async move {
+                let response = client
+                    .payment_authorize(
+                        payment_authorize_request,
+                        connector_auth_metadata,
+                        Some(external_vault_proxy_metadata),
+                        state.get_grpc_headers(),
+                    )
+                    .await
+                    .change_context(ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed to authorize payment")?;
 
-        let (status, router_data_response, status_code) =
-            unified_connector_service::handle_unified_connector_service_response_for_payment_authorize(
-                payment_authorize_response.clone(),
-            )
-            .change_context(ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed to deserialize UCS response")?;
+                let payment_authorize_response = response.into_inner();
 
-        self.status = status;
-        self.response = router_data_response;
-        self.raw_connector_response = payment_authorize_response
-            .raw_connector_response
-            .map(masking::Secret::new);
-        self.connector_http_status_code = Some(status_code);
+                let (status, router_data_response, status_code) =
+                    unified_connector_service::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
+                    .clone()
+                    .map(masking::Secret::new);
+                router_data.connector_http_status_code = Some(status_code);
+
+                Ok((router_data, payment_authorize_response))
+            }
+        )).await?;
 
+        // Copy back the updated data
+        *self = updated_router_data;
         Ok(())
     }
 }
diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs
index 93a2c1ecd48..802bd3d5bcf 100644
--- a/crates/router/src/core/payments/flows/psync_flow.rs
+++ b/crates/router/src/core/payments/flows/psync_flow.rs
@@ -13,7 +13,7 @@ use crate::{
         payments::{self, access_token, helpers, transformers, PaymentData},
         unified_connector_service::{
             build_unified_connector_service_auth_metadata,
-            handle_unified_connector_service_response_for_payment_get,
+            handle_unified_connector_service_response_for_payment_get, ucs_logging_wrapper,
         },
     },
     routes::SessionState,
@@ -233,7 +233,7 @@ impl Feature<api::PSync, types::PaymentsSyncData>
             .ok_or(ApiErrorResponse::InternalServerError)
             .attach_printable("Failed to fetch Unified Connector Service client")?;
 
-        let payment_get_request = payments_grpc::PaymentServiceGetRequest::foreign_try_from(self)
+        let payment_get_request = payments_grpc::PaymentServiceGetRequest::foreign_try_from(&*self)
             .change_context(ApiErrorResponse::InternalServerError)
             .attach_printable("Failed to construct Payment Get Request")?;
 
@@ -244,28 +244,45 @@ impl Feature<api::PSync, types::PaymentsSyncData>
         .change_context(ApiErrorResponse::InternalServerError)
         .attach_printable("Failed to construct request metadata")?;
 
-        let response = client
-            .payment_get(
-                payment_get_request,
-                connector_auth_metadata,
-                state.get_grpc_headers(),
-            )
-            .await
-            .change_context(ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed to get payment")?;
+        let updated_router_data = Box::pin(ucs_logging_wrapper(
+            self.clone(),
+            state,
+            payment_get_request,
+            |mut router_data, payment_get_request| async move {
+                let response = client
+                    .payment_get(
+                        payment_get_request,
+                        connector_auth_metadata,
+                        state.get_grpc_headers(),
+                    )
+                    .await
+                    .change_context(ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed to get payment")?;
+
+                let payment_get_response = response.into_inner();
 
-        let payment_get_response = response.into_inner();
+                let (status, router_data_response, status_code) =
+                    handle_unified_connector_service_response_for_payment_get(
+                        payment_get_response.clone(),
+                    )
+                    .change_context(ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed to deserialize UCS response")?;
 
-        let (status, router_data_response, status_code) =
-            handle_unified_connector_service_response_for_payment_get(payment_get_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_get_response
+                    .raw_connector_response
+                    .clone()
+                    .map(Secret::new);
+                router_data.connector_http_status_code = Some(status_code);
 
-        self.status = status;
-        self.response = router_data_response;
-        self.raw_connector_response = payment_get_response.raw_connector_response.map(Secret::new);
-        self.connector_http_status_code = Some(status_code);
+                Ok((router_data, payment_get_response))
+            },
+        ))
+        .await?;
 
+        // Copy back the updated data
+        *self = updated_router_data;
         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 035937808c4..6cd1cd1dedc 100644
--- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs
+++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs
@@ -14,7 +14,7 @@ use crate::{
         },
         unified_connector_service::{
             build_unified_connector_service_auth_metadata,
-            handle_unified_connector_service_response_for_payment_register,
+            handle_unified_connector_service_response_for_payment_register, ucs_logging_wrapper,
         },
     },
     routes::SessionState,
@@ -272,7 +272,7 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
             .attach_printable("Failed to fetch Unified Connector Service client")?;
 
         let payment_register_request =
-            payments_grpc::PaymentServiceRegisterRequest::foreign_try_from(self)
+            payments_grpc::PaymentServiceRegisterRequest::foreign_try_from(&*self)
                 .change_context(ApiErrorResponse::InternalServerError)
                 .attach_printable("Failed to construct Payment Setup Mandate Request")?;
 
@@ -283,33 +283,41 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
         .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, status_code) =
-            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;
-        self.connector_http_status_code = Some(status_code);
-        // 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);
+        let updated_router_data = Box::pin(ucs_logging_wrapper(
+            self.clone(),
+            state,
+            payment_register_request,
+            |mut router_data, payment_register_request| async move {
+                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, status_code) =
+                    handle_unified_connector_service_response_for_payment_register(
+                        payment_register_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.connector_http_status_code = Some(status_code);
+
+                Ok((router_data, payment_register_response))
+            },
+        ))
+        .await?;
 
+        // Copy back the updated data
+        *self = updated_router_data;
         Ok(())
     }
 }
diff --git a/crates/router/src/core/unified_connector_service.rs b/crates/router/src/core/unified_connector_service.rs
index 9722f36ae41..e473482b57b 100644
--- a/crates/router/src/core/unified_connector_service.rs
+++ b/crates/router/src/core/unified_connector_service.rs
@@ -1,4 +1,4 @@
-use std::str::FromStr;
+use std::{str::FromStr, time::Instant};
 
 use api_models::admin;
 #[cfg(feature = "v2")]
@@ -23,7 +23,7 @@ use hyperswitch_domain_models::{
     router_response_types::PaymentsResponseData,
 };
 use masking::{ExposeInterface, PeekInterface, Secret};
-use router_env::logger;
+use router_env::{instrument, logger, tracing};
 use unified_connector_service_cards::CardNumber;
 use unified_connector_service_client::payments::{
     self as payments_grpc, payment_method::PaymentMethod, CardDetails, CardPaymentMethodType,
@@ -44,6 +44,7 @@ use crate::{
         },
         utils::get_flow_name,
     },
+    events::connector_api_logs::ConnectorEvent,
     routes::SessionState,
     types::transformers::ForeignTryFrom,
     utils,
@@ -804,3 +805,120 @@ pub fn extract_webhook_content_from_ucs_response(
 ) -> Option<&unified_connector_service_client::payments::WebhookResponseContent> {
     transform_data.webhook_content.as_ref()
 }
+
+/// UCS Event Logging Wrapper Function
+/// This function wraps UCS calls with comprehensive event logging.
+/// It logs the actual gRPC request/response data, timing, and error information.
+#[instrument(skip_all, fields(connector_name, flow_type, payment_id))]
+pub async fn ucs_logging_wrapper<T, F, Fut, Req, Resp, GrpcReq, GrpcResp>(
+    router_data: RouterData<T, Req, Resp>,
+    state: &SessionState,
+    grpc_request: GrpcReq,
+    handler: F,
+) -> RouterResult<RouterData<T, Req, Resp>>
+where
+    T: std::fmt::Debug + Clone + Send + 'static,
+    Req: std::fmt::Debug + Clone + Send + Sync + 'static,
+    Resp: std::fmt::Debug + Clone + Send + Sync + 'static,
+    GrpcReq: serde::Serialize,
+    GrpcResp: serde::Serialize,
+    F: FnOnce(RouterData<T, Req, Resp>, GrpcReq) -> Fut + Send,
+    Fut: std::future::Future<Output = RouterResult<(RouterData<T, Req, Resp>, GrpcResp)>> + Send,
+{
+    tracing::Span::current().record("connector_name", &router_data.connector);
+    tracing::Span::current().record("flow_type", std::any::type_name::<T>());
+    tracing::Span::current().record("payment_id", &router_data.payment_id);
+
+    // Capture request data for logging
+    let connector_name = router_data.connector.clone();
+    let payment_id = router_data.payment_id.clone();
+    let merchant_id = router_data.merchant_id.clone();
+    let refund_id = router_data.refund_id.clone();
+    let dispute_id = router_data.dispute_id.clone();
+
+    // Log the actual gRPC request with masking
+    let grpc_request_body = masking::masked_serialize(&grpc_request)
+        .unwrap_or_else(|_| serde_json::json!({"error": "failed_to_serialize_grpc_request"}));
+
+    // Update connector call count metrics for UCS operations
+    crate::routes::metrics::CONNECTOR_CALL_COUNT.add(
+        1,
+        router_env::metric_attributes!(
+            ("connector", connector_name.clone()),
+            (
+                "flow",
+                std::any::type_name::<T>()
+                    .split("::")
+                    .last()
+                    .unwrap_or_default()
+            ),
+        ),
+    );
+
+    // Execute UCS function and measure timing
+    let start_time = Instant::now();
+    let result = handler(router_data, grpc_request).await;
+    let external_latency = start_time.elapsed().as_millis();
+
+    // Create and emit connector event after UCS call
+    let (status_code, response_body, router_result) = match result {
+        Ok((updated_router_data, grpc_response)) => {
+            let status = updated_router_data
+                .connector_http_status_code
+                .unwrap_or(200);
+
+            // Log the actual gRPC response
+            let grpc_response_body = serde_json::to_value(&grpc_response).unwrap_or_else(
+                |_| serde_json::json!({"error": "failed_to_serialize_grpc_response"}),
+            );
+
+            (status, Some(grpc_response_body), Ok(updated_router_data))
+        }
+        Err(error) => {
+            // Update error metrics for UCS calls
+            crate::routes::metrics::CONNECTOR_ERROR_RESPONSE_COUNT.add(
+                1,
+                router_env::metric_attributes!(("connector", connector_name.clone(),)),
+            );
+
+            let error_body = serde_json::json!({
+                "error": error.to_string(),
+                "error_type": "ucs_call_failed"
+            });
+            (500, Some(error_body), Err(error))
+        }
+    };
+
+    let mut connector_event = ConnectorEvent::new(
+        state.tenant.tenant_id.clone(),
+        connector_name,
+        std::any::type_name::<T>(),
+        grpc_request_body,
+        "grpc://unified-connector-service".to_string(),
+        common_utils::request::Method::Post,
+        payment_id,
+        merchant_id,
+        state.request_id.as_ref(),
+        external_latency,
+        refund_id,
+        dispute_id,
+        status_code,
+    );
+
+    // Set response body based on status code
+    if let Some(body) = response_body {
+        match status_code {
+            400..=599 => {
+                connector_event.set_error_response_body(&body);
+            }
+            _ => {
+                connector_event.set_response_body(&body);
+            }
+        }
+    }
+
+    // Emit event
+    state.event_handler.log_event(&connector_event);
+
+    router_result
+}

## Type of Change
<!-- Put an `x` in the boxes that apply -->
- [ ] Bugfix
- [x] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD
## Description
<!-- Describe your changes in detail -->
Added comprehensive event logging for UCS operations to improve debugging and monitoring. The changes wrap UCS calls with structured logging that captures request/response data, timing, and errors across all payment flows.
### 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)?
-->
Enable UCS
```
curl --location 'http://localhost:8080/configs/' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--data '
{
    "key": "ucs_enabled",
    "value": "true"
}'
```
Enable UCS authorize
```curl --location 'http://localhost:8080/configs/' \
--header 'api-key: test_admin' \
--header 'Content-Type: application/json' \
--header 'Authorization: api-key=dev_ya18hWOxWbhNjQWEacOVLAFiqOuhSsU3k53o5iyEK6IcxQohWPAMpCWGURyRSRYc' \
--data '{
      "key": "ucs_rollout_config_merchant_1756126931_razorpay_upi_Authorize",
      "value": "1.0"
  }'
```
Payments - Create
```curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_Qaanra9EEOfvCZtfveDCXQbYgnzJF7vgwIqBiERdn510eGS9M49jmIZweYS5zC7y' \
--data-raw '{
  "amount": 100,
  "currency": "INR",
  "confirm": true,
  "capture_method": "automatic",
  "capture_on": "2022-09-10T10:11:12Z",
  "customer_id": "IatapayCustomer",
  "email": "[guest@example.com](mailto:guest@example.com)",
  "name": "John Doe",
  "phone": "999999999",
  "phone_country_code": "+1",
  "description": "Its my first payment request",
  "authentication_type": "no_three_ds",
  "return_url": "https://google.com/",
  "payment_method": "upi",
  "payment_method_type": "upi_collect",
  "payment_method_data": {
    "upi": {
      "upi_collect": {
      "vpa_id": "success@razorpay"
      }
    },
    "billing": {
            "address": {
                "line1": "1467",
                "line2": "Harrison Street",
                "line3": "Harrison Street",
                "city": "San Fransico",
                "state": "California",
                "zip": "94122",
                "country": "IN",
                "first_name": "Swangi",
                "last_name": "Kumari"
            },
            "phone": {
                "number": "8056594427",
                "country_code": "+91"
            },
            "email": "[swangi.kumari@juspay.in](mailto:swangi.kumari@juspay.in)"
        }
  },
  "billing": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "IN",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "shipping": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "statement_descriptor_name": "joseph",
  "statement_descriptor_suffix": "JS",
  "metadata": {
    "udf1": "value1",
    "new_customer": "true",
    "login_date": "2019-09-10T10:11:12Z"
  },
  "all_keys_required": true
}'
```
Logs (Success)
<img width="1253" height="411" alt="Screenshot 2025-08-28 at 2 46 00 PM" src="https://github.com/user-attachments/assets/4fff5e2e-233a-4e42-a3f9-e13c66594808" />
Logs(Failure)
<img width="1207" height="503" alt="Screenshot 2025-08-25 at 6 37 32 PM" src="https://github.com/user-attachments/assets/6b6f8596-a879-41d4-98ea-2e945376cbe2" />
## 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