Bug: [BUG] Failed payment for Cashtocode via UCS returns status requires_merchant_action



### Bug Description

In UCS when we get None as attempt status we map it to payments_grpc::PaymentStatus::AttemptStatusUnspecified.

In payments via Unified Connector Service path, when for error responses it returned attempt_status_unspecified, it was being mapped to AttemptStatus::Unresolved instead of None. This prevented the proper failure handling logic from executing, causing payments that should fail to not return the expected failure status.

### Expected Behavior

Failed payments should return failed status

### Actual Behavior

Failed payments gave requires_merchant_action status

### Steps To Reproduce

Make a payment for cashtocode via UCS with wrong currency/creds.

### Context For The Bug

_No response_

### Environment

macos sequoia
rustc 1.87.0


### Have you spent some time checking if this bug has been raised before?

- [x] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [x] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs
index 031fd0de7ce..93f7339b954 100644
--- a/crates/router/src/core/payments/flows/authorize_flow.rs
+++ b/crates/router/src/core/payments/flows/authorize_flow.rs
@@ -888,14 +888,17 @@ async fn call_unified_connector_service_authorize(
 
             let payment_authorize_response = response.into_inner();
 
-            let (status, router_data_response, status_code) =
+            let (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;
+            let router_data_response = router_data_response.map(|(response, status)| {
+                router_data.status = status;
+                response
+            });
             router_data.response = router_data_response;
             router_data.raw_connector_response = payment_authorize_response
                 .raw_connector_response
@@ -972,14 +975,17 @@ async fn call_unified_connector_service_repeat_payment(
 
             let payment_repeat_response = response.into_inner();
 
-            let (status, router_data_response, status_code) =
+            let (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;
+            let router_data_response = router_data_response.map(|(response, status)| {
+                router_data.status = status;
+                response
+            });
             router_data.response = router_data_response;
             router_data.raw_connector_response = payment_repeat_response
                 .raw_connector_response
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 fca6c1d3c03..42482131610 100644
--- a/crates/router/src/core/payments/flows/external_proxy_flow.rs
+++ b/crates/router/src/core/payments/flows/external_proxy_flow.rs
@@ -428,14 +428,17 @@ impl Feature<api::ExternalVaultProxy, types::ExternalVaultProxyPaymentsData>
 
                 let payment_authorize_response = response.into_inner();
 
-                let (status, router_data_response, status_code) =
+                let (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;
+                let router_data_response = router_data_response.map(|(response, status)|{
+                    router_data.status = status;
+                    response
+                });
                 router_data.response = router_data_response;
                 router_data.raw_connector_response = payment_authorize_response
                     .raw_connector_response
diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs
index 9683129ca97..404d14923da 100644
--- a/crates/router/src/core/payments/flows/psync_flow.rs
+++ b/crates/router/src/core/payments/flows/psync_flow.rs
@@ -295,14 +295,17 @@ impl Feature<api::PSync, types::PaymentsSyncData>
 
                 let payment_get_response = response.into_inner();
 
-                let (status, router_data_response, status_code) =
+                let (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;
+                let router_data_response = router_data_response.map(|(response, status)| {
+                    router_data.status = status;
+                    response
+                });
                 router_data.response = router_data_response;
                 router_data.raw_connector_response = payment_get_response
                     .raw_connector_response
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 6e30faf7143..3831ac09ba0 100644
--- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs
+++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs
@@ -317,14 +317,17 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
 
                 let payment_register_response = response.into_inner();
 
-                let (status, router_data_response, status_code) =
+                let (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;
+                let router_data_response = router_data_response.map(|(response, status)| {
+                    router_data.status = status;
+                    response
+                });
                 router_data.response = router_data_response;
                 router_data.connector_http_status_code = Some(status_code);
 
diff --git a/crates/router/src/core/unified_connector_service.rs b/crates/router/src/core/unified_connector_service.rs
index 3792cfa280e..62f72860d09 100644
--- a/crates/router/src/core/unified_connector_service.rs
+++ b/crates/router/src/core/unified_connector_service.rs
@@ -55,6 +55,15 @@ pub mod transformers;
 // Re-export webhook transformer types for easier access
 pub use transformers::WebhookTransformData;
 
+/// Type alias for return type used by unified connector service response handlers
+type UnifiedConnectorServiceResult = CustomResult<
+    (
+        Result<(PaymentsResponseData, AttemptStatus), ErrorResponse>,
+        u16,
+    ),
+    UnifiedConnectorServiceError,
+>;
+
 /// Generic version of should_call_unified_connector_service that works with any type
 /// implementing OperationSessionGetters trait
 pub async fn should_call_unified_connector_service<F: Clone, T, D>(
@@ -570,82 +579,46 @@ pub fn build_unified_connector_service_external_vault_proxy_metadata(
 
 pub fn handle_unified_connector_service_response_for_payment_authorize(
     response: PaymentServiceAuthorizeResponse,
-) -> CustomResult<
-    (
-        AttemptStatus,
-        Result<PaymentsResponseData, ErrorResponse>,
-        u16,
-    ),
-    UnifiedConnectorServiceError,
-> {
-    let status = AttemptStatus::foreign_try_from(response.status())?;
-
+) -> UnifiedConnectorServiceResult {
     let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
 
     let router_data_response =
-        Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
+        Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
 
-    Ok((status, router_data_response, status_code))
+    Ok((router_data_response, status_code))
 }
 
 pub fn handle_unified_connector_service_response_for_payment_get(
     response: payments_grpc::PaymentServiceGetResponse,
-) -> CustomResult<
-    (
-        AttemptStatus,
-        Result<PaymentsResponseData, ErrorResponse>,
-        u16,
-    ),
-    UnifiedConnectorServiceError,
-> {
-    let status = AttemptStatus::foreign_try_from(response.status())?;
-
+) -> UnifiedConnectorServiceResult {
     let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
 
     let router_data_response =
-        Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
+        Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
 
-    Ok((status, router_data_response, status_code))
+    Ok((router_data_response, status_code))
 }
 
 pub fn handle_unified_connector_service_response_for_payment_register(
     response: payments_grpc::PaymentServiceRegisterResponse,
-) -> CustomResult<
-    (
-        AttemptStatus,
-        Result<PaymentsResponseData, ErrorResponse>,
-        u16,
-    ),
-    UnifiedConnectorServiceError,
-> {
-    let status = AttemptStatus::foreign_try_from(response.status())?;
-
+) -> UnifiedConnectorServiceResult {
     let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
 
     let router_data_response =
-        Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
+        Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
 
-    Ok((status, router_data_response, status_code))
+    Ok((router_data_response, status_code))
 }
 
 pub fn handle_unified_connector_service_response_for_payment_repeat(
     response: payments_grpc::PaymentServiceRepeatEverythingResponse,
-) -> CustomResult<
-    (
-        AttemptStatus,
-        Result<PaymentsResponseData, ErrorResponse>,
-        u16,
-    ),
-    UnifiedConnectorServiceError,
-> {
-    let status = AttemptStatus::foreign_try_from(response.status())?;
-
+) -> UnifiedConnectorServiceResult {
     let status_code = transformers::convert_connector_service_status_code(response.status_code)?;
 
     let router_data_response =
-        Result::<PaymentsResponseData, ErrorResponse>::foreign_try_from(response)?;
+        Result::<(PaymentsResponseData, AttemptStatus), ErrorResponse>::foreign_try_from(response)?;
 
-    Ok((status, router_data_response, status_code))
+    Ok((router_data_response, status_code))
 }
 
 pub fn build_webhook_secrets_from_merchant_connector_account(
diff --git a/crates/router/src/core/unified_connector_service/transformers.rs b/crates/router/src/core/unified_connector_service/transformers.rs
index b7dc46788c5..70d0ee40bdc 100644
--- a/crates/router/src/core/unified_connector_service/transformers.rs
+++ b/crates/router/src/core/unified_connector_service/transformers.rs
@@ -512,15 +512,13 @@ impl ForeignTryFrom<&RouterData<Authorize, PaymentsAuthorizeData, PaymentsRespon
 }
 
 impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
-    for Result<PaymentsResponseData, ErrorResponse>
+    for Result<(PaymentsResponseData, AttemptStatus), 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
@@ -573,12 +571,17 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
         let status_code = convert_connector_service_status_code(response.status_code)?;
 
         let response = if response.error_code.is_some() {
+            let attempt_status = match response.status() {
+                payments_grpc::PaymentStatus::AttemptStatusUnspecified => None,
+                _ => Some(AttemptStatus::foreign_try_from(response.status())?),
+            };
+
             Err(ErrorResponse {
                 code: response.error_code().to_owned(),
                 message: response.error_message().to_owned(),
                 reason: Some(response.error_message().to_owned()),
                 status_code,
-                attempt_status: Some(status),
+                attempt_status,
                 connector_transaction_id: connector_response_reference_id,
                 network_decline_code: None,
                 network_advice_code: None,
@@ -586,16 +589,21 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
                 connector_metadata: None,
             })
         } else {
-            Ok(PaymentsResponseData::TransactionResponse {
-                resource_id,
-                redirection_data: Box::new(redirection_data),
-                mandate_reference: Box::new(None),
-                connector_metadata,
-                network_txn_id: response.network_txn_id.clone(),
-                connector_response_reference_id,
-                incremental_authorization_allowed: response.incremental_authorization_allowed,
-                charges: None,
-            })
+            let status = AttemptStatus::foreign_try_from(response.status())?;
+
+            Ok((
+                PaymentsResponseData::TransactionResponse {
+                    resource_id,
+                    redirection_data: Box::new(redirection_data),
+                    mandate_reference: Box::new(None),
+                    connector_metadata,
+                    network_txn_id: response.network_txn_id.clone(),
+                    connector_response_reference_id,
+                    incremental_authorization_allowed: response.incremental_authorization_allowed,
+                    charges: None,
+                },
+                status,
+            ))
         };
 
         Ok(response)
@@ -603,15 +611,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceAuthorizeResponse>
 }
 
 impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
-    for Result<PaymentsResponseData, ErrorResponse>
+    for Result<(PaymentsResponseData, AttemptStatus), 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
@@ -635,12 +641,17 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
         };
 
         let response = if response.error_code.is_some() {
+            let attempt_status = match response.status() {
+                payments_grpc::PaymentStatus::AttemptStatusUnspecified => None,
+                _ => Some(AttemptStatus::foreign_try_from(response.status())?),
+            };
+
             Err(ErrorResponse {
                 code: response.error_code().to_owned(),
                 message: response.error_message().to_owned(),
                 reason: Some(response.error_message().to_owned()),
                 status_code,
-                attempt_status: Some(status),
+                attempt_status,
                 connector_transaction_id: connector_response_reference_id,
                 network_decline_code: None,
                 network_advice_code: None,
@@ -648,23 +659,28 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
                 connector_metadata: None,
             })
         } else {
-            Ok(PaymentsResponseData::TransactionResponse {
-                resource_id,
-                redirection_data: Box::new(None),
-                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.clone(),
-                connector_response_reference_id,
-                incremental_authorization_allowed: None,
-                charges: None,
-            })
+            let status = AttemptStatus::foreign_try_from(response.status())?;
+
+            Ok((
+                PaymentsResponseData::TransactionResponse {
+                    resource_id,
+                    redirection_data: Box::new(None),
+                    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.clone(),
+                    connector_response_reference_id,
+                    incremental_authorization_allowed: None,
+                    charges: None,
+                },
+                status,
+            ))
         };
 
         Ok(response)
@@ -672,15 +688,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceGetResponse>
 }
 
 impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
-    for Result<PaymentsResponseData, ErrorResponse>
+    for Result<(PaymentsResponseData, AttemptStatus), 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
@@ -698,12 +712,16 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
         let status_code = convert_connector_service_status_code(response.status_code)?;
 
         let response = if response.error_code.is_some() {
+            let attempt_status = match response.status() {
+                payments_grpc::PaymentStatus::AttemptStatusUnspecified => None,
+                _ => Some(AttemptStatus::foreign_try_from(response.status())?),
+            };
             Err(ErrorResponse {
                 code: response.error_code().to_owned(),
                 message: response.error_message().to_owned(),
                 reason: Some(response.error_message().to_owned()),
                 status_code,
-                attempt_status: Some(status),
+                attempt_status,
                 connector_transaction_id: connector_response_reference_id,
                 network_decline_code: None,
                 network_advice_code: None,
@@ -711,7 +729,9 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
                 connector_metadata: None,
             })
         } else {
-            Ok(PaymentsResponseData::TransactionResponse {
+            let status = AttemptStatus::foreign_try_from(response.status())?;
+
+            Ok((PaymentsResponseData::TransactionResponse {
                 resource_id: response.registration_id.as_ref().and_then(|identifier| {
                     identifier
                         .id_type
@@ -748,7 +768,7 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
                 connector_response_reference_id,
                 incremental_authorization_allowed: response.incremental_authorization_allowed,
                 charges: None,
-            })
+            }, status))
         };
 
         Ok(response)
@@ -756,15 +776,13 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRegisterResponse>
 }
 
 impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
-    for Result<PaymentsResponseData, ErrorResponse>
+    for Result<(PaymentsResponseData, AttemptStatus), 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
@@ -790,12 +808,16 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
         let status_code = convert_connector_service_status_code(response.status_code)?;
 
         let response = if response.error_code.is_some() {
+            let attempt_status = match response.status() {
+                payments_grpc::PaymentStatus::AttemptStatusUnspecified => None,
+                _ => Some(AttemptStatus::foreign_try_from(response.status())?),
+            };
             Err(ErrorResponse {
                 code: response.error_code().to_owned(),
                 message: response.error_message().to_owned(),
                 reason: Some(response.error_message().to_owned()),
                 status_code,
-                attempt_status: Some(status),
+                attempt_status,
                 connector_transaction_id: transaction_id,
                 network_decline_code: None,
                 network_advice_code: None,
@@ -803,7 +825,9 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
                 connector_metadata: None,
             })
         } else {
-            Ok(PaymentsResponseData::TransactionResponse {
+            let status = AttemptStatus::foreign_try_from(response.status())?;
+
+            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,
@@ -815,7 +839,7 @@ impl ForeignTryFrom<payments_grpc::PaymentServiceRepeatEverythingResponse>
                 connector_response_reference_id,
                 incremental_authorization_allowed: None,
                 charges: None,
-            })
+            }, status))
         };
 
         Ok(response)
diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs
index 0fd012e9f7a..d627a3c04cb 100644
--- a/crates/router/src/services/api.rs
+++ b/crates/router/src/services/api.rs
@@ -170,7 +170,7 @@ where
         }
     }?;
 
-    let (status, router_data_response, status_code) =
+    let (router_data_response, status_code) =
         unified_connector_service::handle_unified_connector_service_response_for_payment_get(
             payment_get_response.clone(),
         )
@@ -178,7 +178,10 @@ where
         .attach_printable("Failed to process UCS webhook response using PSync handler")?;
 
     let mut updated_router_data = router_data;
-    updated_router_data.status = status;
+    let router_data_response = router_data_response.map(|(response, status)| {
+        updated_router_data.status = status;
+        response
+    });
 
     let _ = router_data_response.map_err(|error_response| {
         updated_router_data.response = Err(error_response);

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

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

## Description
<!-- Describe your changes in detail -->
In UCS when we get None as attempt status we map it to `payments_grpc::PaymentStatus::AttemptStatusUnspecified`.

In payments via Unified Connector Service  path, when for error responses it returned `attempt_status_unspecified`, it was being mapped to `AttemptStatus::Unresolved` instead of `None`. This prevented the proper failure handling logic from executing, causing payments that should fail to not return the expected failure status.

FIX:
- Changed the mapping of `payments_grpc::PaymentStatus::AttemptStatusUnspecified` from `Ok(Self::Unresolved)` to `Ok(None)` in case of Errorresponse.
- Wrapped Attemptstatus in Ok response and router_data.status is updated in case of Ok response only.
- Allows proper failure logic to execute instead of forcing payments to Unresolved state


### 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
In UCS when we get None as attempt status we map it to `payments_grpc::PaymentStatus::AttemptStatusUnspecified`.

In payments via Unified Connector Service  path, when for error responses it returned `attempt_status_unspecified`, it was being mapped to `AttemptStatus::Unresolved` instead of `None`. This prevented the proper failure handling logic from executing, causing payments that should fail to not return the expected failure status.
<!--
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?
Make a payment via UCS for cashtocode which should fail.(Wrong currency/pmt combination EUR+Evoucher)
Request
```json
{
    "amount": 1000,
    "currency": "EUR",
    "confirm": true,
    "payment_method_data": "reward",
    "payment_method_type": "evoucher",
    "payment_method":"reward",  
    "capture_method": "automatic",
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Safari/605.1.15",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "en-US",
        "color_depth": 24,
        "screen_height": 1117,
        "screen_width": 1728,
        "time_zone": -330,
        "java_enabled": true,
        "java_script_enabled": true
    },
    "customer_id": "cus_5ZiQdWmdv9efuLCPWeoN",
    "email": "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://www.google.com",
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "sundari"
        },
        "phone": {
            "number": "1233456789",
            "country_code": "+1"
        }
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "sundari"
        },
        "phone": {
            "number": "1233456789",
            "country_code": "+1"
        }
    }    
}
```

Response
```json
{
    "payment_id": "pay_eOOvKUOzk8dfmIILn2kg",
    "merchant_id": "merchant_1758217838",
    "status": "failed",
    "amount": 1000,
    "net_amount": 1000,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": "cashtocode",
    "client_secret": "pay_eOOvKUOzk8dfmIILn2kg_secret_25bCUExuNbcQIyhhU6j2",
    "created": "2025-09-22T17:14:03.089Z",
    "currency": "USD",
    "customer_id": "cus_5ZiQdWmdv9efuLCPWeoN",
    "customer": {
        "id": "cus_5ZiQdWmdv9efuLCPWeoN",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "reward",
    "payment_method_data": "reward",
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "sundari",
            "last_name": null,
            "origin_zip": null
        },
        "phone": {
            "number": "1233456789",
            "country_code": "+1"
        },
        "email": null
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "sundari",
            "last_name": null,
            "origin_zip": null
        },
        "phone": {
            "number": "1233456789",
            "country_code": "+1"
        },
        "email": null
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://www.google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": "\"bad_request\"",
    "error_message": "Validation errors occured while creating/updating paytoken",
    "unified_code": "UE_9000",
    "unified_message": "Something went wrong",
    "payment_experience": null,
    "payment_method_type": "evoucher",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cus_5ZiQdWmdv9efuLCPWeoN",
        "created_at": 1758561243,
        "expires": 1758564843,
        "secret": "epk_1fcce0a1fa2f403f9a63b9e03e153e33"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": null,
        "gateway_system": "unified_connector_service"
    },
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_kOI1WKKcE3imNaYJENz3",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_tjMqk5r3abjCMBxp7WAy",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-09-22T17:29:03.089Z",
    "fingerprint": null,
    "browser_info": {
        "language": "en-US",
        "time_zone": -330,
        "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Safari/605.1.15",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1728,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 1117,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": null,
    "network_transaction_id": null,
    "payment_method_status": null,
    "updated": "2025-09-22T17:14:04.092Z",
    "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": null,
    "card_discovery": null,
    "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": "{\"errors\":[{\"message\":\"requestedUrl must be a valid URL\",\"type\":\"Validation error\",\"path\":\"requestedUrl\"},{\"message\":\"cancelUrl must be empty or a valid URL\",\"type\":\"Validation error\",\"path\":\"cancelUrl\"}],\"error\":\"bad_request\",\"error_description\":\"Validation errors occured while creating/updating paytoken\"}",
    "enable_partial_authorization": null,
    "enable_overcapture": null,
    "is_overcapture_enabled": null,
    "network_details": {
        "network_advice_code": null
    }
}
```

success case unchanged
```json
{
    "payment_id": "pay_cpaXS8mYQTM0j8WoynYq",
    "merchant_id": "merchant_1758105428",
    "status": "succeeded",
    "amount": 100,
    "net_amount": 100,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 100,
    "connector": "fiuu",
    "client_secret": "pay_cpaXS8mYQTM0j8WoynYq_secret_YV89WcIDUTqpzr7FnDA2",
    "created": "2025-09-22T17:15:24.386Z",
    "currency": "MYR",
    "customer_id": "StripeCustomer",
    "customer": {
        "id": "StripeCustomer",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1111",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "411111",
            "card_extended_bin": null,
            "card_exp_month": "12",
            "card_exp_year": "2029",
            "card_holder_name": "Max Mustermann",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "Musterhausen",
            "country": "MY",
            "line1": "Musterstr",
            "line2": "CA",
            "line3": "CA",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe",
            "origin_zip": null
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "billing": {
        "address": {
            "city": "Musterhausen",
            "country": "MY",
            "line1": "1467",
            "line2": "CA",
            "line3": "CA",
            "zip": "12345",
            "state": "California",
            "first_name": "Max",
            "last_name": "Mustermann",
            "origin_zip": null
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": "test@novalnet.de"
    },
    "order_details": null,
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "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": "StripeCustomer",
        "created_at": 1758561324,
        "expires": 1758564924,
        "secret": "epk_f470436ee1e546399b67d346f0bb3428"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": "31048203",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": null,
        "gateway_system": "unified_connector_service"
    },
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_YLnpohCCiP6L0NP2H5No",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_renfow5Kuk3DLSsizTH4",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-09-22T17:30:24.386Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "103.77.139.95",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1536,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8",
        "screen_height": 723,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": null,
    "network_transaction_id": null,
    "payment_method_status": null,
    "updated": "2025-09-22T17:15:25.498Z",
    "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": null,
    "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": "..........",
    "enable_partial_authorization": null,
    "enable_overcapture": null,
    "is_overcapture_enabled": null,
    "network_details": null
}
```
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [ ] I formatted the code `cargo +nightly fmt --all`
- [ ] I addressed lints thrown by `cargo clippy`
- [ ] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
