Bug: [FEATURE] Checkout.com support for Applepay, Googlepay and Webhooks



### Feature Description

Scope:
- [ ] Add support for Applepay, Googlepay digital wallets #875 
- [ ] Enable tokenization for respective Googlepay/ Applepay endpoint to make wallet payment #875 
- [ ] Webhook support for asynchronous payment status #875 
- [ ] Webhook support for asynchronous refund status #875 
- [ ] Webhook support for asynchronous dispute status #875 




### Possible Implementation

In order to ensure that the payment flow is agnostic to the processor, this will need integration of pre-decrypted Applepay and Googlepay flow

Reference links:
https://www.checkout.com/docs/payments/payment-methods/google-pay/pay-with-a-pre-decrypted-google-pay-token
https://www.checkout.com/docs/payments/payment-methods/apple-pay/pay-with-a-pre-decrypted-apple-pay-token

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

- [X] I checked and didn't find 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/config/development.toml b/config/development.toml
index 1a335764d67..49c7c91c53d 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -181,3 +181,4 @@ apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,D
 
 [tokenization]
 stripe = { long_lived_token = false, payment_method = "wallet"}
+checkout = { long_lived_token = false, payment_method = "wallet"}
diff --git a/crates/router/src/connector/checkout.rs b/crates/router/src/connector/checkout.rs
index 6c6ff98b697..b034f25bb43 100644
--- a/crates/router/src/connector/checkout.rs
+++ b/crates/router/src/connector/checkout.rs
@@ -4,10 +4,11 @@ mod transformers;
 
 use std::fmt::Debug;
 
+use common_utils::{crypto, ext_traits::ByteSliceExt};
 use error_stack::{IntoReport, ResultExt};
 
 use self::transformers as checkout;
-use super::utils::RefundsRequestData;
+use super::utils::{self as conn_utils, RefundsRequestData};
 use crate::{
     configs::settings,
     consts,
@@ -15,10 +16,12 @@ use crate::{
         errors::{self, CustomResult},
         payments,
     },
-    headers, services,
+    db::StorageInterface,
+    headers,
+    services::{self, ConnectorIntegration},
     types::{
         self,
-        api::{self, ConnectorCommon},
+        api::{self, ConnectorCommon, ConnectorCommonExt},
     },
     utils::{self, BytesExt},
 };
@@ -26,6 +29,25 @@ use crate::{
 #[derive(Debug, Clone)]
 pub struct Checkout;
 
+impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Checkout
+where
+    Self: ConnectorIntegration<Flow, Request, Response>,
+{
+    fn build_headers(
+        &self,
+        req: &types::RouterData<Flow, Request, Response>,
+        _connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        let mut header = vec![(
+            headers::CONTENT_TYPE.to_string(),
+            types::PaymentsAuthorizeType::get_content_type(self).to_string(),
+        )];
+        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
+        header.append(&mut api_key);
+        Ok(header)
+    }
+}
+
 impl ConnectorCommon for Checkout {
     fn id(&self) -> &'static str {
         "checkout"
@@ -44,13 +66,45 @@ impl ConnectorCommon for Checkout {
             .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
         Ok(vec![(
             headers::AUTHORIZATION.to_string(),
-            format!("Bearer {}", auth.api_key),
+            format!("Bearer {}", auth.api_secret),
         )])
     }
 
     fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
         connectors.checkout.base_url.as_ref()
     }
+    fn build_error_response(
+        &self,
+        res: types::Response,
+    ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
+        let response: checkout::ErrorResponse = if res.response.is_empty() {
+            checkout::ErrorResponse {
+                request_id: None,
+                error_type: if res.status_code == 401 | 422 {
+                    Some("Invalid Api Key".to_owned())
+                } else {
+                    None
+                },
+                error_codes: None,
+            }
+        } else {
+            res.response
+                .parse_struct("ErrorResponse")
+                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?
+        };
+
+        Ok(types::ErrorResponse {
+            status_code: res.status_code,
+            code: response
+                .error_codes
+                .unwrap_or_else(|| vec![consts::NO_ERROR_CODE.to_string()])
+                .join(" & "),
+            message: response
+                .error_type
+                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
+            reason: None,
+        })
+    }
 }
 
 impl api::Payment for Checkout {}
@@ -64,66 +118,128 @@ impl api::ConnectorAccessToken for Checkout {}
 impl api::PaymentToken for Checkout {}
 
 impl
-    services::ConnectorIntegration<
+    ConnectorIntegration<
         api::PaymentMethodToken,
         types::PaymentMethodTokenizationData,
         types::PaymentsResponseData,
     > for Checkout
 {
-    // Not Implemented (R)
+    fn get_headers(
+        &self,
+        req: &types::TokenizationRouterData,
+        _connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        let mut header = vec![(
+            headers::CONTENT_TYPE.to_string(),
+            self.common_get_content_type().to_string(),
+        )];
+        let api_key = checkout::CheckoutAuthType::try_from(&req.connector_auth_type)
+            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
+        let mut auth = vec![(
+            headers::AUTHORIZATION.to_string(),
+            format!("Bearer {}", api_key.api_key),
+        )];
+        header.append(&mut auth);
+        Ok(header)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        _req: &types::TokenizationRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!("{}tokens", self.base_url(connectors)))
+    }
+
+    fn get_request_body(
+        &self,
+        req: &types::TokenizationRouterData,
+    ) -> CustomResult<Option<String>, errors::ConnectorError> {
+        let connector_req = checkout::TokenRequest::try_from(req)?;
+        let checkout_req =
+            utils::Encode::<checkout::TokenRequest>::encode_to_string_of_json(&connector_req)
+                .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        Ok(Some(checkout_req))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::TokenizationRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Post)
+                .url(&types::TokenizationType::get_url(self, req, connectors)?)
+                .attach_default_headers()
+                .headers(types::TokenizationType::get_headers(self, req, connectors)?)
+                .body(types::TokenizationType::get_request_body(self, req)?)
+                .build(),
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::TokenizationRouterData,
+        res: types::Response,
+    ) -> CustomResult<types::TokenizationRouterData, errors::ConnectorError>
+    where
+        types::PaymentsResponseData: Clone,
+    {
+        let response: checkout::CheckoutTokenResponse = res
+            .response
+            .parse_struct("CheckoutTokenResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+
+        types::RouterData::try_from(types::ResponseRouterData {
+            response,
+            data: data.clone(),
+            http_code: res.status_code,
+        })
+        .change_context(errors::ConnectorError::ResponseHandlingFailed)
+    }
+
+    fn get_error_response(
+        &self,
+        res: types::Response,
+    ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
 }
 
-impl
-    services::ConnectorIntegration<
-        api::Session,
-        types::PaymentsSessionData,
-        types::PaymentsResponseData,
-    > for Checkout
+impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
+    for Checkout
 {
     // Not Implemented (R)
 }
 
-impl
-    services::ConnectorIntegration<
-        api::AccessTokenAuth,
-        types::AccessTokenRequestData,
-        types::AccessToken,
-    > for Checkout
+impl ConnectorIntegration<api::AccessTokenAuth, types::AccessTokenRequestData, types::AccessToken>
+    for Checkout
 {
     // Not Implemented (R)
 }
 
 impl api::PreVerify for Checkout {}
 
-impl
-    services::ConnectorIntegration<
-        api::Verify,
-        types::VerifyRequestData,
-        types::PaymentsResponseData,
-    > for Checkout
+impl ConnectorIntegration<api::Verify, types::VerifyRequestData, types::PaymentsResponseData>
+    for Checkout
 {
     // Issue: #173
 }
 
-impl
-    services::ConnectorIntegration<
-        api::Capture,
-        types::PaymentsCaptureData,
-        types::PaymentsResponseData,
-    > for Checkout
+impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
+    for Checkout
 {
     fn get_headers(
         &self,
         req: &types::PaymentsCaptureRouterData,
-        _connectors: &settings::Connectors,
+        connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
-        let mut header = vec![(
-            headers::CONTENT_TYPE.to_string(),
-            self.common_get_content_type().to_string(),
-        )];
-        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
-        header.append(&mut api_key);
-        Ok(header)
+        self.build_headers(req, connectors)
     }
 
     fn get_url(
@@ -190,40 +306,19 @@ impl
         &self,
         res: types::Response,
     ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
-        let response: checkout::ErrorResponse = res
-            .response
-            .parse_struct("ErrorResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        Ok(types::ErrorResponse {
-            status_code: res.status_code,
-            code: response
-                .error_codes
-                .unwrap_or_else(|| vec![consts::NO_ERROR_CODE.to_string()])
-                .join(" & "),
-            message: response
-                .error_type
-                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
-            reason: None,
-        })
+        self.build_error_response(res)
     }
 }
 
