Bug: [FEATURE] nuvie : Avs,cvv check, postConfirmVoid,0$ txn



### Feature Description

Add / fix nuvie related features

### Possible Implementation

- Avs,cvv check, 
- postConfirmVoid
- 0$ txn

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

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

### Have you read the Contributing Guidelines?

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

### Are you willing to submit a PR?

None
diff --git a/crates/hyperswitch_connectors/src/connectors/nuvei.rs b/crates/hyperswitch_connectors/src/connectors/nuvei.rs
index 853b9fd968a..e02168e1f41 100644
--- a/crates/hyperswitch_connectors/src/connectors/nuvei.rs
+++ b/crates/hyperswitch_connectors/src/connectors/nuvei.rs
@@ -18,13 +18,13 @@ use hyperswitch_domain_models::{
         access_token_auth::AccessTokenAuth,
         payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
         refunds::{Execute, RSync},
-        AuthorizeSessionToken, CompleteAuthorize, PreProcessing,
+        AuthorizeSessionToken, CompleteAuthorize, PostCaptureVoid, PreProcessing,
     },
     router_request_types::{
         AccessTokenRequestData, AuthorizeSessionTokenData, CompleteAuthorizeData,
         PaymentMethodTokenizationData, PaymentsAuthorizeData, PaymentsCancelData,
-        PaymentsCaptureData, PaymentsPreProcessingData, PaymentsSessionData, PaymentsSyncData,
-        RefundsData, SetupMandateRequestData,
+        PaymentsCancelPostCaptureData, PaymentsCaptureData, PaymentsPreProcessingData,
+        PaymentsSessionData, PaymentsSyncData, RefundsData, SetupMandateRequestData,
     },
     router_response_types::{
         ConnectorInfo, PaymentMethodDetails, PaymentsResponseData, RefundsResponseData,
@@ -32,8 +32,9 @@ use hyperswitch_domain_models::{
     },
     types::{
         PaymentsAuthorizeRouterData, PaymentsAuthorizeSessionTokenRouterData,
-        PaymentsCancelRouterData, PaymentsCaptureRouterData, PaymentsCompleteAuthorizeRouterData,
-        PaymentsPreProcessingRouterData, PaymentsSyncRouterData, RefundsRouterData,
+        PaymentsCancelPostCaptureRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData,
+        PaymentsCompleteAuthorizeRouterData, PaymentsPreProcessingRouterData,
+        PaymentsSyncRouterData, RefundsRouterData,
     },
 };
 use hyperswitch_interfaces::{
@@ -131,7 +132,7 @@ impl api::RefundSync for Nuvei {}
 impl api::PaymentsCompleteAuthorize for Nuvei {}
 impl api::ConnectorAccessToken for Nuvei {}
 impl api::PaymentsPreProcessing for Nuvei {}
-
+impl api::PaymentPostCaptureVoid for Nuvei {}
 impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Nuvei {
     fn build_request(
         &self,
@@ -175,7 +176,6 @@ impl ConnectorIntegration<CompleteAuthorize, CompleteAuthorizeData, PaymentsResp
     ) -> CustomResult<RequestContent, errors::ConnectorError> {
         let meta: nuvei::NuveiMeta = utils::to_connector_meta(req.request.connector_meta.clone())?;
         let connector_req = nuvei::NuveiPaymentsRequest::try_from((req, meta.session_token))?;
-
         Ok(RequestContent::Json(Box::new(connector_req)))
     }
     fn build_request(
@@ -209,7 +209,6 @@ impl ConnectorIntegration<CompleteAuthorize, CompleteAuthorizeData, PaymentsResp
             .response
             .parse_struct("NuveiPaymentsResponse")
             .switch()?;
-
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
 
@@ -309,6 +308,90 @@ impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Nu
     }
 }
 
+impl ConnectorIntegration<PostCaptureVoid, PaymentsCancelPostCaptureData, PaymentsResponseData>
+    for Nuvei
+{
+    fn get_headers(
+        &self,
+        req: &PaymentsCancelPostCaptureRouterData,
+        connectors: &Connectors,
+    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
+        self.build_headers(req, connectors)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        _req: &PaymentsCancelPostCaptureRouterData,
+        connectors: &Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!(
+            "{}ppp/api/v1/voidTransaction.do",
+            ConnectorCommon::base_url(self, connectors)
+        ))
+    }
+
+    fn get_request_body(
+        &self,
+        req: &PaymentsCancelPostCaptureRouterData,
+        _connectors: &Connectors,
+    ) -> CustomResult<RequestContent, errors::ConnectorError> {
+        let connector_req = nuvei::NuveiVoidRequest::try_from(req)?;
+        Ok(RequestContent::Json(Box::new(connector_req)))
+    }
+
+    fn build_request(
+        &self,
+        req: &PaymentsCancelPostCaptureRouterData,
+        connectors: &Connectors,
+    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
+        let request = RequestBuilder::new()
+            .method(Method::Post)
+            .url(&types::PaymentsPostCaptureVoidType::get_url(
+                self, req, connectors,
+            )?)
+            .attach_default_headers()
+            .headers(types::PaymentsPostCaptureVoidType::get_headers(
+                self, req, connectors,
+            )?)
+            .set_body(types::PaymentsPostCaptureVoidType::get_request_body(
+                self, req, connectors,
+            )?)
+            .build();
+        Ok(Some(request))
+    }
+
+    fn handle_response(
+        &self,
+        data: &PaymentsCancelPostCaptureRouterData,
+        event_builder: Option<&mut ConnectorEvent>,
+        res: Response,
+    ) -> CustomResult<PaymentsCancelPostCaptureRouterData, errors::ConnectorError> {
+        let response: nuvei::NuveiPaymentsResponse = res
+            .response
+            .parse_struct("NuveiPaymentsResponse")
+            .switch()?;
+        event_builder.map(|i| i.set_response_body(&response));
+        router_env::logger::info!(connector_response=?response);
+        RouterData::try_from(ResponseRouterData {
+            response,
+            data: data.clone(),
+            http_code: res.status_code,
+        })
+        .change_context(errors::ConnectorError::ResponseHandlingFailed)
+    }
+
+    fn get_error_response(
+        &self,
+        res: Response,
+        event_builder: Option<&mut ConnectorEvent>,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res, event_builder)
+    }
+}
 impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Nuvei {}
 
 impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Nuvei {
@@ -509,7 +592,6 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
         _connectors: &Connectors,
     ) -> CustomResult<RequestContent, errors::ConnectorError> {
         let connector_req = nuvei::NuveiPaymentsRequest::try_from((req, req.get_session_token()?))?;
-
         Ok(RequestContent::Json(Box::new(connector_req)))
     }
 
@@ -545,7 +627,6 @@ impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData
             .response
             .parse_struct("NuveiPaymentsResponse")
             .switch()?;
-
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
 
@@ -683,7 +764,6 @@ impl ConnectorIntegration<PreProcessing, PaymentsPreProcessingData, PaymentsResp
         _connectors: &Connectors,
     ) -> CustomResult<RequestContent, errors::ConnectorError> {
         let connector_req = nuvei::NuveiPaymentsRequest::try_from((req, req.get_session_token()?))?;
-
         Ok(RequestContent::Json(Box::new(connector_req)))
     }
 
@@ -719,7 +799,6 @@ impl ConnectorIntegration<PreProcessing, PaymentsPreProcessingData, PaymentsResp
             .response
             .parse_struct("NuveiPaymentsResponse")
             .switch()?;
-
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
 
@@ -802,7 +881,6 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Nuvei {
             .response
             .parse_struct("NuveiPaymentsResponse")
             .switch()?;
-
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
 
@@ -849,33 +927,75 @@ impl IncomingWebhook for Nuvei {
         _merchant_id: &id_type::MerchantId,
         connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets,
     ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
-        let body = serde_urlencoded::from_str::<nuvei::NuveiWebhookDetails>(&request.query_params)
+        // Parse the webhook payload
+        let webhook = serde_urlencoded::from_str::<nuvei::NuveiWebhook>(&request.query_params)
             .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+
         let secret_str = std::str::from_utf8(&connector_webhook_secrets.secret)
             .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
-        let status = format!("{:?}", body.status).to_uppercase();
-        let to_sign = format!(
-            "{}{}{}{}{}{}{}",
-            secret_str,
-            body.total_amount,
-            body.currency,
-            body.response_time_stamp,
-            body.ppp_transaction_id,
-            status,
-            body.product_id
-        );
-        Ok(to_sign.into_bytes())
+
+        // Generate signature based on webhook type
+        match webhook {
+            nuvei::NuveiWebhook::PaymentDmn(notification) => {
+                // For payment DMNs, use the same format as before
+                let status = notification
+                    .transaction_status
+                    .as_ref()
+                    .map(|s| format!("{s:?}").to_uppercase())
+                    .unwrap_or_else(|| "UNKNOWN".to_string());
+
+                let to_sign = transformers::concat_strings(&[
+                    secret_str.to_string(),
+                    notification.total_amount.unwrap_or_default(),
+                    notification.currency.unwrap_or_default(),
+                    notification.response_time_stamp.unwrap_or_default(),
+                    notification.ppp_transaction_id.unwrap_or_default(),
+                    status,
+                    notification.product_id.unwrap_or_default(),
+                ]);
+                Ok(to_sign.into_bytes())
+            }
+            nuvei::NuveiWebhook::Chargeback(notification) => {
+                // For chargeback notifications, use a different format based on Nuvei's documentation
+                // Note: This is a placeholder - you'll need to adjust based on Nuvei's actual chargeback signature format
+                let status = notification
+                    .status
+                    .as_ref()
+                    .map(|s| format!("{s:?}").to_uppercase())
+                    .unwrap_or_else(|| "UNKNOWN".to_string());
+
+                let to_sign = transformers::concat_strings(&[
+                    secret_str.to_string(),
+                    notification.chargeback_amount.unwrap_or_default(),
+                    notification.chargeback_currency.unwrap_or_default(),
+                    notification.ppp_transaction_id.unwrap_or_default(),
+                    status,
+                ]);
+                Ok(to_sign.into_bytes())
+            }
+        }
     }
 
     fn get_webhook_object_reference_id(
         &self,
         request: &IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
-        let body =
-            serde_urlencoded::from_str::<nuvei::NuveiWebhookTransactionId>(&request.query_params)
-                .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+        // Parse the webhook payload
+        let webhook = serde_urlencoded::from_str::<nuvei::NuveiWebhook>(&request.query_params)
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+
+        // Extract transaction ID from the webhook
+        let transaction_id = match &webhook {
+            nuvei::NuveiWebhook::PaymentDmn(notification) => {
+                notification.ppp_transaction_id.clone().unwrap_or_default()
+            }
+            nuvei::NuveiWebhook::Chargeback(notification) => {
+                notification.ppp_transaction_id.clone().unwrap_or_default()
+            }
+        };
+
         Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
-            PaymentIdType::ConnectorTransactionId(body.ppp_transaction_id),
+            PaymentIdType::ConnectorTransactionId(transaction_id),
         ))
     }
 