-impl
-    services::ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
+impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
     for Checkout
 {
     fn get_headers(
         &self,
         req: &types::PaymentsSyncRouterData,
-        _connectors: &settings::Connectors,
+        connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
-        let mut header = vec![(
-            headers::CONTENT_TYPE.to_string(),
-            types::PaymentsAuthorizeType::get_content_type(self).to_string(),
-        )];
-        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
-        header.append(&mut api_key);
-        Ok(header)
+        self.build_headers(req, connectors)
     }
 
     fn get_url(
@@ -284,43 +379,19 @@ impl
         &self,
         res: types::Response,
     ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
-        let response: checkout::ErrorResponse = res
-            .response
-            .parse_struct("ErrorResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        Ok(types::ErrorResponse {
-            status_code: res.status_code,
-            code: response
-                .error_codes
-                .unwrap_or_else(|| vec![consts::NO_ERROR_CODE.to_string()])
-                .join(" &"),
-            message: response
-                .error_type
-                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
-            reason: None,
-        })
+        self.build_error_response(res)
     }
 }
 
-impl
-    services::ConnectorIntegration<
-        api::Authorize,
-        types::PaymentsAuthorizeData,
-        types::PaymentsResponseData,
-    > for Checkout
+impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData>
+    for Checkout
 {
     fn get_headers(
         &self,
         req: &types::PaymentsAuthorizeRouterData,
-        _connectors: &settings::Connectors,
+        connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
-        let mut header = vec![(
-            headers::CONTENT_TYPE.to_string(),
-            types::PaymentsAuthorizeType::get_content_type(self).to_string(),
-        )];
-        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
-        header.append(&mut api_key);
-        Ok(header)
+        self.build_headers(req, connectors)
     }
 
     fn get_url(
@@ -386,55 +457,19 @@ impl
         &self,
         res: types::Response,
     ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
-        let response: checkout::ErrorResponse = if res.response.is_empty() {
-            checkout::ErrorResponse {
-                request_id: None,
-                error_type: if res.status_code == 401 {
-                    Some("Invalid Api Key".to_owned())
-                } else {
-                    None
-                },
-                error_codes: None,
-            }
-        } else {
-            res.response
-                .parse_struct("ErrorResponse")
-                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?
-        };
-
-        Ok(types::ErrorResponse {
-            status_code: res.status_code,
-            code: response
-                .error_codes
-                .unwrap_or_else(|| vec![consts::NO_ERROR_CODE.to_string()])
-                .join(" & "),
-            message: response
-                .error_type
-                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
-            reason: None,
-        })
+        self.build_error_response(res)
     }
 }
 
-impl
-    services::ConnectorIntegration<
-        api::Void,
-        types::PaymentsCancelData,
-        types::PaymentsResponseData,
-    > for Checkout
+impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
+    for Checkout
 {
     fn get_headers(
         &self,
         req: &types::PaymentsCancelRouterData,
-        _connectors: &settings::Connectors,
+        connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
-        let mut header = vec![(
-            headers::CONTENT_TYPE.to_string(),
-            types::PaymentsVoidType::get_content_type(self).to_string(),
-        )];
-        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
-        header.append(&mut api_key);
-        Ok(header)
+        self.build_headers(req, connectors)
     }
 
     fn get_url(
@@ -497,21 +532,7 @@ impl
         &self,
         res: types::Response,
     ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
-        let response: checkout::ErrorResponse = res
-            .response
-            .parse_struct("ErrorResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        Ok(types::ErrorResponse {
-            status_code: res.status_code,
-            code: response
-                .error_codes
-                .unwrap_or_else(|| vec![consts::NO_ERROR_CODE.to_string()])
-                .join(" & "),
-            message: response
-                .error_type
-                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
-            reason: None,
-        })
+        self.build_error_response(res)
     }
 }
 
@@ -519,21 +540,15 @@ impl api::Refund for Checkout {}
 impl api::RefundExecute for Checkout {}
 impl api::RefundSync for Checkout {}
 
-impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
+impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
     for Checkout
 {
     fn get_headers(
         &self,
         req: &types::RefundsRouterData<api::Execute>,
-        _connectors: &settings::Connectors,
+        connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
-        let mut header = vec![(
-            headers::CONTENT_TYPE.to_string(),
-            types::RefundExecuteType::get_content_type(self).to_string(),
-        )];
-        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
-        header.append(&mut api_key);
-        Ok(header)
+        self.build_headers(req, connectors)
     }
 
     fn get_content_type(&self) -> &'static str {
@@ -607,39 +622,17 @@ impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::Ref
         &self,
         res: types::Response,
     ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
-        let response: checkout::ErrorResponse = res
-            .response
-            .parse_struct("ErrorResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        Ok(types::ErrorResponse {
-            status_code: res.status_code,
-            code: response
-                .error_codes
-                .unwrap_or_else(|| vec![consts::NO_ERROR_CODE.to_string()])
-                .join(" & "),
-            message: response
-                .error_type
-                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
-            reason: None,
-        })
+        self.build_error_response(res)
     }
 }
 
-impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData>
-    for Checkout
-{
+impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for Checkout {
     fn get_headers(
         &self,
         req: &types::RefundsRouterData<api::RSync>,
-        _connectors: &settings::Connectors,
+        connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
-        let mut header = vec![(
-            headers::CONTENT_TYPE.to_string(),
-            types::RefundSyncType::get_content_type(self).to_string(),
-        )];
-        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
-        header.append(&mut api_key);
-        Ok(header)
+        self.build_headers(req, connectors)
     }
 
     fn get_url(
@@ -700,45 +693,126 @@ impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::Refun
         &self,
         res: types::Response,
     ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
-        let response: checkout::ErrorResponse = res
-            .response
-            .parse_struct("ErrorResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        Ok(types::ErrorResponse {
-            status_code: res.status_code,
-            code: response
-                .error_codes
-                .unwrap_or_else(|| vec![consts::NO_ERROR_CODE.to_string()])
-                .join(" & "),
-            message: response
-                .error_type
-                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
-            reason: None,
-        })
+        self.build_error_response(res)
     }
 }
 
 #[async_trait::async_trait]
 impl api::IncomingWebhook for Checkout {
-    fn get_webhook_object_reference_id(
+    fn get_webhook_source_verification_algorithm(
         &self,
         _request: &api::IncomingWebhookRequestDetails<'_>,
+    ) -> CustomResult<Box<dyn crypto::VerifySignature + Send>, errors::ConnectorError> {
+        Ok(Box::new(crypto::HmacSha256))
+    }
+    fn get_webhook_source_verification_signature(
+        &self,
+        request: &api::IncomingWebhookRequestDetails<'_>,
+    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
+        let signature = conn_utils::get_header_key_value("cko-signature", request.headers)
+            .change_context(errors::ConnectorError::WebhookSignatureNotFound)?;
+        hex::decode(signature)
+            .into_report()
+            .change_context(errors::ConnectorError::WebhookSignatureNotFound)
+    }
+    fn get_webhook_source_verification_message(
+        &self,
+        request: &api::IncomingWebhookRequestDetails<'_>,
+        _merchant_id: &str,
+        _secret: &[u8],
+    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
+        Ok(format!("{}", String::from_utf8_lossy(request.body)).into_bytes())
+    }
+    async fn get_webhook_source_verification_merchant_secret(
+        &self,
+        db: &dyn StorageInterface,
+        merchant_id: &str,
+    ) -> CustomResult<Vec<u8>, errors::ConnectorError> {
+        let key = format!("whsec_verification_{}_{}", self.id(), merchant_id);
+        let secret = db
+            .find_config_by_key(&key)
+            .await
+            .change_context(errors::ConnectorError::WebhookVerificationSecretNotFound)?;
+        Ok(secret.config.into_bytes())
+    }
+    fn get_webhook_object_reference_id(
+        &self,
+        request: &api::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
-        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
+        let details: checkout::CheckoutWebhookBody = request
+            .body
+            .parse_struct("CheckoutWebhookBody")
+            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
+
+        if checkout::is_chargeback_event(&details.txn_type) {
+            return Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
+                api_models::payments::PaymentIdType::ConnectorTransactionId(
+                    details
+                        .data
+                        .payment_id
+                        .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
+                ),
+            ));
+        }
+        if checkout::is_refund_event(&details.txn_type) {
+            return Ok(api_models::webhooks::ObjectReferenceId::RefundId(
+                api_models::webhooks::RefundIdType::ConnectorRefundId(
+                    details
+                        .data
+                        .action_id
+                        .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
+                ),
+            ));
+        }
+        Ok(api_models::webhooks::ObjectReferenceId::PaymentId(
+            api_models::payments::PaymentIdType::ConnectorTransactionId(details.data.id),
+        ))
     }
 
     fn get_webhook_event_type(
         &self,
-        _request: &api::IncomingWebhookRequestDetails<'_>,
+        request: &api::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
-        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
+        let details: checkout::CheckoutWebhookBody = request
+            .body
+            .parse_struct("CheckoutWebhookBody")
+            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
+
+        Ok(api::IncomingWebhookEvent::from(details.txn_type))
     }
 
     fn get_webhook_resource_object(
         &self,
-        _request: &api::IncomingWebhookRequestDetails<'_>,
+        request: &api::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<serde_json::Value, errors::ConnectorError> {
-        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
+        let details: checkout::CheckoutWebhookObjectResource = request
+            .body
+            .parse_struct("CheckoutWebhookObjectResource")
+            .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
+
+        Ok(details.data)
+    }
+
+    fn get_dispute_details(
+        &self,
+        request: &api::IncomingWebhookRequestDetails<'_>,
+    ) -> CustomResult<api::disputes::DisputePayload, errors::ConnectorError> {
+        let dispute_details: checkout::CheckoutWebhookBody = request
+            .body
+            .parse_struct("CheckoutWebhookBody")
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+        Ok(api::disputes::DisputePayload {
+            amount: dispute_details.data.amount.to_string(),
+            currency: dispute_details.data.currency,
+            dispute_stage: api_models::enums::DisputeStage::from(dispute_details.txn_type.clone()),
+            connector_dispute_id: dispute_details.data.id,
+            connector_reason: None,
+            connector_reason_code: dispute_details.data.reason_code,
+            challenge_required_by: dispute_details.data.evidence_required_by,
+            connector_status: dispute_details.txn_type.to_string(),
+            created_at: dispute_details.created_on,
+            updated_at: dispute_details.data.date,
+        })
     }
 }
 