@@ -883,15 +1003,29 @@ impl IncomingWebhook for Nuvei {
         &self,
         request: &IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<IncomingWebhookEvent, errors::ConnectorError> {
-        let body =
-            serde_urlencoded::from_str::<nuvei::NuveiWebhookDataStatus>(&request.query_params)
-                .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
-        match body.status {
-            nuvei::NuveiWebhookStatus::Approved => Ok(IncomingWebhookEvent::PaymentIntentSuccess),
-            nuvei::NuveiWebhookStatus::Declined => Ok(IncomingWebhookEvent::PaymentIntentFailure),
-            nuvei::NuveiWebhookStatus::Unknown
-            | nuvei::NuveiWebhookStatus::Pending
-            | nuvei::NuveiWebhookStatus::Update => Ok(IncomingWebhookEvent::EventNotSupported),
+        // Parse the webhook payload
+        let webhook = serde_urlencoded::from_str::<nuvei::NuveiWebhook>(&request.query_params)
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+
+        // Map webhook type to event type
+        match webhook {
+            nuvei::NuveiWebhook::PaymentDmn(notification) => {
+                match notification.transaction_status {
+                    Some(nuvei::TransactionStatus::Approved)
+                    | Some(nuvei::TransactionStatus::Settled) => {
+                        Ok(IncomingWebhookEvent::PaymentIntentSuccess)
+                    }
+                    Some(nuvei::TransactionStatus::Declined)
+                    | Some(nuvei::TransactionStatus::Error) => {
+                        Ok(IncomingWebhookEvent::PaymentIntentFailure)
+                    }
+                    _ => Ok(IncomingWebhookEvent::EventNotSupported),
+                }
+            }
+            nuvei::NuveiWebhook::Chargeback(_) => {
+                // Chargeback notifications always map to dispute opened
+                Ok(IncomingWebhookEvent::DisputeOpened)
+            }
         }
     }
 
@@ -899,9 +1033,12 @@ impl IncomingWebhook for Nuvei {
         &self,
         request: &IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
-        let body = serde_urlencoded::from_str::<nuvei::NuveiWebhookDetails>(&request.query_params)
+        // Parse the webhook payload
+        let webhook = serde_urlencoded::from_str::<nuvei::NuveiWebhook>(&request.query_params)
             .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
-        let payment_response = nuvei::NuveiPaymentsResponse::from(body);
+
+        // Convert webhook to payments response
+        let payment_response = nuvei::NuveiPaymentsResponse::from(webhook);
 
         Ok(Box::new(payment_response))
     }
diff --git a/crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs b/crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs
index 9cc8476a4f4..6a2e26bc056 100644
--- a/crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs
@@ -1,9 +1,10 @@
-use common_enums::enums;
+use common_enums::{enums, CaptureMethod, PaymentChannel};
 use common_utils::{
     crypto::{self, GenerateDigest},
     date_time,
     ext_traits::{Encode, OptionExt},
     fp_utils,
+    id_type::CustomerId,
     pii::{Email, IpAddress},
     request::Method,
 };
@@ -14,10 +15,13 @@ use hyperswitch_domain_models::{
         self, ApplePayWalletData, BankRedirectData, GooglePayWalletData, PayLaterData,
         PaymentMethodData, WalletData,
     },
-    router_data::{ConnectorAuthType, ErrorResponse, RouterData},
+    router_data::{
+        AdditionalPaymentMethodConnectorResponse, ConnectorAuthType, ConnectorResponseData,
+        ErrorResponse, RouterData,
+    },
     router_flow_types::{
         refunds::{Execute, RSync},
-        Authorize, Capture, CompleteAuthorize, PSync, Void,
+        Authorize, Capture, CompleteAuthorize, PSync, PostCaptureVoid, Void,
     },
     router_request_types::{
         authentication::MessageExtensionAttribute, BrowserInformation, PaymentsAuthorizeData,
@@ -41,7 +45,7 @@ use crate::{
         PaymentsPreprocessingResponseRouterData, RefundsResponseRouterData, ResponseRouterData,
     },
     utils::{
-        self, AddressDetailsData, BrowserInformationData, ForeignTryFrom,
+        self, missing_field_err, AddressDetailsData, BrowserInformationData, ForeignTryFrom,
         PaymentsAuthorizeRequestData, PaymentsCancelRequestData, PaymentsPreProcessingRequestData,
         RouterData as _,
     },
@@ -61,21 +65,26 @@ fn to_boolean(string: String) -> bool {
 trait NuveiAuthorizePreprocessingCommon {
     fn get_browser_info(&self) -> Option<BrowserInformation>;
     fn get_related_transaction_id(&self) -> Option<String>;
-    fn get_email_required(&self) -> Result<Email, error_stack::Report<errors::ConnectorError>>;
     fn get_setup_mandate_details(&self) -> Option<MandateData>;
     fn get_complete_authorize_url(&self) -> Option<String>;
+    fn get_is_moto(&self) -> Option<bool>;
     fn get_connector_mandate_id(&self) -> Option<String>;
     fn get_return_url_required(
         &self,
     ) -> Result<String, error_stack::Report<errors::ConnectorError>>;
-    fn get_capture_method(&self) -> Option<enums::CaptureMethod>;
+    fn get_capture_method(&self) -> Option<CaptureMethod>;
     fn get_amount_required(&self) -> Result<i64, error_stack::Report<errors::ConnectorError>>;
+    fn get_customer_id_required(&self) -> Option<CustomerId>;
+    fn get_email_required(&self) -> Result<Email, error_stack::Report<errors::ConnectorError>>;
     fn get_currency_required(
         &self,
     ) -> Result<enums::Currency, error_stack::Report<errors::ConnectorError>>;
     fn get_payment_method_data_required(
         &self,
     ) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>>;
+    fn get_order_tax_amount(
+        &self,
+    ) -> Result<Option<i64>, error_stack::Report<errors::ConnectorError>>;
 }
 
 impl NuveiAuthorizePreprocessingCommon for PaymentsAuthorizeData {
@@ -86,9 +95,15 @@ impl NuveiAuthorizePreprocessingCommon for PaymentsAuthorizeData {
     fn get_related_transaction_id(&self) -> Option<String> {
         self.related_transaction_id.clone()
     }
+    fn get_is_moto(&self) -> Option<bool> {
+        match self.payment_channel {
+            Some(PaymentChannel::MailOrder) | Some(PaymentChannel::TelephoneOrder) => Some(true),
+            _ => None,
+        }
+    }
 
-    fn get_email_required(&self) -> Result<Email, error_stack::Report<errors::ConnectorError>> {
-        self.get_email()
+    fn get_customer_id_required(&self) -> Option<CustomerId> {
+        self.customer_id.clone()
     }
 
     fn get_setup_mandate_details(&self) -> Option<MandateData> {
@@ -109,7 +124,7 @@ impl NuveiAuthorizePreprocessingCommon for PaymentsAuthorizeData {
         self.get_router_return_url()
     }
 
-    fn get_capture_method(&self) -> Option<enums::CaptureMethod> {
+    fn get_capture_method(&self) -> Option<CaptureMethod> {
         self.capture_method
     }
 
@@ -127,6 +142,15 @@ impl NuveiAuthorizePreprocessingCommon for PaymentsAuthorizeData {
     ) -> Result<PaymentMethodData, error_stack::Report<errors::ConnectorError>> {
         Ok(self.payment_method_data.clone())
     }
+    fn get_order_tax_amount(
+        &self,
+    ) -> Result<Option<i64>, error_stack::Report<errors::ConnectorError>> {
+        Ok(self.order_tax_amount.map(|tax| tax.get_amount_as_i64()))
+    }
+
+    fn get_email_required(&self) -> Result<Email, error_stack::Report<errors::ConnectorError>> {
+        self.get_email()
+    }
 }
 
 impl NuveiAuthorizePreprocessingCommon for PaymentsPreProcessingData {
@@ -138,10 +162,16 @@ impl NuveiAuthorizePreprocessingCommon for PaymentsPreProcessingData {
         self.related_transaction_id.clone()
     }
 
+    fn get_is_moto(&self) -> Option<bool> {
+        None
+    }
+
+    fn get_customer_id_required(&self) -> Option<CustomerId> {
+        None
+    }
     fn get_email_required(&self) -> Result<Email, error_stack::Report<errors::ConnectorError>> {
         self.get_email()
     }
-
     fn get_setup_mandate_details(&self) -> Option<MandateData> {
         self.setup_mandate_details.clone()
     }
@@ -160,7 +190,7 @@ impl NuveiAuthorizePreprocessingCommon for PaymentsPreProcessingData {
         self.get_router_return_url()
     }
 
-    fn get_capture_method(&self) -> Option<enums::CaptureMethod> {
+    fn get_capture_method(&self) -> Option<CaptureMethod> {
         self.capture_method
     }
 
@@ -183,6 +213,11 @@ impl NuveiAuthorizePreprocessingCommon for PaymentsPreProcessingData {
             .into(),
         )
     }
+    fn get_order_tax_amount(
+        &self,
+    ) -> Result<Option<i64>, error_stack::Report<errors::ConnectorError>> {
+        Ok(None)
+    }
 }
 
 #[derive(Debug, Serialize, Default, Deserialize)]
@@ -219,6 +254,11 @@ pub struct NuveiSessionResponse {
     pub client_request_id: String,
 }
 
+#[derive(Debug, Serialize, Default)]
+#[serde(rename_all = "camelCase")]
+pub struct NuvieAmountDetails {
+    total_tax: Option<String>,
+}
 #[serde_with::skip_serializing_none]
 #[derive(Debug, Serialize, Default)]
 #[serde(rename_all = "camelCase")]
@@ -231,16 +271,19 @@ pub struct NuveiPaymentsRequest {
     pub amount: String,
     pub currency: enums::Currency,
     /// This ID uniquely identifies your consumer/user in your system.
-    pub user_token_id: Option<Email>,
+    pub user_token_id: Option<CustomerId>,
+    //unique transaction id
     pub client_unique_id: String,
     pub transaction_type: TransactionType,
     pub is_rebilling: Option<String>,
     pub payment_option: PaymentOption,
-    pub device_details: Option<DeviceDetails>,
+    pub is_moto: Option<bool>,
+    pub device_details: DeviceDetails,
     pub checksum: Secret<String>,
     pub billing_address: Option<BillingAddress>,
     pub related_transaction_id: Option<String>,
     pub url_details: Option<UrlDetails>,
+    pub amount_details: Option<NuvieAmountDetails>,
 }
 
 #[derive(Debug, Serialize, Default)]
@@ -421,11 +464,24 @@ pub struct ThreeD {
     #[serde(rename = "merchantURL")]
     pub merchant_url: Option<String>,
     pub acs_url: Option<String>,
+    pub acs_challenge_mandate: Option<String>,
     pub c_req: Option<Secret<String>>,
+    pub three_d_flow: Option<String>,
+    pub external_transaction_id: Option<String>,
+    pub transaction_id: Option<String>,
+    pub three_d_reason_id: Option<String>,
+    pub three_d_reason: Option<String>,
+    pub challenge_preference_reason: Option<String>,
+    pub challenge_cancel_reason_id: Option<String>,
+    pub challenge_cancel_reason: Option<String>,
+    pub is_liability_on_issuer: Option<String>,
+    pub is_exemption_request_in_authentication: Option<String>,
+    pub flow: Option<String>,
+    pub acquirer_decision: Option<String>,
+    pub decision_reason: Option<String>,
     pub platform_type: Option<PlatformType>,
     pub v2supported: Option<String>,
     pub v2_additional_params: Option<V2AdditionalParams>,
-    pub is_liability_on_issuer: Option<LiabilityShift>,
 }
 
 #[derive(Debug, Clone, Default, Serialize, Deserialize)]
@@ -479,11 +535,16 @@ pub struct DeviceDetails {
     pub ip_address: Secret<String, IpAddress>,
 }
 
-impl From<enums::CaptureMethod> for TransactionType {
-    fn from(value: enums::CaptureMethod) -> Self {
-        match value {
-            enums::CaptureMethod::Manual => Self::Auth,
-            _ => Self::Sale,
+impl TransactionType {
+    fn get_from_capture_method_and_amount_string(
+        capture_method: CaptureMethod,
+        amount: &str,
+    ) -> Self {
+        let amount_value = amount.parse::<f64>();
+        if capture_method == CaptureMethod::Manual || amount_value == Ok(0.0) {
+            Self::Auth
+        } else {
+            Self::Sale
         }
     }
 }
@@ -514,12 +575,14 @@ pub enum LiabilityShift {
     Failed,
 }
 
-fn encode_payload(payload: &[&str]) -> Result<String, error_stack::Report<errors::ConnectorError>> {
+pub fn encode_payload(
+    payload: &[&str],
+) -> Result<String, error_stack::Report<errors::ConnectorError>> {
     let data = payload.join("");
     let digest = crypto::Sha256
         .generate_digest(data.as_bytes())
         .change_context(errors::ConnectorError::RequestEncodingFailed)
-        .attach_printable("error encoding the payload")?;
+        .attach_printable("error encoding nuvie payload")?;
     Ok(hex::encode(digest))
 }
 
@@ -874,7 +937,7 @@ where
         .get_billing()?
         .address
         .as_ref()
-        .ok_or_else(utils::missing_field_err("billing.address"))?;
+        .ok_or_else(missing_field_err("billing.address"))?;
     let first_name = address.get_first_name()?;
     let payment_method = payment_method_type;
     Ok(NuveiPaymentsRequest {
@@ -1041,9 +1104,16 @@ where
             ..Default::default()
         })?;
         let return_url = item.request.get_return_url_required()?;
+
+        let amount_details = match item.request.get_order_tax_amount()? {
+            Some(tax) => Some(NuvieAmountDetails {
+                total_tax: Some(utils::to_currency_base_unit(tax, currency)?),
+            }),
+            None => None,
+        };
         Ok(Self {
             is_rebilling: request_data.is_rebilling,
-            user_token_id: request_data.user_token_id,
+            user_token_id: item.customer_id.clone(),
             related_transaction_id: request_data.related_transaction_id,
             payment_option: request_data.payment_option,
             billing_address: request_data.billing_address,
@@ -1051,8 +1121,10 @@ where
             url_details: Some(UrlDetails {
                 success_url: return_url.clone(),
                 failure_url: return_url.clone(),
-                pending_url: return_url,
+                pending_url: return_url.clone(),
             }),
+            amount_details,
+
             ..request
         })
     }
@@ -1105,7 +1177,7 @@ where
                     }
                 };
                 let mandate_meta: NuveiMandateMeta = utils::to_connector_meta_from_secret(Some(
-                    details.get_metadata().ok_or_else(utils::missing_field_err(
+                    details.get_metadata().ok_or_else(missing_field_err(
                         "mandate_data.mandate_type.{multi_use|single_use}.metadata",
                     ))?,
                 ))?;
@@ -1116,14 +1188,14 @@ where
                             details
                                 .get_end_date(date_time::DateFormat::YYYYMMDD)
                                 .change_context(errors::ConnectorError::DateFormattingFailed)?
-                                .ok_or_else(utils::missing_field_err(
+                                .ok_or_else(missing_field_err(
                                     "mandate_data.mandate_type.{multi_use|single_use}.end_date",
                                 ))?,
                         ),
                         rebill_frequency: Some(mandate_meta.frequency),
                         challenge_window_size: None,
                     }),
-                    Some(item.request.get_email_required()?),
+                    item.request.get_customer_id_required(),
                 )
             }
             _ => (None, None, None),
@@ -1159,20 +1231,19 @@ where
     } else {
         None
     };
-
+    let is_moto = item.request.get_is_moto();
     Ok(NuveiPaymentsRequest {
         related_transaction_id,
         is_rebilling,
         user_token_id,
-        device_details: Option::<DeviceDetails>::foreign_try_from(
-            &item.request.get_browser_info().clone(),
-        )?,
+        device_details: DeviceDetails::foreign_try_from(&item.request.get_browser_info().clone())?,
         payment_option: PaymentOption::from(NuveiCardDetails {
             card: card_details.clone(),
             three_d,
             card_holder_name: item.get_optional_billing_full_name(),
         }),
         billing_address,
+        is_moto,
         ..Default::default()
     })
 }
@@ -1265,16 +1336,17 @@ impl TryFrom<NuveiPaymentRequestData> for NuveiPaymentsRequest {
             date_time::format_date(date_time::now(), date_time::DateFormat::YYYYMMDDHHmmss)
                 .change_context(errors::ConnectorError::RequestEncodingFailed)?;
         let merchant_secret = connector_meta.merchant_secret;
+        let transaction_type = TransactionType::get_from_capture_method_and_amount_string(
+            request.capture_method.unwrap_or_default(),
+            &request.amount,
+        );
         Ok(Self {
             merchant_id: merchant_id.clone(),
             merchant_site_id: merchant_site_id.clone(),
             client_request_id: Secret::new(client_request_id.clone()),
             time_stamp: time_stamp.clone(),
             session_token,
-            transaction_type: request
-                .capture_method
-                .map(TransactionType::from)
-                .unwrap_or_default(),
+            transaction_type,
             checksum: Secret::new(encode_payload(&[
                 merchant_id.peek(),
                 merchant_site_id.peek(),
@@ -1285,6 +1357,7 @@ impl TryFrom<NuveiPaymentRequestData> for NuveiPaymentsRequest {
                 merchant_secret.peek(),
             ])?),
             amount: request.amount,
+            user_token_id: None,
             currency: request.currency,
             ..Default::default()
         })
@@ -1332,7 +1405,7 @@ pub struct NuveiPaymentRequestData {
     pub client_request_id: String,
     pub connector_auth_type: ConnectorAuthType,
     pub session_token: Secret<String>,
-    pub capture_method: Option<enums::CaptureMethod>,
+    pub capture_method: Option<CaptureMethod>,
 }
 
 impl TryFrom<&types::PaymentsCaptureRouterData> for NuveiPaymentFlowRequest {
@@ -1378,6 +1451,57 @@ impl TryFrom<&types::PaymentsSyncRouterData> for NuveiPaymentSyncRequest {
     }
 }
 
+#[derive(Debug, Serialize, Default)]
+#[serde(rename_all = "camelCase")]
+pub struct NuveiVoidRequest {
+    pub merchant_id: Secret<String>,
+    pub merchant_site_id: Secret<String>,
+    pub client_unique_id: String,
+    pub related_transaction_id: String,
+    pub time_stamp: String,
+    pub checksum: Secret<String>,
+    pub client_request_id: String,
+}
+
+impl TryFrom<&types::PaymentsCancelPostCaptureRouterData> for NuveiVoidRequest {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(item: &types::PaymentsCancelPostCaptureRouterData) -> Result<Self, Self::Error> {
+        let connector_meta: NuveiAuthType = NuveiAuthType::try_from(&item.connector_auth_type)?;
+        let merchant_id = connector_meta.merchant_id.clone();
+        let merchant_site_id = connector_meta.merchant_site_id.clone();
+        let merchant_secret = connector_meta.merchant_secret.clone();
+        let client_unique_id = item.connector_request_reference_id.clone();
+        let related_transaction_id = item.request.connector_transaction_id.clone();
+        let client_request_id = item.connector_request_reference_id.clone();
+        let time_stamp =
+            date_time::format_date(date_time::now(), date_time::DateFormat::YYYYMMDDHHmmss)
+                .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        let checksum = Secret::new(encode_payload(&[
+            merchant_id.peek(),
+            merchant_site_id.peek(),
+            &client_request_id,
+            &client_unique_id,
+            "", // amount (empty for void)
+            "", // currency (empty for void)
+            &related_transaction_id,
+            "", // authCode (empty)
+            "", // comment (empty)
+            &time_stamp,
+            merchant_secret.peek(),
+        ])?);
+
+        Ok(Self {
+            merchant_id,
+            merchant_site_id,
+            client_unique_id,
+            related_transaction_id,
+            time_stamp,
+            checksum,
+            client_request_id,
+        })
+    }
+}
+
 impl TryFrom<&types::PaymentsCancelRouterData> for NuveiPaymentFlowRequest {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(item: &types::PaymentsCancelRouterData) -> Result<Self, Self::Error> {
@@ -1484,9 +1608,10 @@ pub struct NuveiPaymentsResponse {
     pub merchant_site_id: Option<Secret<String>>,
     pub version: Option<String>,
     pub client_request_id: Option<String>,
+    pub merchant_advice_code: Option<String>,
 }
 
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
 pub enum NuveiTransactionType {
     Auth,
     Sale,
@@ -1503,7 +1628,29 @@ pub struct FraudDetails {
     pub final_decision: String,
 }
 
-fn get_payment_status(response: &NuveiPaymentsResponse) -> enums::AttemptStatus {
+fn get_payment_status(
+    response: &NuveiPaymentsResponse,
+    amount: Option<i64>,
+) -> enums::AttemptStatus {
+    // ZERO dollar authorization
+    if amount == Some(0) && response.transaction_type.clone() == Some(NuveiTransactionType::Auth) {
+        return match response.transaction_status.clone() {
+            Some(NuveiTransactionStatus::Approved) => enums::AttemptStatus::Charged,
+            Some(NuveiTransactionStatus::Declined) | Some(NuveiTransactionStatus::Error) => {
+                enums::AttemptStatus::AuthorizationFailed
+            }
+            Some(NuveiTransactionStatus::Pending) | Some(NuveiTransactionStatus::Processing) => {
+                enums::AttemptStatus::Pending
+            }
+            Some(NuveiTransactionStatus::Redirect) => enums::AttemptStatus::AuthenticationPending,
+            None => match response.status {
+                NuveiPaymentStatus::Failed | NuveiPaymentStatus::Error => {
+                    enums::AttemptStatus::Failure
+                }
+                _ => enums::AttemptStatus::Pending,
+            },
+        };
+    }
     match response.transaction_status.clone() {
         Some(status) => match status {
             NuveiTransactionStatus::Approved => match response.transaction_type {
@@ -1539,15 +1686,32 @@ fn get_payment_status(response: &NuveiPaymentsResponse) -> enums::AttemptStatus
 fn build_error_response<T>(
     response: &NuveiPaymentsResponse,
     http_code: u16,
-) -> Option<Result<T, ErrorResponse>> {
+) -> Option<Result<T, error_stack::Report<errors::ConnectorError>>> {
     match response.status {
         NuveiPaymentStatus::Error => Some(
-            get_error_response(response.err_code, &response.reason, http_code).map_err(|err| *err),
+            get_error_response(
+                response.err_code,
+                &response.reason,
+                http_code,
+                &response.merchant_advice_code,
+                &response.gw_error_code.map(|e| e.to_string()),
+                &response.gw_error_reason,
+            )
+            .map_err(|_err| error_stack::report!(errors::ConnectorError::ResponseHandlingFailed)),
         ),
         _ => {
             let err = Some(
-                get_error_response(response.gw_error_code, &response.gw_error_reason, http_code)
-                    .map_err(|err| *err),
+                get_error_response(
+                    response.gw_error_code,
+                    &response.gw_error_reason,
+                    http_code,
+                    &response.merchant_advice_code,
+                    &response.gw_error_code.map(|e| e.to_string()),
+                    &response.gw_error_reason,
+                )
+                .map_err(|_err| {
+                    error_stack::report!(errors::ConnectorError::ResponseHandlingFailed)
+                }),
             );
             match response.transaction_status {
                 Some(NuveiTransactionStatus::Error) | Some(NuveiTransactionStatus::Declined) => err,
@@ -1566,86 +1730,174 @@ fn build_error_response<T>(
 
 pub trait NuveiPaymentsGenericResponse {}
 
-impl NuveiPaymentsGenericResponse for Authorize {}
 impl NuveiPaymentsGenericResponse for CompleteAuthorize {}
 impl NuveiPaymentsGenericResponse for Void {}
 impl NuveiPaymentsGenericResponse for PSync {}
 impl NuveiPaymentsGenericResponse for Capture {}
+impl NuveiPaymentsGenericResponse for PostCaptureVoid {}
+
+// Helper function to process Nuvei payment response
+
+fn process_nuvei_payment_response<F, T>(
+    item: &ResponseRouterData<F, NuveiPaymentsResponse, T, PaymentsResponseData>,
+    amount: Option<i64>,
+) -> Result<
+    (
+        enums::AttemptStatus,
+        Option<RedirectForm>,
+        Option<ConnectorResponseData>,
+    ),
+    error_stack::Report<errors::ConnectorError>,
+>
+where
+    F: std::fmt::Debug,
+    T: std::fmt::Debug,
+{
+    let redirection_data = match item.data.payment_method {
+        enums::PaymentMethod::Wallet | enums::PaymentMethod::BankRedirect => item
+            .response
+            .payment_option
+            .as_ref()
+            .and_then(|po| po.redirect_url.clone())
+            .map(|base_url| RedirectForm::from((base_url, Method::Get))),
+        _ => item
+            .response
+            .payment_option
+            .as_ref()
+            .and_then(|o| o.card.clone())
+            .and_then(|card| card.three_d)
+            .and_then(|three_ds| three_ds.acs_url.zip(three_ds.c_req))
+            .map(|(base_url, creq)| RedirectForm::Form {
+                endpoint: base_url,
+                method: Method::Post,
+                form_fields: std::collections::HashMap::from([("creq".to_string(), creq.expose())]),
+            }),
+    };
+
+    let connector_response_data =
+        convert_to_additional_payment_method_connector_response(&item.response)
+            .map(ConnectorResponseData::with_additional_payment_method_data);
+
+    let status = get_payment_status(&item.response, amount);
+
+    Ok((status, redirection_data, connector_response_data))
+}
+
+// Helper function to create transaction response
+fn create_transaction_response(
+    response: &NuveiPaymentsResponse,
+    redirection_data: Option<RedirectForm>,
+    http_code: u16,
+) -> Result<PaymentsResponseData, error_stack::Report<errors::ConnectorError>> {
+    if let Some(err) = build_error_response(response, http_code) {
+        return err;
+    }
+
+    Ok(PaymentsResponseData::TransactionResponse {
+        resource_id: response
+            .transaction_id
+            .clone()
+            .map_or(response.order_id.clone(), Some) // For paypal there will be no transaction_id, only order_id will be present
+            .map(ResponseId::ConnectorTransactionId)
+            .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?,
+        redirection_data: Box::new(redirection_data),
+        mandate_reference: Box::new(
+            response
+                .payment_option
+                .as_ref()
+                .and_then(|po| po.user_payment_option_id.clone())
+                .map(|id| MandateReference {
+                    connector_mandate_id: Some(id),
+                    payment_method_id: None,
+                    mandate_metadata: None,
+                    connector_mandate_request_reference_id: None,
+                }),
+        ),
+        // we don't need to save session token for capture, void flow so ignoring if it is not present
+        connector_metadata: if let Some(token) = response.session_token.clone() {
+            Some(
+                serde_json::to_value(NuveiMeta {
+                    session_token: token,
+                })
+                .change_context(errors::ConnectorError::ResponseHandlingFailed)?,
+            )
+        } else {
+            None
+        },
+        network_txn_id: None,
+        connector_response_reference_id: response.order_id.clone(),
+        incremental_authorization_allowed: None,
+        charges: None,
+    })
+}
 
+// Specialized implementation for Authorize
+impl
+    TryFrom<
+        ResponseRouterData<
+            Authorize,
+            NuveiPaymentsResponse,
+            PaymentsAuthorizeData,
+            PaymentsResponseData,
+        >,
+    > for RouterData<Authorize, PaymentsAuthorizeData, PaymentsResponseData>
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: ResponseRouterData<
+            Authorize,
+            NuveiPaymentsResponse,
+            PaymentsAuthorizeData,
+            PaymentsResponseData,
+        >,
+    ) -> Result<Self, Self::Error> {
+        // Get amount directly from the authorize data
+        let amount = Some(item.data.request.amount);
+
+        let (status, redirection_data, connector_response_data) =
+            process_nuvei_payment_response(&item, amount)?;
+
+        Ok(Self {
+            status,
+            response: Ok(create_transaction_response(
+                &item.response,
+                redirection_data,
+                item.http_code,
+            )?),
+            connector_response: connector_response_data,
+            ..item.data
+        })
+    }
+}
+
+// Generic implementation for other flow types
 impl<F, T> TryFrom<ResponseRouterData<F, NuveiPaymentsResponse, T, PaymentsResponseData>>
     for RouterData<F, T, PaymentsResponseData>
 where
-    F: NuveiPaymentsGenericResponse,
+    F: NuveiPaymentsGenericResponse + std::fmt::Debug,
+    T: std::fmt::Debug,
+    F: std::any::Any,
 {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(
         item: ResponseRouterData<F, NuveiPaymentsResponse, T, PaymentsResponseData>,
     ) -> Result<Self, Self::Error> {
-        let redirection_data = match item.data.payment_method {
-            enums::PaymentMethod::Wallet | enums::PaymentMethod::BankRedirect => item
-                .response
-                .payment_option
-                .as_ref()
-                .and_then(|po| po.redirect_url.clone())
-                .map(|base_url| RedirectForm::from((base_url, Method::Get))),
-            _ => item
-                .response
-                .payment_option
-                .as_ref()
-                .and_then(|o| o.card.clone())
-                .and_then(|card| card.three_d)
-                .and_then(|three_ds| three_ds.acs_url.zip(three_ds.c_req))
-                .map(|(base_url, creq)| RedirectForm::Form {
-                    endpoint: base_url,
-                    method: Method::Post,
-                    form_fields: std::collections::HashMap::from([(
-                        "creq".to_string(),
-                        creq.expose(),
-                    )]),
-                }),
-        };
+        let amount = item
+            .data
+            .minor_amount_capturable
+            .map(|amount| amount.get_amount_as_i64());
+
+        let (status, redirection_data, connector_response_data) =
+            process_nuvei_payment_response(&item, amount)?;
 
-        let response = item.response;
         Ok(Self {
-            status: get_payment_status(&response),
-            response: if let Some(err) = build_error_response(&response, item.http_code) {
-                err
-            } else {
-                Ok(PaymentsResponseData::TransactionResponse {
-                    resource_id: response
-                        .transaction_id
-                        .map_or(response.order_id.clone(), Some) // For paypal there will be no transaction_id, only order_id will be present
-                        .map(ResponseId::ConnectorTransactionId)
-                        .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?,
-                    redirection_data: Box::new(redirection_data),
-                    mandate_reference: Box::new(
-                        response
-                            .payment_option
-                            .and_then(|po| po.user_payment_option_id)
-                            .map(|id| MandateReference {
-                                connector_mandate_id: Some(id),
-                                payment_method_id: None,
-                                mandate_metadata: None,
-                                connector_mandate_request_reference_id: None,
-                            }),
-                    ),
-                    // we don't need to save session token for capture, void flow so ignoring if it is not present
-                    connector_metadata: if let Some(token) = response.session_token {
-                        Some(
-                            serde_json::to_value(NuveiMeta {
-                                session_token: token,
-                            })
-                            .change_context(errors::ConnectorError::ResponseHandlingFailed)?,
-                        )
-                    } else {
-                        None
-                    },
-                    network_txn_id: None,
-                    connector_response_reference_id: response.order_id,
-                    incremental_authorization_allowed: None,
-                    charges: None,
-                })
-            },
+            status,
+            response: Ok(create_transaction_response(
+                &item.response,
+                redirection_data,
+                item.http_code,
+            )?),
+            connector_response: connector_response_data,
             ..item.data
         })
     }
@@ -1668,11 +1920,12 @@ impl TryFrom<PaymentsPreprocessingResponseRouterData<NuveiPaymentsResponse>>
             .map(to_boolean)
             .unwrap_or_default();
         Ok(Self {
-            status: get_payment_status(&response),
+            status: get_payment_status(&response, item.data.request.amount),
             response: Ok(PaymentsResponseData::ThreeDSEnrollmentResponse {
                 enrolled_v2: is_enrolled_for_3ds,
                 related_transaction_id: response.transaction_id,
             }),
+
             ..item.data
         })
     }
@@ -1697,15 +1950,17 @@ impl TryFrom<RefundsResponseRouterData<Execute, NuveiPaymentsResponse>>
     fn try_from(
         item: RefundsResponseRouterData<Execute, NuveiPaymentsResponse>,
     ) -> Result<Self, Self::Error> {
+        let transaction_id = item
+            .response
+            .transaction_id
+            .clone()
+            .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?;
+
+        let refund_response =
+            get_refund_response(item.response.clone(), item.http_code, transaction_id)?;
+
         Ok(Self {
-            response: get_refund_response(
-                item.response.clone(),
-                item.http_code,
-                item.response
-                    .transaction_id
-                    .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?,
-            )
-            .map_err(|err| *err),
+            response: Ok(refund_response),
             ..item.data
         })
     }
@@ -1718,15 +1973,17 @@ impl TryFrom<RefundsResponseRouterData<RSync, NuveiPaymentsResponse>>
     fn try_from(
         item: RefundsResponseRouterData<RSync, NuveiPaymentsResponse>,
     ) -> Result<Self, Self::Error> {
+        let transaction_id = item
+            .response
+            .transaction_id
+            .clone()
+            .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?;
+
+        let refund_response =
+            get_refund_response(item.response.clone(), item.http_code, transaction_id)?;
+
         Ok(Self {
-            response: get_refund_response(
-                item.response.clone(),
-                item.http_code,
-                item.response
-                    .transaction_id
-                    .ok_or(errors::ConnectorError::MissingConnectorTransactionID)?,
-            )
-            .map_err(|err| *err),
+            response: Ok(refund_response),
             ..item.data
         })
     }
@@ -1741,6 +1998,10 @@ where
         {
             let item = data;
             let connector_mandate_id = &item.request.get_connector_mandate_id();
+            let customer_id = item
+                .request
+                .get_customer_id_required()
+                .ok_or(missing_field_err("customer_id")())?;
             let related_transaction_id = if item.is_three_ds() {
                 item.request.get_related_transaction_id().clone()
             } else {
@@ -1748,11 +2009,11 @@ where
             };
             Ok(Self {
                 related_transaction_id,
-                device_details: Option::<DeviceDetails>::foreign_try_from(
+                device_details: DeviceDetails::foreign_try_from(
                     &item.request.get_browser_info().clone(),
                 )?,
                 is_rebilling: Some("1".to_string()), // In case of second installment, rebilling should be 1
-                user_token_id: Some(item.request.get_email_required()?),
+                user_token_id: Some(customer_id),
                 payment_option: PaymentOption {
                     user_payment_option_id: connector_mandate_id.clone(),
                     ..Default::default()
@@ -1763,16 +2024,15 @@ where
     }
 }
 
-impl ForeignTryFrom<&Option<BrowserInformation>> for Option<DeviceDetails> {
+impl ForeignTryFrom<&Option<BrowserInformation>> for DeviceDetails {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn foreign_try_from(browser_info: &Option<BrowserInformation>) -> Result<Self, Self::Error> {
-        let device_details = match browser_info {
-            Some(browser_info) => Some(DeviceDetails {
-                ip_address: browser_info.get_ip_address()?,
-            }),
-            None => None,
-        };
-        Ok(device_details)
+        let browser_info = browser_info
+            .as_ref()
+            .ok_or_else(missing_field_err("browser_info"))?;
+        Ok(Self {
+            ip_address: browser_info.get_ip_address()?,
+        })
     }
 }
 
@@ -1780,20 +2040,32 @@ fn get_refund_response(
     response: NuveiPaymentsResponse,
     http_code: u16,
     txn_id: String,
-) -> Result<RefundsResponseData, Box<ErrorResponse>> {
+) -> Result<RefundsResponseData, error_stack::Report<errors::ConnectorError>> {
     let refund_status = response
         .transaction_status
         .clone()
         .map(enums::RefundStatus::from)
         .unwrap_or(enums::RefundStatus::Failure);
     match response.status {
-        NuveiPaymentStatus::Error => {
-            get_error_response(response.err_code, &response.reason, http_code)
-        }
+        NuveiPaymentStatus::Error => get_error_response(
+            response.err_code,
+            &response.reason,
+            http_code,
+            &response.merchant_advice_code,
+            &response.gw_error_code.map(|e| e.to_string()),
+            &response.gw_error_reason,
+        )
+        .map_err(|_err| error_stack::report!(errors::ConnectorError::ResponseHandlingFailed)),
         _ => match response.transaction_status {
-            Some(NuveiTransactionStatus::Error) => {
-                get_error_response(response.gw_error_code, &response.gw_error_reason, http_code)
-            }
+            Some(NuveiTransactionStatus::Error) => get_error_response(
+                response.err_code,
+                &response.reason,
+                http_code,
+                &response.merchant_advice_code,
+                &response.gw_error_code.map(|e| e.to_string()),
+                &response.gw_error_reason,
+            )
+            .map_err(|_err| error_stack::report!(errors::ConnectorError::ResponseHandlingFailed)),
             _ => Ok(RefundsResponseData {
                 connector_refund_id: txn_id,
                 refund_status,
@@ -1806,6 +2078,9 @@ fn get_error_response<T>(
     error_code: Option<i64>,
     error_msg: &Option<String>,
     http_code: u16,
+    network_advice_code: &Option<String>,
+    network_decline_code: &Option<String>,
+    network_error_message: &Option<String>,
 ) -> Result<T, Box<ErrorResponse>> {
     Err(Box::new(ErrorResponse {
         code: error_code
@@ -1818,80 +2093,299 @@ fn get_error_response<T>(
         status_code: http_code,
         attempt_status: None,
         connector_transaction_id: None,
-        network_advice_code: None,
-        network_decline_code: None,
-        network_error_message: None,
+        network_advice_code: network_advice_code.clone(),
+        network_decline_code: network_decline_code.clone(),
+        network_error_message: network_error_message.clone(),
     }))
 }
 
-#[derive(Debug, Default, Serialize, Deserialize)]
-pub struct NuveiWebhookDetails {
-    pub ppp_status: Option<String>,
+/// Represents any possible webhook notification from Nuvei.
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(untagged)]
+pub enum NuveiWebhook {
+    PaymentDmn(PaymentDmnNotification),
+    Chargeback(ChargebackNotification),
+}
+
+/// Represents the status of a chargeback event.
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
+pub enum ChargebackStatus {
+    RetrievalRequest,
+    Chargeback,
+    Representment,
+    SecondChargeback,
+    Arbitration,
+    #[serde(other)]
+    Unknown,
+}
+
+/// Represents a Chargeback webhook notification from the Nuvei Control Panel.
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ChargebackNotification {
     #[serde(rename = "ppp_TransactionID")]
-    pub ppp_transaction_id: String,
-    #[serde(rename = "TransactionId")]
+    pub ppp_transaction_id: Option<String>,
+    pub merchant_unique_id: Option<String>,
+    pub merchant_id: Option<String>,
+    pub merchant_site_id: Option<String>,
+    pub request_version: Option<String>,
+    pub message: Option<String>,
+    pub status: Option<ChargebackStatus>,
+    pub reason: Option<String>,
+    pub case_id: Option<String>,
+    pub processor_case_id: Option<String>,
+    pub arn: Option<String>,
+    pub retrieval_request_date: Option<String>,
+    pub chargeback_date: Option<String>,
+    pub chargeback_amount: Option<String>,
+    pub chargeback_currency: Option<String>,
+    pub original_amount: Option<String>,
+    pub original_currency: Option<String>,
+    #[serde(rename = "transactionID")]
+    pub transaction_id: Option<String>,
+    pub user_token_id: Option<String>,
+}
+
+/// Represents the overall status of the DMN.
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum DmnStatus {
+    Success,
+    Error,
+    Pending,
+}
+
+/// Represents the status of the transaction itself.
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum TransactionStatus {
+    Approved,
+    Declined,
+    Error,
+    Cancelled,
+    Pending,
+    #[serde(rename = "Settle")]
+    Settled,
+}
+
+/// Represents the type of transaction.
+#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
+#[serde(rename_all = "PascalCase")]
+pub enum PaymentTransactionType {
+    Auth,
+    Sale,
+    Settle,
+    Credit,
+    Void,
+    Auth3D,
+    Sale3D,
+    Verif,
+}
+
+/// Represents a Payment Direct Merchant Notification (DMN) webhook.
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PaymentDmnNotification {
+    #[serde(rename = "PPP_TransactionID")]
+    pub ppp_transaction_id: Option<String>,
+    #[serde(rename = "TransactionID")]
     pub transaction_id: Option<String>,
-    pub userid: Option<String>,
+    pub status: Option<DmnStatus>,
+    #[serde(rename = "ErrCode")]
+    pub err_code: Option<String>,
+    #[serde(rename = "ExErrCode")]
+    pub ex_err_code: Option<String>,
+    pub desc: Option<String>,
     pub merchant_unique_id: Option<String>,
-    #[serde(rename = "customData")]
     pub custom_data: Option<String>,
-    #[serde(rename = "productId")]
-    pub product_id: String,
+    pub product_id: Option<String>,
     pub first_name: Option<String>,
     pub last_name: Option<String>,
     pub email: Option<String>,
-    #[serde(rename = "totalAmount")]
-    pub total_amount: String,
-    pub currency: String,
+    pub total_amount: Option<String>,
+    pub currency: Option<String>,
+    pub fee: Option<String>,
+    #[serde(rename = "AuthCode")]
+    pub auth_code: Option<String>,
+    pub transaction_status: Option<TransactionStatus>,
+    pub transaction_type: Option<PaymentTransactionType>,
+    #[serde(rename = "user_token_id")]
+    pub user_token_id: Option<String>,
+    #[serde(rename = "payment_method")]
+    pub payment_method: Option<String>,
     #[serde(rename = "responseTimeStamp")]
-    pub response_time_stamp: String,
-    #[serde(rename = "Status")]
-    pub status: NuveiWebhookStatus,
-    #[serde(rename = "transactionType")]
-    pub transaction_type: Option<NuveiTransactionType>,
-}
-
+    pub response_time_stamp: Option<String>,
+    #[serde(rename = "invoice_id")]
+    pub invoice_id: Option<String>,
+    #[serde(rename = "merchant_id")]
+    pub merchant_id: Option<String>,
+    #[serde(rename = "merchant_site_id")]
+    pub merchant_site_id: Option<String>,
+    #[serde(rename = "responsechecksum")]
+    pub response_checksum: Option<String>,
+    #[serde(rename = "advanceResponseChecksum")]
+    pub advance_response_checksum: Option<String>,
+}
+
+// For backward compatibility with existing code
 #[derive(Debug, Default, Serialize, Deserialize)]
 pub struct NuveiWebhookTransactionId {
     #[serde(rename = "ppp_TransactionID")]
     pub ppp_transaction_id: String,
 }
 
-#[derive(Debug, Default, Serialize, Deserialize)]
-pub struct NuveiWebhookDataStatus {
-    #[serde(rename = "Status")]
-    pub status: NuveiWebhookStatus,
+// Helper struct to extract transaction ID from either webhook type
+impl From<&NuveiWebhook> for NuveiWebhookTransactionId {
+    fn from(webhook: &NuveiWebhook) -> Self {
+        match webhook {
+            NuveiWebhook::Chargeback(notification) => Self {
+                ppp_transaction_id: notification.ppp_transaction_id.clone().unwrap_or_default(),
+            },
+            NuveiWebhook::PaymentDmn(notification) => Self {
+                ppp_transaction_id: notification.ppp_transaction_id.clone().unwrap_or_default(),
+            },
+        }
+    }
 }
 
-#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "UPPERCASE")]
-pub enum NuveiWebhookStatus {
-    Approved,
-    Declined,
-    #[default]
-    Pending,
-    Update,
-    #[serde(other)]
-    Unknown,
+// Convert webhook to payments response for further processing
+impl From<NuveiWebhook> for NuveiPaymentsResponse {
+    fn from(webhook: NuveiWebhook) -> Self {
+        match webhook {
+            NuveiWebhook::Chargeback(notification) => Self {
+                transaction_status: Some(NuveiTransactionStatus::Processing),
+                transaction_id: notification.transaction_id,
+                transaction_type: Some(NuveiTransactionType::Credit), // Using Credit as placeholder for chargeback
+                ..Default::default()
+            },
+            NuveiWebhook::PaymentDmn(notification) => {
+                let transaction_type = notification.transaction_type.map(|tt| match tt {
+                    PaymentTransactionType::Auth => NuveiTransactionType::Auth,
+                    PaymentTransactionType::Sale => NuveiTransactionType::Sale,
+                    PaymentTransactionType::Settle => NuveiTransactionType::Settle,
+                    PaymentTransactionType::Credit => NuveiTransactionType::Credit,
+                    PaymentTransactionType::Void => NuveiTransactionType::Void,
+                    PaymentTransactionType::Auth3D => NuveiTransactionType::Auth3D,
+                    PaymentTransactionType::Sale3D => NuveiTransactionType::Auth3D, // Map to closest equivalent
+                    PaymentTransactionType::Verif => NuveiTransactionType::Auth, // Map to closest equivalent
+                });
+
+                Self {
+                    transaction_status: notification.transaction_status.map(|ts| match ts {
+                        TransactionStatus::Approved => NuveiTransactionStatus::Approved,
+                        TransactionStatus::Declined => NuveiTransactionStatus::Declined,
+                        TransactionStatus::Error => NuveiTransactionStatus::Error,
+                        TransactionStatus::Settled => NuveiTransactionStatus::Approved,
+                        _ => NuveiTransactionStatus::Processing,
+                    }),
+                    transaction_id: notification.transaction_id,
+                    transaction_type,
+                    ..Default::default()
+                }
+            }
+        }
+    }
 }
 
-impl From<NuveiWebhookStatus> for NuveiTransactionStatus {
-    fn from(status: NuveiWebhookStatus) -> Self {
-        match status {
-            NuveiWebhookStatus::Approved => Self::Approved,
-            NuveiWebhookStatus::Declined => Self::Declined,
-            _ => Self::Processing,
-        }
+fn get_cvv2_response_description(code: &str) -> Option<&str> {
+    match code {
+        "M" => Some("CVV2 Match"),
+        "N" => Some("CVV2 No Match"),
+        "P" => Some("Not Processed. For EU card-on-file (COF) and ecommerce (ECOM) network token transactions, Visa removes any CVV and sends P. If you have fraud or security concerns, Visa recommends using 3DS."),
+        "U" => Some("Issuer is not certified and/or has not provided Visa the encryption keys"),
+        "S" => Some("CVV2 processor is unavailable."),
+        _=> None,
     }
 }
 
-impl From<NuveiWebhookDetails> for NuveiPaymentsResponse {
-    fn from(item: NuveiWebhookDetails) -> Self {
-        Self {
-            transaction_status: Some(NuveiTransactionStatus::from(item.status)),
-            transaction_id: item.transaction_id,
-            transaction_type: item.transaction_type,
-            ..Default::default()
-        }
+fn get_avs_response_description(code: &str) -> Option<&str> {
+    match code {
+        "A" => Some("The street address matches, the ZIP code does not."),
+        "W" => Some("Postal code matches, the street address does not."),
+        "Y" => Some("Postal code and the street address match."),
+        "X" => Some("An exact match of both the 9-digit ZIP code and the street address."),
+        "Z" => Some("Postal code matches, the street code does not."),
+        "U" => Some("Issuer is unavailable."),
+        "S" => Some("AVS not supported by issuer."),
+        "R" => Some("Retry."),
+        "B" => Some("Not authorized (declined)."),
+        "N" => Some("Both the street address and postal code do not match."),
+        _ => None,
+    }
+}
+
+fn get_merchant_advice_code_description(code: &str) -> Option<&str> {
+    match code {
+        "01" => Some("New Account Information Available"),
+        "02" => Some("Cannot approve at this time, try again later"),
+        "03" => Some("Do Not Try Again"),
+        "04" => Some("Token requirements not fulfilled for this token type"),
+        "21" => Some("Payment Cancellation, do not try again"),
+        "24" => Some("Retry after 1 hour"),
+        "25" => Some("Retry after 24 hours"),
+        "26" => Some("Retry after 2 days"),
+        "27" => Some("Retry after 4 days"),
+        "28" => Some("Retry after 6 days"),
+        "29" => Some("Retry after 8 days"),
+        "30" => Some("Retry after 10 days"),
+        "40" => Some("Card is a consumer non-reloadable prepaid card"),
+        "41" => Some("Card is a consumer single-use virtual card number"),
+        "42" => Some("Transaction type exceeds issuer's risk threshold. Please retry with another payment account."),
+        "43" => Some("Card is a consumer multi-use virtual card number"),
+        _ => None,
+    }
+}
+
+/// Concatenates a vector of strings without any separator
+/// This is useful for creating verification messages for webhooks
+pub fn concat_strings(strings: &[String]) -> String {
+    strings.join("")
+}
+
+fn convert_to_additional_payment_method_connector_response(
+    transaction_response: &NuveiPaymentsResponse,
+) -> Option<AdditionalPaymentMethodConnectorResponse> {
+    let card = transaction_response
+        .payment_option
+        .as_ref()?
+        .card
+        .as_ref()?;
+    let avs_code = card.avs_code.as_ref();
+    let cvv2_code = card.cvv2_reply.as_ref();
+    let merchant_advice_code = transaction_response.merchant_advice_code.as_ref();
+
+    let avs_description = avs_code.and_then(|code| get_avs_response_description(code));
+    let cvv_description = cvv2_code.and_then(|code| get_cvv2_response_description(code));
+    let merchant_advice_description =
+        merchant_advice_code.and_then(|code| get_merchant_advice_code_description(code));
+
+    let payment_checks = serde_json::json!({
+        "avs_result_code": avs_code,
+        "avs_description": avs_description,
+        "cvv_2_reply_code": cvv2_code,
+        "cvv_2_description": cvv_description,
+        "merchant_advice_code": merchant_advice_code,
+        "merchant_advice_code_description": merchant_advice_description
+    });
+
+    let card_network = card.card_brand.clone();
+    let three_ds_data = card
+        .three_d
+        .clone()
+        .map(|three_d| {
+            serde_json::to_value(three_d)
+                .map_err(|_| errors::ConnectorError::ResponseHandlingFailed)
+                .attach_printable("threeDs encoding failed Nuvei")
+        })
+        .transpose();
+
+    match three_ds_data {
+        Ok(authentication_data) => Some(AdditionalPaymentMethodConnectorResponse::Card {
+            authentication_data,
+            payment_checks: Some(payment_checks),
+            card_network,
+            domestic_network: None,
+        }),
+        Err(_) => None,
     }
 }
diff --git a/crates/hyperswitch_connectors/src/default_implementations.rs b/crates/hyperswitch_connectors/src/default_implementations.rs
index 22c87d08323..2ecdf1f4de1 100644
--- a/crates/hyperswitch_connectors/src/default_implementations.rs
+++ b/crates/hyperswitch_connectors/src/default_implementations.rs
@@ -1058,7 +1058,6 @@ default_imp_for_cancel_post_capture!(
     connectors::Nexixpay,
     connectors::Opayo,
     connectors::Opennode,
-    connectors::Nuvei,
     connectors::Nmi,
     connectors::Paybox,
     connectors::Payeezy,

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

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

## Description

Added few Nuvie features
- AVC,CVV : pass the response of AVC , CVV checks from Nuvie to Hypserswitch payment resonse (check in any below responses)


```json
    "payment_checks": {
                "avs_description": null,
                "avs_result_code": "",
                "cvv_2_reply_code": "",
                "cvv_2_description": null,
                "merchant_advice_code": "",
                "merchant_advice_code_description": null
            },
```
- Post Capture Void : After capture of successful amount we should be able to make void (typically before 24 hours)

- 0$ transaction : Allow 0$ transaction // We are going to change this to setup mandate flow in upcomming pr rightnow its routing through AUTHORIZE flow itself . We can skip the test for this as of now.



<!-- Describe your changes in detail -->






## zero dollar transaction

<details>

 <summary>
Get connector mandate id with 0 transaction initization `/payments`
</summary>

## Request

```json
{
    "amount": 0,
    "currency": "EUR",
    "confirm": true,
    "customer_acceptance": {
        "acceptance_type": "online",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
    // "order_tax_amount": 100,
    "setup_future_usage": "off_session",
    // "payment_type":"setup_mandate",
    "customer_id": "nithxxinn",
    "return_url": "https://www.google.com",
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_type": "credit",
    "authentication_type": "no_three_ds",
    "description": "hellow world",
    "billing": {
        "address": {
            "zip": "560095",
            "country": "US",
            "first_name": "Sakil",
            "last_name": "Mostak",
            "line1": "Fasdf",
            "line2": "Fasdf",
            "city": "Fasdf"
        }
    },
    "browser_info": {
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "ip_address": "192.168.1.1",
        "java_enabled": false,
        "java_script_enabled": true,
        "language": "en-US",
        "color_depth": 24,
        "screen_height": 1080,
        "screen_width": 1920,
        "time_zone": 330,
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
    },
    "email": "hello@gmail.com",
    "payment_method_data": {
        "card": {
            "card_number": "4000000000009995",
            "card_exp_month": "01",
            "card_exp_year": "2026",
            "card_holder_name": "John Smith",
            "card_cvc": "100"
        }
    }
}

```


## response

```json
{
    "payment_id": "pay_bnO3yXpju09Ws8oBUR9w",
    "merchant_id": "merchant_1754498214",
    "status": "requires_capture",
    "amount": 0,
    "net_amount": 0,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": "nuvei",
    "client_secret": "pay_bnO3yXpju09Ws8oBUR9w_secret_Y6WO2DC3Uidzbeb7WyWa",
    "created": "2025-08-06T17:23:41.192Z",
    "currency": "EUR",
    "customer_id": "nithxxinn",
    "customer": {
        "id": "nithxxinn",
        "name": null,
        "email": "hello@gmail.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": "hellow world",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "9995",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "400000",
            "card_extended_bin": null,
            "card_exp_month": "01",
            "card_exp_year": "2026",
            "card_holder_name": "John Smith",
            "payment_checks": {
                "avs_description": null,
                "avs_result_code": "",
                "cvv_2_reply_code": "",
                "cvv_2_description": null,
                "merchant_advice_code": "",
                "merchant_advice_code_description": null
            },
            "authentication_data": {
                "challengePreferenceReason": "12"
            }
        },
        "billing": null
    },
    "payment_token": "token_rO5qEPT5099xgR6E600V",
    "shipping": null,
    "billing": {
        "address": {
            "city": "Fasdf",
            "country": "US",
            "line1": "Fasdf",
            "line2": "Fasdf",
            "line3": null,
            "zip": "560095",
            "state": null,
            "first_name": "Sakil",
            "last_name": "Mostak",
            "origin_zip": null
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": "hello@gmail.com",
    "name": null,
    "phone": null,
    "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": 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": "nithxxinn",
        "created_at": 1754501021,
        "expires": 1754504621,
        "secret": "epk_6fb49f9cdabd42dd9d33789fb584df66"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "7110000000016293888",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "7657741111",
    "payment_link": null,
    "profile_id": "pro_Lm9uDS83De6QX5EHQNMy",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_BgWz2Uy3MgHlzzgy7W7H",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-08-06T17:38:41.192Z",
    "fingerprint": null,
    "browser_info": {
        "language": "en-US",
        "time_zone": 330,
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
        "color_depth": 24,
        "java_enabled": false,
        "screen_width": 1920,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "screen_height": 1080,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": "pm_Ku0TdAhmkKDiX9TqhomL",
    "network_transaction_id": null,
    "payment_method_status": "active",
    "updated": "2025-08-06T17:23:46.105Z",
    "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": "2073997111", // connector mandate id 
    "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
}
```

</details>


<details>

 <summary> Mandates triggered using 0 transcation payment method id </summary>

## Request

```json
curl --location 'localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_gvwtxVj8XLUh0di5xt8yUkxS187Wlr733tSxZh7Aof45gYnrteTvmP2aJvFD8vdj' \
--data '{
    "amount": 333,
    "currency": "EUR",
    "customer_id": "nithxxinn",
    "confirm": true,
    "off_session": true,
    "recurring_details": {
        "type": "payment_method_id",
        "data": "pm_Ku0TdAhmkKDiX9TqhomL" 
    },
       "browser_info": {
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "ip_address": "192.168.1.1",
        "java_enabled": false,
        "java_script_enabled": true,
        "language": "en-US",
        "color_depth": 24,
        "screen_height": 1080,
        "screen_width": 1920,
        "time_zone": 330,
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
    }
}'
```





##response

```json
{
    "payment_id": "pay_eW2XRbgGai3X3RpAVVGD",
    "merchant_id": "merchant_1754498214",
    "status": "succeeded",
    "amount": 333,
    "net_amount": 333,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 333,
    "connector": "nuvei",
    "client_secret": "pay_eW2XRbgGai3X3RpAVVGD_secret_H6pCfoxWHonNwkXzyHD2",
    "created": "2025-08-06T17:34:58.537Z",
    "currency": "EUR",
    "customer_id": "nithxxinn",
    "customer": {
        "id": "nithxxinn",
        "name": null,
        "email": "hello@gmail.com",
        "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": null,
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "9995",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "400000",
            "card_extended_bin": null,
            "card_exp_month": "01",
            "card_exp_year": "2026",
            "card_holder_name": "John Smith",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": "hello@gmail.com",
    "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": "nithxxinn",
        "created_at": 1754501698,
        "expires": 1754505298,
        "secret": "epk_7e35c394cdc94bc59e5184173d3fa385"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "7110000000016294501",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "7658013111",
    "payment_link": null,
    "profile_id": "pro_Lm9uDS83De6QX5EHQNMy",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_BgWz2Uy3MgHlzzgy7W7H",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-08-06T17:49:58.537Z",
    "fingerprint": null,
    "browser_info": {
        "language": "en-US",
        "time_zone": 330,
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
        "color_depth": 24,
        "java_enabled": false,
        "screen_width": 1920,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "screen_height": 1080,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": "pm_Ku0TdAhmkKDiX9TqhomL",
    "network_transaction_id": null,
    "payment_method_status": "active",
    "updated": "2025-08-06T17:35:01.823Z",
    "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": "2073997111",
    "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
}
```

</details>

## Post capture cancel
- original txn:   7110000000016291163
- void:               7110000000016291191
<details>
    <summary>  
           /payments/:id/cancel_post_capture
  </summary>

```json
curl --location 'localhost:8080/payments/pay_MyZex1y0W8JtlkJ4E8sX/cancel_post_capture' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_gvwtxVj8XLUh0di5xt8yUkxS187Wlr733tSxZh7Aof45gYnrteTvmP2aJvFD8vdj' \
--data '{
  "cancellation_reason": "requested_by_customer"
}'
```

### Response

```json
{
    "payment_id": "pay_MyZex1y0W8JtlkJ4E8sX",
    "merchant_id": "merchant_1754498214",
    "status": "partially_captured",
    "amount": 21,
    "net_amount": 21,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 21,
    "connector": "nuvei",
    "client_secret": "pay_MyZex1y0W8JtlkJ4E8sX_secret_Ih4q9iGVVaUNIM69pSHv",
    "created": "2025-08-06T16:45:05.230Z",
    "currency": "EUR",
    "customer_id": null,
    "customer": {
        "id": null,
        "name": null,
        "email": "hello@gmail.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": "hellow world",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "9995",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "400000",
            "card_extended_bin": null,
            "card_exp_month": "01",
            "card_exp_year": "2026",
            "card_holder_name": "John Smith",
            "payment_checks": {
                "avs_description": null,
                "avs_result_code": "",
                "cvv_2_reply_code": "",
                "cvv_2_description": null,
                "merchant_advice_code": "",
                "merchant_advice_code_description": null
            },
            "authentication_data": {
                "challengePreferenceReason": "12"
            }
        },
        "billing": null
    },
    "payment_token": "token_IpZOPBQT3Cr7UWNqtKFT",
    "shipping": null,
    "billing": {
        "address": {
            "city": "Fasdf",
            "country": "US",
            "line1": "Fasdf",
            "line2": "Fasdf",
            "line3": null,
            "zip": "560095",
            "state": null,
            "first_name": "Sakil",
            "last_name": "Mostak",
            "origin_zip": null
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "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": 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": "7110000000016291191",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "7656640111",
    "payment_link": null,
    "profile_id": "pro_Lm9uDS83De6QX5EHQNMy",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_BgWz2Uy3MgHlzzgy7W7H",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-08-06T17:00:05.230Z",
    "fingerprint": null,
    "browser_info": {
        "language": "en-US",
        "time_zone": 330,
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
        "color_depth": 24,
        "java_enabled": false,
        "screen_width": 1920,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "screen_height": 1080,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": "pm_IINXjPD3GBVwSFS5jrNS",
    "network_transaction_id": null,
    "payment_method_status": null,
    "updated": "2025-08-06T16:45:23.093Z",
    "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": null
}
```

For AVS , cvv and MAC you can check in the above payment resopnses

```
json
           "payment_checks": {
                "avs_description": null,
                "avs_result_code": "",
                "cvv_2_reply_code": "", 
                "cvv_2_description": null,
                "merchant_advice_code": "",
                "merchant_advice_code_description": null
            },
```
</details>


<img width="647" height="703" alt="Screenshot 2025-08-08 at 7 37 41 PM" src="https://github.com/user-attachments/assets/cb4aa3b0-4908-46c2-b4f7-f231d3d9f044" />
<img width="775" height="892" alt="Screenshot 2025-08-08 at 7 38 07 PM" src="https://github.com/user-attachments/assets/829f417f-859e-4712-936f-fa9d3165dc10" />
<img width="643" height="699" alt="Screenshot 2025-08-08 at 7 38 22 PM" src="https://github.com/user-attachments/assets/8bc337eb-b79b-4f62-8170-74bd5b3a3d6a" />



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