diff --git a/crates/router/src/connector/checkout/transformers.rs b/crates/router/src/connector/checkout/transformers.rs
index a9d5eef4fa3..1de1256d7ee 100644
--- a/crates/router/src/connector/checkout/transformers.rs
+++ b/crates/router/src/connector/checkout/transformers.rs
@@ -1,30 +1,131 @@
+use error_stack::IntoReport;
 use serde::{Deserialize, Serialize};
 use url::Url;
 
 use crate::{
+    connector::utils::{RouterData, WalletData},
     core::errors,
     pii, services,
     types::{self, api, storage::enums, transformers::ForeignFrom},
 };
 
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "lowercase")]
+#[serde(tag = "type", content = "token_data")]
+pub enum TokenRequest {
+    Googlepay(CheckoutGooglePayData),
+    Applepay(CheckoutApplePayData),
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CheckoutGooglePayData {
+    protocol_version: pii::Secret<String>,
+    signature: pii::Secret<String>,
+    signed_message: pii::Secret<String>,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+pub struct CheckoutApplePayData {
+    version: pii::Secret<String>,
+    data: pii::Secret<String>,
+    signature: pii::Secret<String>,
+    header: CheckoutApplePayHeader,
+}
+
+#[derive(Debug, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CheckoutApplePayHeader {
+    ephemeral_public_key: pii::Secret<String>,
+    public_key_hash: pii::Secret<String>,
+    transaction_id: pii::Secret<String>,
+}
+
+impl TryFrom<&types::TokenizationRouterData> for TokenRequest {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(item: &types::TokenizationRouterData) -> Result<Self, Self::Error> {
+        match item.request.payment_method_data.clone() {
+            api::PaymentMethodData::Wallet(wallet_data) => match wallet_data.clone() {
+                api_models::payments::WalletData::GooglePay(_data) => {
+                    let json_wallet_data: CheckoutGooglePayData =
+                        wallet_data.get_wallet_token_as_json()?;
+                    Ok(Self::Googlepay(json_wallet_data))
+                }
+                api_models::payments::WalletData::ApplePay(_data) => {
+                    let json_wallet_data: CheckoutApplePayData =
+                        wallet_data.get_wallet_token_as_json()?;
+                    Ok(Self::Applepay(json_wallet_data))
+                }
+                _ => Err(errors::ConnectorError::NotImplemented(
+                    "Payment Method".to_string(),
+                ))
+                .into_report(),
+            },
+            _ => Err(errors::ConnectorError::NotImplemented(
+                "Payment Method".to_string(),
+            ))
+            .into_report(),
+        }
+    }
+}
+
+#[derive(Debug, Eq, PartialEq, Deserialize)]
+pub struct CheckoutTokenResponse {
+    token: String,
+}
+
+impl<F, T>
+    TryFrom<types::ResponseRouterData<F, CheckoutTokenResponse, T, types::PaymentsResponseData>>
+    for types::RouterData<F, T, types::PaymentsResponseData>
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: types::ResponseRouterData<F, CheckoutTokenResponse, T, types::PaymentsResponseData>,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            response: Ok(types::PaymentsResponseData::TokenizationResponse {
+                token: item.response.token,
+            }),
+            ..item.data
+        })
+    }
+}
+
 #[derive(Debug, Serialize)]
 pub struct CardSource {
     #[serde(rename = "type")]
-    pub source_type: Option<String>,
-    pub number: Option<pii::Secret<String, pii::CardNumber>>,
-    pub expiry_month: Option<pii::Secret<String>>,
-    pub expiry_year: Option<pii::Secret<String>>,
+    pub source_type: CheckoutSourceTypes,
+    pub number: pii::Secret<String, pii::CardNumber>,
+    pub expiry_month: pii::Secret<String>,
+    pub expiry_year: pii::Secret<String>,
+    pub cvv: pii::Secret<String>,
+}
+
+#[derive(Debug, Serialize)]
+pub struct WalletSource {
+    #[serde(rename = "type")]
+    pub source_type: CheckoutSourceTypes,
+    pub token: String,
 }
 
 #[derive(Debug, Serialize)]
 #[serde(untagged)]
-pub enum Source {
+pub enum PaymentSource {
     Card(CardSource),
+    Wallets(WalletSource),
+}
+
+#[derive(Debug, Serialize)]
+#[serde(rename_all = "lowercase")]
+pub enum CheckoutSourceTypes {
+    Card,
+    Token,
 }
 
 pub struct CheckoutAuthType {
     pub(super) api_key: String,
     pub(super) processing_channel_id: String,
+    pub(super) api_secret: String,
 }
 
 #[derive(Debug, Serialize)]
@@ -35,7 +136,7 @@ pub struct ReturnUrl {
 
 #[derive(Debug, Serialize)]
 pub struct PaymentsRequest {
-    pub source: Source,
+    pub source: PaymentSource,
     pub amount: i64,
     pub currency: String,
     pub processing_channel_id: String,
@@ -55,9 +156,15 @@ pub struct CheckoutThreeDS {
 impl TryFrom<&types::ConnectorAuthType> for CheckoutAuthType {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
-        if let types::ConnectorAuthType::BodyKey { api_key, key1 } = auth_type {
+        if let types::ConnectorAuthType::SignatureKey {
+            api_key,
+            api_secret,
+            key1,
+        } = auth_type
+        {
             Ok(Self {
                 api_key: api_key.to_string(),
+                api_secret: api_secret.to_string(),
                 processing_channel_id: key1.to_string(),
             })
         } else {
@@ -68,13 +175,33 @@ impl TryFrom<&types::ConnectorAuthType> for CheckoutAuthType {
 impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentsRequest {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
-        let ccard = match item.request.payment_method_data {
-            api::PaymentMethodData::Card(ref ccard) => Some(ccard),
-            api::PaymentMethodData::Wallet(_)
-            | api::PaymentMethodData::PayLater(_)
-            | api::PaymentMethodData::BankRedirect(_)
-            | api::PaymentMethodData::Crypto(_) => None,
-        };
+        let source_var = match item.request.payment_method_data.clone() {
+            api::PaymentMethodData::Card(ccard) => {
+                let a = PaymentSource::Card(CardSource {
+                    source_type: CheckoutSourceTypes::Card,
+                    number: ccard.card_number.clone(),
+                    expiry_month: ccard.card_exp_month.clone(),
+                    expiry_year: ccard.card_exp_year.clone(),
+                    cvv: ccard.card_cvc,
+                });
+                Ok(a)
+            }
+            api::PaymentMethodData::Wallet(wallet_data) => match wallet_data {
+                api_models::payments::WalletData::GooglePay(_)
+                | api_models::payments::WalletData::ApplePay(_) => {
+                    Ok(PaymentSource::Wallets(WalletSource {
+                        source_type: CheckoutSourceTypes::Token,
+                        token: item.get_payment_method_token()?,
+                    }))
+                }
+                _ => Err(errors::ConnectorError::NotImplemented(
+                    "Payment Method".to_string(),
+                )),
+            },
+            _ => Err(errors::ConnectorError::NotImplemented(
+                "Payment Method".to_string(),
+            )),
+        }?;
 
         let three_ds = match item.auth_type {
             enums::AuthenticationType::ThreeDs => CheckoutThreeDS {
@@ -105,12 +232,6 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PaymentsRequest {
             Some(enums::CaptureMethod::Automatic)
         );
 
-        let source_var = Source::Card(CardSource {
-            source_type: Some("card".to_owned()),
-            number: ccard.map(|x| x.card_number.clone()),
-            expiry_month: ccard.map(|x| x.card_exp_month.clone()),
-            expiry_year: ccard.map(|x| x.card_exp_year.clone()),
-        });
         let connector_auth = &item.connector_auth_type;
         let auth_type: CheckoutAuthType = connector_auth.try_into()?;
         let processing_channel_id = auth_type.processing_channel_id;
@@ -551,3 +672,106 @@ impl From<CheckoutRedirectResponseStatus> for enums::AttemptStatus {
         }
     }
 }
+
+pub fn is_refund_event(event_code: &CheckoutTxnType) -> bool {
+    matches!(
+        event_code,
+        CheckoutTxnType::PaymentRefunded | CheckoutTxnType::PaymentRefundDeclined
+    )
+}
+
+pub fn is_chargeback_event(event_code: &CheckoutTxnType) -> bool {
+    matches!(
+        event_code,
+        CheckoutTxnType::DisputeReceived
+            | CheckoutTxnType::DisputeExpired
+            | CheckoutTxnType::DisputeAccepted
+            | CheckoutTxnType::DisputeCanceled
+            | CheckoutTxnType::DisputeEvidenceSubmitted
+            | CheckoutTxnType::DisputeEvidenceAcknowledgedByScheme
+            | CheckoutTxnType::DisputeEvidenceRequired
+            | CheckoutTxnType::DisputeArbitrationLost
+            | CheckoutTxnType::DisputeArbitrationWon
+            | CheckoutTxnType::DisputeWon
+            | CheckoutTxnType::DisputeLost
+    )
+}
+
+#[derive(Debug, Deserialize)]
+pub struct CheckoutWebhookData {
+    pub id: String,
+    pub payment_id: Option<String>,
+    pub action_id: Option<String>,
+    pub amount: i32,
+    pub currency: String,
+    pub evidence_required_by: Option<String>,
+    pub reason_code: Option<String>,
+    pub date: Option<String>,
+}
+#[derive(Debug, Deserialize)]
+pub struct CheckoutWebhookBody {
+    #[serde(rename = "type")]
+    pub txn_type: CheckoutTxnType,
+    pub data: CheckoutWebhookData,
+    pub created_on: Option<String>,
+}
+#[derive(Debug, Deserialize, strum::Display, Clone)]
+#[serde(rename_all = "snake_case")]
+pub enum CheckoutTxnType {
+    PaymentApproved,
+    PaymentDeclined,
+    PaymentRefunded,
+    PaymentRefundDeclined,
+    DisputeReceived,
+    DisputeExpired,
+    DisputeAccepted,
+    DisputeCanceled,
+    DisputeEvidenceSubmitted,
+    DisputeEvidenceAcknowledgedByScheme,
+    DisputeEvidenceRequired,
+    DisputeArbitrationLost,
+    DisputeArbitrationWon,
+    DisputeWon,
+    DisputeLost,
+}
+
+impl From<CheckoutTxnType> for api::IncomingWebhookEvent {
+    fn from(txn_type: CheckoutTxnType) -> Self {
+        match txn_type {
+            CheckoutTxnType::PaymentApproved => Self::PaymentIntentSuccess,
+            CheckoutTxnType::PaymentDeclined => Self::PaymentIntentSuccess,
+            CheckoutTxnType::PaymentRefunded => Self::RefundSuccess,
+            CheckoutTxnType::PaymentRefundDeclined => Self::RefundFailure,
+            CheckoutTxnType::DisputeReceived | CheckoutTxnType::DisputeEvidenceRequired => {
+                Self::DisputeOpened
+            }
+            CheckoutTxnType::DisputeExpired => Self::DisputeExpired,
+            CheckoutTxnType::DisputeAccepted => Self::DisputeAccepted,
+            CheckoutTxnType::DisputeCanceled => Self::DisputeCancelled,
+            CheckoutTxnType::DisputeEvidenceSubmitted
+            | CheckoutTxnType::DisputeEvidenceAcknowledgedByScheme => Self::DisputeChallenged,
+            CheckoutTxnType::DisputeWon | CheckoutTxnType::DisputeArbitrationWon => {
+                Self::DisputeWon
+            }
+            CheckoutTxnType::DisputeLost | CheckoutTxnType::DisputeArbitrationLost => {
+                Self::DisputeLost
+            }
+        }
+    }
+}
+
+impl From<CheckoutTxnType> for api_models::enums::DisputeStage {
+    fn from(code: CheckoutTxnType) -> Self {
+        match code {
+            CheckoutTxnType::DisputeArbitrationLost | CheckoutTxnType::DisputeArbitrationWon => {
+                Self::PreArbitration
+            }
+            _ => Self::Dispute,
+        }
+    }
+}
+
+#[derive(Debug, Deserialize)]
+pub struct CheckoutWebhookObjectResource {
+    pub data: serde_json::Value,
+}
diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs
index 172c0de2ef9..f0591e9b26d 100644
--- a/crates/router/src/connector/utils.rs
+++ b/crates/router/src/connector/utils.rs
@@ -61,6 +61,7 @@ pub trait RouterData {
     where
         T: serde::de::DeserializeOwned;
     fn is_three_ds(&self) -> bool;
+    fn get_payment_method_token(&self) -> Result<String, Error>;
 }
 
 impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Response> {
@@ -139,6 +140,11 @@ impl<Flow, Request, Response> RouterData for types::RouterData<Flow, Request, Re
             .and_then(|a| a.address.as_ref())
             .ok_or_else(missing_field_err("shipping.address"))
     }
+    fn get_payment_method_token(&self) -> Result<String, Error> {
+        self.payment_method_token
+            .clone()
+            .ok_or_else(missing_field_err("payment_method_token"))
+    }
 }
 
 pub trait PaymentsAuthorizeRequestData {
diff --git a/crates/router/tests/connectors/checkout.rs b/crates/router/tests/connectors/checkout.rs
index a1869f2ff57..70e537fc7d5 100644
--- a/crates/router/tests/connectors/checkout.rs
+++ b/crates/router/tests/connectors/checkout.rs
@@ -1,317 +1,479 @@
-use std::marker::PhantomData;
+use masking::Secret;
+use router::types::{self, api, storage::enums};
 
-use router::{
-    core::payments,
-    db::StorageImpl,
-    routes,
-    types::{self, api, storage::enums, PaymentAddress},
+use crate::{
+    connector_auth,
+    utils::{self, ConnectorActions},
 };
 
-use crate::connector_auth::ConnectorAuthentication;
+#[derive(Clone, Copy)]
+struct CheckoutTest;
+impl ConnectorActions for CheckoutTest {}
+impl utils::Connector for CheckoutTest {
+    fn get_data(&self) -> types::api::ConnectorData {
+        use router::connector::Checkout;
+        types::api::ConnectorData {
+            connector: Box::new(&Checkout),
+            connector_name: types::Connector::Checkout,
+            get_token: types::api::GetToken::Connector,
+        }
+    }
 
-fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
-    let auth = ConnectorAuthentication::new()
-        .checkout
-        .expect("Missing Checkout connector authentication configuration");
+    fn get_auth_token(&self) -> types::ConnectorAuthType {
+        types::ConnectorAuthType::from(
+            connector_auth::ConnectorAuthentication::new()
+                .checkout
+                .expect("Missing connector authentication configuration"),
+        )
+    }
 
-    types::RouterData {
-        flow: PhantomData,
-        merchant_id: "checkout".to_string(),
-        connector: "checkout".to_string(),
-        payment_id: uuid::Uuid::new_v4().to_string(),
-        attempt_id: uuid::Uuid::new_v4().to_string(),
-        status: enums::AttemptStatus::default(),
-        auth_type: enums::AuthenticationType::NoThreeDs,
-        payment_method: enums::PaymentMethod::Card,
-        connector_auth_type: auth.into(),
-        description: Some("This is a test".to_string()),
-        return_url: None,
-        request: types::PaymentsAuthorizeData {
-            amount: 100,
-            currency: enums::Currency::USD,
-            payment_method_data: types::api::PaymentMethodData::Card(api::Card {
-                card_number: "4242424242424242".to_string().into(),
-                card_exp_month: "10".to_string().into(),
-                card_exp_year: "35".to_string().into(),
-                card_holder_name: "John Doe".to_string().into(),
-                card_cvc: "123".to_string().into(),
-                card_issuer: None,
-                card_network: None,
-            }),
-            confirm: true,
-            statement_descriptor_suffix: None,
-            statement_descriptor: None,
-            setup_future_usage: None,
-            mandate_id: None,
-            off_session: None,
-            setup_mandate_details: None,
-            capture_method: None,
-            browser_info: None,
-            order_details: None,
-            email: None,
-            session_token: None,
-            enrolled_for_3ds: false,
-            related_transaction_id: None,
-            payment_experience: None,
-            payment_method_type: None,
-            router_return_url: None,
-            webhook_url: None,
-            complete_authorize_url: None,
-        },
-        response: Err(types::ErrorResponse::default()),
-        payment_method_id: None,
-        address: PaymentAddress::default(),
-        connector_meta_data: None,
-        amount_captured: None,
-        access_token: None,
-        session_token: None,
-        reference_id: None,
-        payment_method_token: None,
+    fn get_name(&self) -> String {
+        "checkout".to_string()
     }
 }
 
-fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
-    let auth = ConnectorAuthentication::new()
-        .checkout
-        .expect("Missing Checkout connector authentication configuration");
+static CONNECTOR: CheckoutTest = CheckoutTest {};
 
-    types::RouterData {
-        flow: PhantomData,
-        connector_meta_data: None,
-        merchant_id: "checkout".to_string(),
-        connector: "checkout".to_string(),
-        payment_id: uuid::Uuid::new_v4().to_string(),
-        attempt_id: uuid::Uuid::new_v4().to_string(),
-        status: enums::AttemptStatus::default(),
-        payment_method: enums::PaymentMethod::Card,
-        auth_type: enums::AuthenticationType::NoThreeDs,
-        connector_auth_type: auth.into(),
-        description: Some("This is a test".to_string()),
-        return_url: None,
-        request: types::RefundsData {
-            amount: 100,
-            currency: enums::Currency::USD,
-            refund_id: uuid::Uuid::new_v4().to_string(),
-            connector_transaction_id: String::new(),
-            refund_amount: 10,
-            connector_metadata: None,
-            reason: None,
-            connector_refund_id: None,
-        },
-        response: Err(types::ErrorResponse::default()),
-        payment_method_id: None,
-        address: PaymentAddress::default(),
-        amount_captured: None,
-        access_token: None,
-        session_token: None,
-        reference_id: None,
-        payment_method_token: None,
-    }
+fn get_default_payment_info() -> Option<utils::PaymentInfo> {
+    None
+}
+
+fn payment_method_details() -> Option<types::PaymentsAuthorizeData> {
+    None
+}
+
+// Cards Positive Tests
+// Creates a payment using the manual capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_only_authorize_payment() {
+    let response = CONNECTOR
+        .authorize_payment(payment_method_details(), get_default_payment_info())
+        .await
+        .expect("Authorize payment response");
+    assert_eq!(response.status, enums::AttemptStatus::Authorized);
 }
 
+// Captures a payment using the manual capture flow (Non 3DS).
+#[serial_test::serial]
 #[actix_web::test]
-#[ignore]
-async fn test_checkout_payment_success() {
-    use router::{configs::settings::Settings, connector::Checkout, services};
+async fn should_capture_authorized_payment() {
+    let response = CONNECTOR
+        .authorize_and_capture_payment(payment_method_details(), None, get_default_payment_info())
+        .await
+        .expect("Capture payment response");
+    assert_eq!(response.status, enums::AttemptStatus::Charged);
+}
 
-    let conf = Settings::new().unwrap();
-    static CV: Checkout = Checkout;
-    let connector = types::api::ConnectorData {
-        connector: Box::new(&CV),
-        connector_name: types::Connector::Checkout,
-        get_token: types::api::GetToken::Connector,
-    };
-    let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
-    let connector_integration: services::BoxedConnectorIntegration<
-        '_,
-        types::api::Authorize,
-        types::PaymentsAuthorizeData,
-        types::PaymentsResponseData,
-    > = connector.connector.get_connector_integration();
-    let request = construct_payment_router_data();
+// Partially captures a payment using the manual capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_partially_capture_authorized_payment() {
+    let response = CONNECTOR
+        .authorize_and_capture_payment(
+            payment_method_details(),
+            Some(types::PaymentsCaptureData {
+                amount_to_capture: 50,
+                ..utils::PaymentCaptureType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .expect("Capture payment response");
+    assert_eq!(response.status, enums::AttemptStatus::Charged);
+}
 
-    let response = services::api::execute_connector_processing_step(
-        &state,
-        connector_integration,
-        &request,
-        payments::CallConnectorAction::Trigger,
-    )
-    .await
-    .unwrap();
+// Synchronizes a payment using the manual capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_sync_authorized_payment() {
+    let authorize_response = CONNECTOR
+        .authorize_payment(payment_method_details(), get_default_payment_info())
+        .await
+        .expect("Authorize payment response");
+    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
+    let response = CONNECTOR
+        .psync_retry_till_status_matches(
+            enums::AttemptStatus::Authorized,
+            Some(types::PaymentsSyncData {
+                connector_transaction_id: router::types::ResponseId::ConnectorTransactionId(
+                    txn_id.unwrap(),
+                ),
+                ..Default::default()
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .expect("PSync response");
+    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
+}
 
-    println!("{response:?}");
+// Voids a payment using the manual capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_void_authorized_payment() {
+    let response = CONNECTOR
+        .authorize_and_void_payment(
+            payment_method_details(),
+            Some(types::PaymentsCancelData {
+                connector_transaction_id: String::from(""),
+                cancellation_reason: Some("requested_by_customer".to_string()),
+                ..Default::default()
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .expect("Void payment response");
+    assert_eq!(response.status, enums::AttemptStatus::Voided);
+}
 
-    assert!(
-        response.status == enums::AttemptStatus::Charged,
-        "The payment failed"
+// Refunds a payment using the manual capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_refund_manually_captured_payment() {
+    let response = CONNECTOR
+        .capture_payment_and_refund(
+            payment_method_details(),
+            None,
+            None,
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
     );
 }
 
+// Partially refunds a payment using the manual capture flow (Non 3DS).
+#[serial_test::serial]
 #[actix_web::test]
-#[ignore]
-async fn test_checkout_refund_success() {
-    // Successful payment
-    use router::{configs::settings::Settings, connector::Checkout, services};
+async fn should_partially_refund_manually_captured_payment() {
+    let response = CONNECTOR
+        .capture_payment_and_refund(
+            payment_method_details(),
+            None,
+            Some(types::RefundsData {
+                refund_amount: 50,
+                ..utils::PaymentRefundType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
 
-    let conf = Settings::new().expect("invalid settings");
-    let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
-    static CV: Checkout = Checkout;
-    let connector = types::api::ConnectorData {
-        connector: Box::new(&CV),
-        connector_name: types::Connector::Checkout,
-        get_token: types::api::GetToken::Connector,
-    };
-    let connector_integration: services::BoxedConnectorIntegration<
-        '_,
-        types::api::Authorize,
-        types::PaymentsAuthorizeData,
-        types::PaymentsResponseData,
-    > = connector.connector.get_connector_integration();
-    let request = construct_payment_router_data();
+// Synchronizes a refund using the manual capture flow (Non 3DS).
+#[actix_web::test]
+#[ignore = "Connector Error, needs to be looked into and fixed"]
+async fn should_sync_manually_captured_refund() {
+    let refund_response = CONNECTOR
+        .capture_payment_and_refund(
+            payment_method_details(),
+            None,
+            None,
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    let response = CONNECTOR
+        .rsync_retry_till_status_matches(
+            enums::RefundStatus::Success,
+            refund_response.response.unwrap().connector_refund_id,
+            None,
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
 
-    let response = services::api::execute_connector_processing_step(
-        &state,
-        connector_integration,
-        &request,
-        payments::CallConnectorAction::Trigger,
-    )
-    .await
-    .unwrap();
+// Creates a payment using the automatic capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_make_payment() {
+    let authorize_response = CONNECTOR
+        .make_payment(payment_method_details(), get_default_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
+}
 
-    println!("{response:?}");
+// Synchronizes a payment using the automatic capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_sync_auto_captured_payment() {
+    let authorize_response = CONNECTOR
+        .make_payment(payment_method_details(), get_default_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
+    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
+    assert_ne!(txn_id, None, "Empty connector transaction id");
+    let response = CONNECTOR
+        .psync_retry_till_status_matches(
+            enums::AttemptStatus::Charged,
+            Some(types::PaymentsSyncData {
+                connector_transaction_id: router::types::ResponseId::ConnectorTransactionId(
+                    txn_id.unwrap(),
+                ),
+                capture_method: Some(enums::CaptureMethod::Automatic),
+                ..Default::default()
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(response.status, enums::AttemptStatus::Charged,);
+}
 
-    assert!(
-        response.status == enums::AttemptStatus::Charged,
-        "The payment failed"
+// Refunds a payment using the automatic capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_refund_auto_captured_payment() {
+    let response = CONNECTOR
+        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
     );
-    // Successful refund
-    let connector_integration: services::BoxedConnectorIntegration<
-        '_,
-        types::api::Execute,
-        types::RefundsData,
-        types::RefundsResponseData,
-    > = connector.connector.get_connector_integration();
-    let mut refund_request = construct_refund_router_data();
-
-    refund_request.request.connector_transaction_id = match response.response.unwrap() {
-        types::PaymentsResponseData::TransactionResponse { resource_id, .. } => {
-            resource_id.get_connector_transaction_id().unwrap()
-        }
-        _ => panic!("Connector transaction id not found"),
-    };
+}
 
-    let response = services::api::execute_connector_processing_step(
-        &state,
-        connector_integration,
-        &refund_request,
-        payments::CallConnectorAction::Trigger,
-    )
-    .await;
+// Partially refunds a payment using the automatic capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_partially_refund_succeeded_payment() {
+    let refund_response = CONNECTOR
+        .make_payment_and_refund(
+            payment_method_details(),
+            Some(types::RefundsData {
+                refund_amount: 50,
+                ..utils::PaymentRefundType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        refund_response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
 
-    let response = response.unwrap();
-    println!("{response:?}");
+// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_refund_succeeded_payment_multiple_times() {
+    CONNECTOR
+        .make_payment_and_multiple_refund(
+            payment_method_details(),
+            Some(types::RefundsData {
+                refund_amount: 50,
+                ..utils::PaymentRefundType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await;
+}
 
-    assert!(
-        response.response.unwrap().refund_status == enums::RefundStatus::Success,
-        "The refund failed"
+// Synchronizes a refund using the automatic capture flow (Non 3DS).
+#[actix_web::test]
+#[ignore = "Connector Error, needs to be looked into and fixed"]
+async fn should_sync_refund() {
+    let refund_response = CONNECTOR
+        .make_payment_and_refund(payment_method_details(), None, get_default_payment_info())
+        .await
+        .unwrap();
+    tokio::time::sleep(std::time::Duration::from_secs(5)).await;
+    let response = CONNECTOR
+        .rsync_retry_till_status_matches(
+            enums::RefundStatus::Success,
+            refund_response.response.unwrap().connector_refund_id,
+            None,
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
     );
 }
 
+// Cards Negative scenerios
+// Creates a payment with incorrect card number.
+#[serial_test::serial]
 #[actix_web::test]
-async fn test_checkout_payment_failure() {
-    use router::{configs::settings::Settings, connector::Checkout, services};
-
-    let conf = Settings::new().expect("invalid settings");
-    let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
-    static CV: Checkout = Checkout;
-    let connector = types::api::ConnectorData {
-        connector: Box::new(&CV),
-        connector_name: types::Connector::Checkout,
-        get_token: types::api::GetToken::Connector,
-    };
-    let connector_integration: services::BoxedConnectorIntegration<
-        '_,
-        types::api::Authorize,
-        types::PaymentsAuthorizeData,
-        types::PaymentsResponseData,
-    > = connector.connector.get_connector_integration();
-    let mut request = construct_payment_router_data();
-    request.connector_auth_type = types::ConnectorAuthType::BodyKey {
-        api_key: "".to_string(),
-        key1: "".to_string(),
-    };
-    let response = services::api::execute_connector_processing_step(
-        &state,
-        connector_integration,
-        &request,
-        payments::CallConnectorAction::Trigger,
-    )
-    .await;
-    assert!(response.is_err(), "The payment passed");
+async fn should_fail_payment_for_incorrect_card_number() {
+    let response = CONNECTOR
+        .make_payment(
+            Some(types::PaymentsAuthorizeData {
+                payment_method_data: types::api::PaymentMethodData::Card(api::Card {
+                    card_number: Secret::new("1234567891011".to_string()),
+                    ..utils::CCardType::default().0
+                }),
+                ..utils::PaymentAuthorizeType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap_err().code,
+        "card_number_invalid".to_string(),
+    );
 }
+
+// Creates a payment with empty card number.
+#[serial_test::serial]
 #[actix_web::test]
-#[ignore]
-async fn test_checkout_refund_failure() {
-    use router::{configs::settings::Settings, connector::Checkout, services};
+async fn should_fail_payment_for_empty_card_number() {
+    let response = CONNECTOR
+        .make_payment(
+            Some(types::PaymentsAuthorizeData {
+                payment_method_data: types::api::PaymentMethodData::Card(api::Card {
+                    card_number: Secret::new(String::from("")),
+                    ..utils::CCardType::default().0
+                }),
+                ..utils::PaymentAuthorizeType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    let x = response.response.unwrap_err();
+    assert_eq!(x.code, "card_number_required",);
+}
 
-    let conf = Settings::new().expect("invalid settings");
-    let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
-    static CV: Checkout = Checkout;
-    let connector = types::api::ConnectorData {
-        connector: Box::new(&CV),
-        connector_name: types::Connector::Checkout,
-        get_token: types::api::GetToken::Connector,
-    };
-    let connector_integration: services::BoxedConnectorIntegration<
-        '_,
-        types::api::Authorize,
-        types::PaymentsAuthorizeData,
-        types::PaymentsResponseData,
-    > = connector.connector.get_connector_integration();
-    let request = construct_payment_router_data();
+// Creates a payment with incorrect CVC.
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_fail_payment_for_incorrect_cvc() {
+    let response = CONNECTOR
+        .make_payment(
+            Some(types::PaymentsAuthorizeData {
+                payment_method_data: types::api::PaymentMethodData::Card(api::Card {
+                    card_cvc: Secret::new("12345".to_string()),
+                    ..utils::CCardType::default().0
+                }),
+                ..utils::PaymentAuthorizeType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap_err().code,
+        "cvv_invalid".to_string(),
+    );
+}
 
-    let response = services::api::execute_connector_processing_step(
-        &state,
-        connector_integration,
-        &request,
-        payments::CallConnectorAction::Trigger,
-    )
-    .await
-    .unwrap();
+// Creates a payment with incorrect expiry month.
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_fail_payment_for_invalid_exp_month() {
+    let response = CONNECTOR
+        .make_payment(
+            Some(types::PaymentsAuthorizeData {
+                payment_method_data: types::api::PaymentMethodData::Card(api::Card {
+                    card_exp_month: Secret::new("20".to_string()),
+                    ..utils::CCardType::default().0
+                }),
+                ..utils::PaymentAuthorizeType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap_err().code,
+        "card_expiry_month_invalid".to_string(),
+    );
+}
 
-    assert!(
-        response.status == enums::AttemptStatus::Charged,
-        "The payment failed"
+// Creates a payment with incorrect expiry year.
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_fail_payment_for_incorrect_expiry_year() {
+    let response = CONNECTOR
+        .make_payment(
+            Some(types::PaymentsAuthorizeData {
+                payment_method_data: types::api::PaymentMethodData::Card(api::Card {
+                    card_exp_year: Secret::new("2000".to_string()),
+                    ..utils::CCardType::default().0
+                }),
+                ..utils::PaymentAuthorizeType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap_err().code,
+        "card_expired".to_string(),
     );
-    // Unsuccessful refund
-    let connector_integration: services::BoxedConnectorIntegration<
-        '_,
-        types::api::Execute,
-        types::RefundsData,
-        types::RefundsResponseData,
-    > = connector.connector.get_connector_integration();
-    let mut refund_request = construct_refund_router_data();
-    refund_request.request.connector_transaction_id = match response.response.unwrap() {
-        types::PaymentsResponseData::TransactionResponse { resource_id, .. } => {
-            resource_id.get_connector_transaction_id().unwrap()
-        }
-        _ => panic!("Connector transaction id not found"),
-    };
+}
 
-    // Higher amount than that of payment
-    refund_request.request.refund_amount = 696969;
-    let response = services::api::execute_connector_processing_step(
-        &state,
-        connector_integration,
-        &refund_request,
-        payments::CallConnectorAction::Trigger,
-    )
-    .await;
+// Voids a payment using automatic capture flow (Non 3DS).
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_fail_void_payment_for_auto_capture() {
+    let authorize_response = CONNECTOR
+        .make_payment(payment_method_details(), get_default_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
+    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
+    assert_ne!(txn_id, None, "Empty connector transaction id");
+    let void_response = CONNECTOR
+        .void_payment(txn_id.unwrap(), None, get_default_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(void_response.response.unwrap_err().status_code, 403);
+}
 
-    println!("{response:?}");
-    let response = response.unwrap();
-    assert!(response.response.is_err());
+// Captures a payment using invalid connector payment id.
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_fail_capture_for_invalid_payment() {
+    let capture_response = CONNECTOR
+        .capture_payment("123456789".to_string(), None, get_default_payment_info())
+        .await
+        .unwrap();
+    assert_eq!(capture_response.response.unwrap_err().status_code, 404);
+}
 
-    let code = response.response.unwrap_err().code;
-    assert_eq!(code, "refund_amount_exceeds_balance");
+// Refunds a payment with refund amount higher than payment amount.
+#[serial_test::serial]
+#[actix_web::test]
+async fn should_fail_for_refund_amount_higher_than_payment_amount() {
+    let response = CONNECTOR
+        .make_payment_and_refund(
+            payment_method_details(),
+            Some(types::RefundsData {
+                refund_amount: 150,
+                ..utils::PaymentRefundType::default().0
+            }),
+            get_default_payment_info(),
+        )
+        .await
+        .unwrap();
+    assert_eq!(
+        response.response.unwrap_err().code,
+        "refund_amount_exceeds_balance",
+    );
 }
+
+// Connector dependent test cases goes here
+
+// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests
diff --git a/crates/router/tests/connectors/connector_auth.rs b/crates/router/tests/connectors/connector_auth.rs
index 32d235874e9..dbfa5147720 100644
--- a/crates/router/tests/connectors/connector_auth.rs
+++ b/crates/router/tests/connectors/connector_auth.rs
@@ -11,7 +11,7 @@ pub(crate) struct ConnectorAuthentication {
     pub authorizedotnet: Option<BodyKey>,
     pub bambora: Option<BodyKey>,
     pub bluesnap: Option<BodyKey>,
-    pub checkout: Option<BodyKey>,
+    pub checkout: Option<SignatureKey>,
     pub coinbase: Option<HeaderKey>,
     pub cybersource: Option<SignatureKey>,
     pub dlocal: Option<SignatureKey>,
diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml
index 4a43bde4727..5892e409c54 100644
--- a/crates/router/tests/connectors/sample_auth.toml
+++ b/crates/router/tests/connectors/sample_auth.toml
@@ -14,7 +14,8 @@ api_key = "MyMerchantName"
 key1 = "MyTransactionKey"
 
 [checkout]
-api_key = "Bearer MyApiKey"
+api_key = "Bearer PublicKey"
+api_secret = "Bearer SecretKey"
 key1 = "MyProcessingChannelId"
 
 [cybersource]

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

- [ ] Bugfix
- [X] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates

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

- Added Wallets ( GooglePay, ApplePay ) and Webhooks support for [checkout](https://www.checkout.com/docs) 
- Introduced tokenization and then called the respective endpoint to make wallet payment [GooglePay](https://www.checkout.com/docs/payments/payment-methods/google-pay), [ApplePay](https://www.checkout.com/docs/payments/payment-methods/apple-pay)
- Payments, Refunds, Disputes [Webhooks](https://www.checkout.com/docs/workflows) are integrated



### Additional Changes

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

The Authentication Type for Checkout has been changed to `SignatureKey` to accommodate additional key for tokenization of wallet_data.
Encrypted secret file is also being pushed along to accommodate the change for sanity tests.

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

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


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

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

Closes #916 


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Introduced all the basic unit tests, `Rsync` is ignored as it is throwing error from connector side although working in Postman.

`ApplePay` is not tested due to token availability issue.

![Screenshot 2023-04-13 at 4 38 36 PM](https://user-images.githubusercontent.com/55536657/231742922-03afe2dd-edc5-478f-bf5c-d55352a0dfc9.png)


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

- [X] I formatted the code `cargo +nightly fmt --all`
- [X] I addressed lints thrown by `cargo clippy`
- [X] I reviewed submitted code
- [X] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
