Bug: Add Cybersource for card payments




diff --git a/config/Development.toml b/config/Development.toml
index bc2b912fa37..f14f2300065 100644
--- a/config/Development.toml
+++ b/config/Development.toml
@@ -38,7 +38,7 @@ locker_decryption_key2 = ""
 
 [connectors.supported]
 wallets = ["klarna","braintree","applepay"]
-cards = ["stripe","adyen","authorizedotnet","checkout","braintree","aci","shift4"]
+cards = ["stripe","adyen","authorizedotnet","checkout","braintree","aci","shift4","cybersource"]
 
 [eph_key]
 validity = 1
@@ -67,6 +67,9 @@ base_url = "https://api-na.playground.klarna.com/"
 [connectors.applepay]
 base_url = "https://apple-pay-gateway.apple.com/"
 
+[connectors.cybersource]
+base_url = "https://apitest.cybersource.com/"
+
 [connectors.shift4]
 base_url = "https://api.shift4.com/"
 
diff --git a/config/config.example.toml b/config/config.example.toml
index 6e9f4d152c0..196155c8182 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -119,14 +119,16 @@ base_url = "https://api-na.playground.klarna.com/"
 [connectors.applepay]
 base_url = "https://apple-pay-gateway.apple.com/"
 
+[connectors.cybersource]
+base_url = "https://apitest.cybersource.com/"
+
 [connectors.shift4]
 base_url = "https://api.shift4.com/"
 
 # This data is used to call respective connectors for wallets and cards
 [connectors.supported]
 wallets = ["klarna","braintree","applepay"]
-cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
-
+cards = ["stripe","adyen","authorizedotnet","checkout","braintree", "cybersource"]
 
 # Scheduler settings provides a point to modify the behaviour of scheduler flow.
 # It defines the the streams/queues name and configuration as well as event selection variables
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index 58a22c7c5c6..265aefe903b 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -74,9 +74,12 @@ base_url = "https://api-na.playground.klarna.com/"
 [connectors.applepay]
 base_url = "https://apple-pay-gateway.apple.com/"
 
+[connectors.cybersource]
+base_url = "https://apitest.cybersource.com/"
+
 [connectors.shift4]
 base_url = "https://api.shift4.com/"
 
 [connectors.supported]
 wallets = ["klarna","braintree","applepay"]
-cards = ["stripe","adyen","authorizedotnet","checkout","braintree","shift4"]
+cards = ["stripe","adyen","authorizedotnet","checkout","braintree","shift4","cybersource"]
diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs
index e37de90ba7e..48c5a32a9d2 100644
--- a/crates/api_models/src/enums.rs
+++ b/crates/api_models/src/enums.rs
@@ -491,6 +491,7 @@ pub enum Connector {
     Authorizedotnet,
     Braintree,
     Checkout,
+    Cybersource,
     #[default]
     Dummy,
     Klarna,
diff --git a/crates/router/src/configs/defaults.toml b/crates/router/src/configs/defaults.toml
index c6680ebaacf..5ccfaefe39b 100644
--- a/crates/router/src/configs/defaults.toml
+++ b/crates/router/src/configs/defaults.toml
@@ -57,5 +57,5 @@ num_partitions = 64
 max_read_count = 100
 
 [connectors.supported]
-wallets = ["klarna", "braintree"]
-cards = ["stripe", "adyen", "authorizedotnet", "checkout", "braintree"]
+wallets = ["klarna","braintree"]
+cards = ["stripe","adyen","authorizedotnet","checkout","braintree", "cybersource"]
diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs
index e0cc902531b..f5e8e744318 100644
--- a/crates/router/src/configs/settings.rs
+++ b/crates/router/src/configs/settings.rs
@@ -113,6 +113,7 @@ pub struct Connectors {
     pub braintree: ConnectorParams,
     pub checkout: ConnectorParams,
     pub klarna: ConnectorParams,
+    pub cybersource: ConnectorParams,
     pub shift4: ConnectorParams,
     pub stripe: ConnectorParams,
     pub supported: SupportedConnectors,
diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs
index 9476a026693..9b598df8f34 100644
--- a/crates/router/src/connector.rs
+++ b/crates/router/src/connector.rs
@@ -4,6 +4,7 @@ pub mod applepay;
 pub mod authorizedotnet;
 pub mod braintree;
 pub mod checkout;
+pub mod cybersource;
 pub mod klarna;
 pub mod stripe;
 
@@ -11,5 +12,6 @@ pub mod shift4;
 
 pub use self::{
     aci::Aci, adyen::Adyen, applepay::Applepay, authorizedotnet::Authorizedotnet,
-    braintree::Braintree, checkout::Checkout, klarna::Klarna, shift4::Shift4, stripe::Stripe,
+    braintree::Braintree, checkout::Checkout, cybersource::Cybersource, klarna::Klarna,
+    shift4::Shift4, stripe::Stripe,
 };
diff --git a/crates/router/src/connector/cybersource.rs b/crates/router/src/connector/cybersource.rs
new file mode 100644
index 00000000000..6bdb1f22a6d
--- /dev/null
+++ b/crates/router/src/connector/cybersource.rs
@@ -0,0 +1,303 @@
+mod transformers;
+
+use std::fmt::Debug;
+
+use base64;
+use bytes::Bytes;
+use error_stack::{IntoReport, ResultExt};
+use ring::{digest, hmac};
+use time::OffsetDateTime;
+use transformers as cybersource;
+use url::Url;
+
+use crate::{
+    configs::settings,
+    consts,
+    core::errors::{self, CustomResult},
+    headers, logger, services,
+    types::{self, api},
+    utils::{self, BytesExt},
+};
+
+#[derive(Debug, Clone)]
+pub struct Cybersource;
+
+impl Cybersource {
+    pub fn generate_digest(&self, payload: &[u8]) -> String {
+        let payload_digest = digest::digest(&digest::SHA256, payload);
+        base64::encode(payload_digest)
+    }
+
+    pub fn generate_signature(
+        &self,
+        auth: cybersource::CybersourceAuthType,
+        host: String,
+        resource: &str,
+        payload: &str,
+        date: OffsetDateTime,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        let cybersource::CybersourceAuthType {
+            api_key,
+            merchant_account,
+            api_secret,
+        } = auth;
+
+        let headers_for_post_method = "host date (request-target) digest v-c-merchant-id";
+        let signature_string = format!(
+            "host: {host}\n\
+             date: {date}\n\
+             (request-target): post {resource}\n\
+             digest: SHA-256={}\n\
+             v-c-merchant-id: {merchant_account}",
+            self.generate_digest(payload.as_bytes())
+        );
+        let key_value = base64::decode(api_secret)
+            .into_report()
+            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        let key = hmac::Key::new(hmac::HMAC_SHA256, &key_value);
+        let signature_value =
+            base64::encode(hmac::sign(&key, signature_string.as_bytes()).as_ref());
+        let signature_header = format!(
+            r#"keyid="{api_key}", algorithm="HmacSHA256", headers="{headers_for_post_method}", signature="{signature_value}""#
+        );
+
+        Ok(signature_header)
+    }
+}
+
+impl api::ConnectorCommon for Cybersource {
+    fn id(&self) -> &'static str {
+        "cybersource"
+    }
+
+    fn common_get_content_type(&self) -> &'static str {
+        "application/json"
+    }
+
+    fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
+        connectors.cybersource.base_url.as_ref()
+    }
+}
+
+impl api::Payment for Cybersource {}
+impl api::PaymentAuthorize for Cybersource {}
+impl api::PaymentSync for Cybersource {}
+impl api::PaymentVoid for Cybersource {}
+impl api::PaymentCapture for Cybersource {}
+impl api::PreVerify for Cybersource {}
+
+impl
+    services::ConnectorIntegration<
+        api::Verify,
+        types::VerifyRequestData,
+        types::PaymentsResponseData,
+    > for Cybersource
+{
+}
+
+impl api::PaymentSession for Cybersource {}
+
+impl
+    services::ConnectorIntegration<
+        api::Session,
+        types::PaymentsSessionData,
+        types::PaymentsResponseData,
+    > for Cybersource
+{
+}
+
+impl
+    services::ConnectorIntegration<
+        api::Capture,
+        types::PaymentsCaptureData,
+        types::PaymentsResponseData,
+    > for Cybersource
+{
+}
+
+impl
+    services::ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
+    for Cybersource
+{
+}
+
+impl
+    services::ConnectorIntegration<
+        api::Authorize,
+        types::PaymentsAuthorizeData,
+        types::PaymentsResponseData,
+    > for Cybersource
+{
+    fn get_headers(
+        &self,
+        _req: &types::PaymentsAuthorizeRouterData,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        let headers = vec![
+            (
+                headers::CONTENT_TYPE.to_string(),
+                types::PaymentsAuthorizeType::get_content_type(self).to_string(),
+            ),
+            (
+                headers::ACCEPT.to_string(),
+                "application/hal+json;charset=utf-8".to_string(),
+            ),
+        ];
+        Ok(headers)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        "application/json;charset=utf-8"
+    }
+
+    fn get_url(
+        &self,
+        _req: &types::PaymentsAuthorizeRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!(
+            "{}pts/v2/payments/",
+            api::ConnectorCommon::base_url(self, connectors)
+        ))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsAuthorizeRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        let date = OffsetDateTime::now_utc();
+
+        let cybersource_req =
+            utils::Encode::<cybersource::CybersourcePaymentsRequest>::convert_and_encode(req)
+                .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        let auth: cybersource::CybersourceAuthType =
+            cybersource::CybersourceAuthType::try_from(&req.connector_auth_type)?;
+        let merchant_account = auth.merchant_account.clone();
+
+        let cybersource_host = Url::parse(connectors.cybersource.base_url.as_str())
+            .into_report()
+            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        match cybersource_host.host_str() {
+            Some(host) => {
+                let signature = self.generate_signature(
+                    auth,
+                    host.to_string(),
+                    "/pts/v2/payments/",
+                    &cybersource_req,
+                    date,
+                )?;
+                let headers = vec![
+                    (
+                        "Digest".to_string(),
+                        format!(
+                            "SHA-256={}",
+                            self.generate_digest(cybersource_req.as_bytes())
+                        ),
+                    ),
+                    ("v-c-merchant-id".to_string(), merchant_account),
+                    ("Date".to_string(), date.to_string()),
+                    ("Host".to_string(), host.to_string()),
+                    ("Signature".to_string(), signature),
+                ];
+                let request = services::RequestBuilder::new()
+                    .method(services::Method::Post)
+                    .url(&types::PaymentsAuthorizeType::get_url(
+                        self, req, connectors,
+                    )?)
+                    .headers(headers)
+                    .headers(types::PaymentsAuthorizeType::get_headers(self, req)?)
+                    .body(Some(cybersource_req))
+                    .build();
+
+                Ok(Some(request))
+            }
+            None => Err(errors::ConnectorError::RequestEncodingFailed.into()),
+        }
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsAuthorizeRouterData,
+        res: types::Response,
+    ) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
+        let response: cybersource::CybersourcePaymentsResponse = res
+            .response
+            .parse_struct("Cybersource PaymentResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        logger::debug!(cybersourcepayments_create_response=?response);
+        types::ResponseRouterData {
+            response,
+            data: data.clone(),
+            http_code: res.status_code,
+        }
+        .try_into()
+        .change_context(errors::ConnectorError::ResponseHandlingFailed)
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<types::ErrorResponse, errors::ConnectorError> {
+        let response: cybersource::ErrorResponse = res
+            .parse_struct("Cybersource ErrorResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        Ok(types::ErrorResponse {
+            code: consts::NO_ERROR_CODE.to_string(),
+            message: response
+                .message
+                .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()),
+            reason: None,
+        })
+    }
+}
+
+impl
+    services::ConnectorIntegration<
+        api::Void,
+        types::PaymentsCancelData,
+        types::PaymentsResponseData,
+    > for Cybersource
+{
+}
+
+impl api::Refund for Cybersource {}
+impl api::RefundExecute for Cybersource {}
+impl api::RefundSync for Cybersource {}
+
+#[allow(dead_code)]
+impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
+    for Cybersource
+{
+}
+
+#[allow(dead_code)]
+impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData>
+    for Cybersource
+{
+}
+
+#[async_trait::async_trait]
+impl api::IncomingWebhook for Cybersource {
+    fn get_webhook_object_reference_id(
+        &self,
+        _body: &[u8],
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Err(errors::ConnectorError::NotImplemented("cybersource".to_string()).into())
+    }
+
+    fn get_webhook_event_type(
+        &self,
+        _body: &[u8],
+    ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
+        Err(errors::ConnectorError::NotImplemented("cybersource".to_string()).into())
+    }
+
+    fn get_webhook_resource_object(
+        &self,
+        _body: &[u8],
+    ) -> CustomResult<serde_json::Value, errors::ConnectorError> {
+        Err(errors::ConnectorError::NotImplemented("cybersource".to_string()).into())
+    }
+}
+
+impl services::ConnectorRedirectResponse for Cybersource {}
diff --git a/crates/router/src/connector/cybersource/transformers.rs b/crates/router/src/connector/cybersource/transformers.rs
new file mode 100644
index 00000000000..7e1565e521b
--- /dev/null
+++ b/crates/router/src/connector/cybersource/transformers.rs
@@ -0,0 +1,316 @@
+use api_models::payments;
+use common_utils::pii;
+use masking::Secret;
+use serde::{Deserialize, Serialize};
+
+use crate::{
+    core::errors,
+    pii::PeekInterface,
+    types::{self, api, storage::enums},
+};
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct CybersourcePaymentsRequest {
+    processing_information: ProcessingInformation,
+    payment_information: PaymentInformation,
+    order_information: OrderInformationWithBill,
+}
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+pub struct ProcessingInformation {
+    capture: bool,
+}
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+pub struct PaymentInformation {
+    card: Card,
+}
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct Card {
+    number: String,
+    expiration_month: String,
+    expiration_year: String,
+    security_code: String,
+}
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct OrderInformationWithBill {
+    amount_details: Amount,
+    bill_to: BillTo,
+}
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct OrderInformation {
+    amount_details: Amount,
+}
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct Amount {
+    total_amount: String,
+    currency: String,
+}
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct BillTo {
+    first_name: Secret<String>,
+    last_name: Secret<String>,
+    address1: Secret<String>,
+    locality: String,
+    administrative_area: Secret<String>,
+    postal_code: Secret<String>,
+    country: String,
+    email: Secret<String, pii::Email>,
+    phone_number: Secret<String>,
+}
+
+// for cybersource each item in Billing is mandatory
+fn build_bill_to(
+    address_details: payments::Address,
+    email: Secret<String, pii::Email>,
+    phone_number: Secret<String>,
+) -> Option<BillTo> {
+    if let Some(api_models::payments::AddressDetails {
+        first_name: Some(f_name),
+        last_name: Some(last_name),
+        line1: Some(address1),
+        city: Some(city),
+        line2: Some(administrative_area),
+        zip: Some(postal_code),
+        country: Some(country),
+        ..
+    }) = address_details.address
+    {
+        Some(BillTo {
+            first_name: f_name,
+            last_name,
+            address1,
+            locality: city,
+            administrative_area,
+            postal_code,
+            country,
+            email,
+            phone_number,
+        })
+    } else {
+        None
+    }
+}
+
+impl TryFrom<&types::PaymentsAuthorizeRouterData> for CybersourcePaymentsRequest {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
+        match item.request.payment_method_data {
+            api::PaymentMethod::Card(ref ccard) => {
+                let address = item
+                    .address
+                    .billing
+                    .clone()
+                    .ok_or(errors::ConnectorError::RequestEncodingFailed)?;
+                let phone = address
+                    .clone()
+                    .phone
+                    .ok_or(errors::ConnectorError::RequestEncodingFailed)?;
+                let phone_number = phone
+                    .number
+                    .ok_or(errors::ConnectorError::RequestEncodingFailed)?;
+                let country_code = phone
+                    .country_code
+                    .ok_or(errors::ConnectorError::RequestEncodingFailed)?;
+                let number_with_code =
+                    Secret::new(format!("{}{}", country_code, phone_number.peek()));
+                let email = item
+                    .request
+                    .email
+                    .clone()
+                    .ok_or(errors::ConnectorError::RequestEncodingFailed)?;
+                let bill_to = build_bill_to(address, email, number_with_code)
+                    .ok_or(errors::ConnectorError::RequestEncodingFailed)?;
+
+                let order_information = OrderInformationWithBill {
+                    amount_details: Amount {
+                        total_amount: item.request.amount.to_string(),
+                        currency: item.request.currency.to_string().to_uppercase(),
+                    },
+                    bill_to,
+                };
+
+                let payment_information = PaymentInformation {
+                    card: Card {
+                        number: ccard.card_number.peek().clone(),
+                        expiration_month: ccard.card_exp_month.peek().clone(),
+                        expiration_year: ccard.card_exp_year.peek().clone(),
+                        security_code: ccard.card_cvc.peek().clone(),
+                    },
+                };
+
+                let processing_information = ProcessingInformation {
+                    capture: matches!(
+                        item.request.capture_method,
+                        Some(enums::CaptureMethod::Automatic) | None
+                    ),
+                };
+
+                Ok(Self {
+                    processing_information,
+                    payment_information,
+                    order_information,
+                })
+            }
+            _ => Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()),
+        }
+    }
+}
+
+pub struct CybersourceAuthType {
+    pub(super) api_key: String,
+    pub(super) merchant_account: String,
+    pub(super) api_secret: String,
+}
+
+impl TryFrom<&types::ConnectorAuthType> for CybersourceAuthType {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
+        if let types::ConnectorAuthType::SignatureKey {
+            api_key,
+            key1,
+            api_secret,
+        } = auth_type
+        {
+            Ok(Self {
+                api_key: api_key.to_string(),
+                merchant_account: key1.to_string(),
+                api_secret: api_secret.to_string(),
+            })
+        } else {
+            Err(errors::ConnectorError::FailedToObtainAuthType)?
+        }
+    }
+}
+#[derive(Debug, Default, Clone, Deserialize, Eq, PartialEq)]
+#[serde(rename_all = "UPPERCASE")]
+pub enum CybersourcePaymentStatus {
+    Authorized,
+    Succeeded,
+    Failed,
+    #[default]
+    Processing,
+}
+
+impl From<CybersourcePaymentStatus> for enums::AttemptStatus {
+    fn from(item: CybersourcePaymentStatus) -> Self {
+        match item {
+            CybersourcePaymentStatus::Authorized => Self::Authorized,
+            CybersourcePaymentStatus::Succeeded => Self::Charged,
+            CybersourcePaymentStatus::Failed => Self::Failure,
+            CybersourcePaymentStatus::Processing => Self::Authorizing,
+        }
+    }
+}
+
+#[derive(Default, Debug, Clone, Deserialize, Eq, PartialEq)]
+pub struct CybersourcePaymentsResponse {
+    id: String,
+    status: CybersourcePaymentStatus,
+}
+
+impl TryFrom<types::PaymentsResponseRouterData<CybersourcePaymentsResponse>>
+    for types::PaymentsAuthorizeRouterData
+{
+    type Error = error_stack::Report<errors::ParsingError>;
+    fn try_from(
+        item: types::PaymentsResponseRouterData<CybersourcePaymentsResponse>,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            status: item.response.status.into(),
+            response: Ok(types::PaymentsResponseData::TransactionResponse {
+                resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
+                redirection_data: None,
+                redirect: false,
+                mandate_reference: None,
+            }),
+            ..item.data
+        })
+    }
+}
+
+#[derive(Debug, Default, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ErrorResponse {
+    pub error_information: Option<ErrorInformation>,
+    pub status: String,
+    pub message: Option<String>,
+}
+
+#[derive(Debug, Default, Deserialize)]
+pub struct ErrorInformation {
+    pub message: String,
+    pub reason: String,
+}
+
+#[derive(Default, Debug, Serialize)]
+pub struct CybersourceRefundRequest {
+    order_information: OrderInformation,
+}
+
+impl<F> TryFrom<&types::RefundsRouterData<F>> for CybersourceRefundRequest {
+    type Error = error_stack::Report<errors::ParsingError>;
+    fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
+        Ok(Self {
+            order_information: OrderInformation {
+                amount_details: Amount {
+                    total_amount: item.request.amount.to_string(),
+                    currency: item.request.currency.to_string(),
+                },
+            },
+        })
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Debug, Default, Deserialize, Clone)]
+pub enum RefundStatus {
+    Succeeded,
+    Failed,
+    #[default]
+    Processing,
+}
+
+impl From<RefundStatus> for enums::RefundStatus {
+    fn from(item: RefundStatus) -> Self {
+        match item {
+            self::RefundStatus::Succeeded => Self::Success,
+            self::RefundStatus::Failed => Self::Failure,
+            self::RefundStatus::Processing => Self::Pending,
+        }
+    }
+}
+
+#[derive(Default, Debug, Clone, Deserialize)]
+pub struct CybersourceRefundResponse {
+    pub id: String,
+    pub status: RefundStatus,
+}
+
+impl TryFrom<types::RefundsResponseRouterData<api::RSync, CybersourceRefundResponse>>
+    for types::RefundsRouterData<api::RSync>
+{
+    type Error = error_stack::Report<errors::ParsingError>;
+    fn try_from(
+        item: types::RefundsResponseRouterData<api::RSync, CybersourceRefundResponse>,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            response: Ok(types::RefundsResponseData {
+                connector_refund_id: item.response.id,
+                refund_status: enums::RefundStatus::from(item.response.status),
+            }),
+            ..item.data
+        })
+    }
+}
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index b10478a1adc..8ca9322c75e 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -469,6 +469,7 @@ where
     pub refunds: Vec<storage::Refund>,
     pub sessions_token: Vec<api::SessionToken>,
     pub card_cvc: Option<pii::Secret<String>>,
+    pub email: Option<masking::Secret<String, pii::Email>>,
 }
 
 #[derive(Debug)]
diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs
index 5647f3dc5d6..6377231744f 100644
--- a/crates/router/src/core/payments/operations/payment_cancel.rs
+++ b/crates/router/src/core/payments/operations/payment_cancel.rs
@@ -113,6 +113,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsCancelRequest>
                     payment_attempt,
                     currency,
                     amount,
+                    email: None,
                     mandate_id: None,
                     setup_mandate: None,
                     token: None,
diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs
index 81620fb9e77..356ff837ea3 100644
--- a/crates/router/src/core/payments/operations/payment_capture.rs
+++ b/crates/router/src/core/payments/operations/payment_capture.rs
@@ -125,6 +125,7 @@ impl<F: Send + Clone> GetTracker<F, payments::PaymentData<F>, api::PaymentsCaptu
                 currency,
                 force_sync: None,
                 amount,
+                email: None,
                 mandate_id: None,
                 setup_mandate: None,
                 token: None,
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 93cd443a71c..e92bd7cafe0 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -142,6 +142,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
                     currency,
                     connector_response,
                     amount,
+                    email: request.email.clone(),
                     mandate_id: None,
                     setup_mandate,
                     token,
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index 33f1df2a88d..357416fe2b2 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -214,6 +214,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
                 payment_attempt,
                 currency,
                 amount,
+                email: request.email.clone(),
                 mandate_id,
                 setup_mandate,
                 token,
diff --git a/crates/router/src/core/payments/operations/payment_method_validate.rs b/crates/router/src/core/payments/operations/payment_method_validate.rs
index bc3aa5e89b8..5e9b510ca31 100644
--- a/crates/router/src/core/payments/operations/payment_method_validate.rs
+++ b/crates/router/src/core/payments/operations/payment_method_validate.rs
@@ -136,6 +136,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::VerifyRequest> for Paym
                 /// currency and amount are irrelevant in this scenario
                 currency: storage_enums::Currency::default(),
                 amount: api::Amount::Zero,
+                email: None,
                 mandate_id: None,
                 setup_mandate: request.mandate_data.clone(),
                 token: request.payment_token.clone(),
diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs
index 185889feaa0..9f940cf3963 100644
--- a/crates/router/src/core/payments/operations/payment_session.rs
+++ b/crates/router/src/core/payments/operations/payment_session.rs
@@ -13,6 +13,7 @@ use crate::{
         payments::{self, helpers, operations, PaymentData},
     },
     db::StorageInterface,
+    pii,
     pii::Secret,
     routes::AppState,
     types::{
@@ -131,6 +132,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsSessionRequest>
                 payment_attempt,
                 currency,
                 amount,
+                email: None::<Secret<String, pii::Email>>,
                 mandate_id: None,
                 token: None,
                 setup_mandate: None,
diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs
index cf847caae47..8f086e6695b 100644
--- a/crates/router/src/core/payments/operations/payment_start.rs
+++ b/crates/router/src/core/payments/operations/payment_start.rs
@@ -12,6 +12,7 @@ use crate::{
         payments::{helpers, operations, CustomerDetails, PaymentAddress, PaymentData},
     },
     db::StorageInterface,
+    pii,
     pii::Secret,
     routes::AppState,
     types::{
@@ -128,6 +129,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsStartRequest> f
                     payment_intent,
                     currency,
                     amount,
+                    email: None::<Secret<String, pii::Email>>,
                     mandate_id: None,
                     connector_response,
                     setup_mandate: None,
diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs
index 693a1f4ed8f..4cf76066045 100644
--- a/crates/router/src/core/payments/operations/payment_status.rs
+++ b/crates/router/src/core/payments/operations/payment_status.rs
@@ -275,6 +275,7 @@ async fn get_tracker_for_sync<
             connector_response,
             currency,
             amount,
+            email: None,
             mandate_id: None,
             setup_mandate: None,
             token: None,
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index a9d1560b81d..e9347e1aaeb 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -164,6 +164,7 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
                     payment_attempt,
                     currency,
                     amount,
+                    email: request.email.clone(),
                     mandate_id,
                     token,
                     setup_mandate,
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index 7e963424505..36df6cdbc32 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -433,6 +433,7 @@ impl<F: Clone> TryFrom<PaymentData<F>> for types::PaymentsAuthorizeData {
             amount: payment_data.amount.into(),
             currency: payment_data.currency,
             browser_info,
+            email: payment_data.email,
             order_details,
         })
     }
diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs
index 088e009038c..7ab6221cf39 100644
--- a/crates/router/src/types.rs
+++ b/crates/router/src/types.rs
@@ -13,6 +13,7 @@ pub mod transformers;
 use std::marker::PhantomData;
 
 pub use api_models::enums::Connector;
+use common_utils::pii::Email;
 use error_stack::{IntoReport, ResultExt};
 
 use self::{api::payments, storage::enums as storage_enums};
@@ -90,6 +91,7 @@ pub struct RouterData<Flow, Request, Response> {
 pub struct PaymentsAuthorizeData {
     pub payment_method_data: payments::PaymentMethod,
     pub amount: i64,
+    pub email: Option<masking::Secret<String, Email>>,
     pub currency: storage_enums::Currency,
     pub confirm: bool,
     pub statement_descriptor_suffix: Option<String>,
diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs
index ff73559ad9f..e34849fabe6 100644
--- a/crates/router/src/types/api.rs
+++ b/crates/router/src/types/api.rs
@@ -146,6 +146,7 @@ impl ConnectorData {
             "braintree" => Ok(Box::new(&connector::Braintree)),
             "klarna" => Ok(Box::new(&connector::Klarna)),
             "applepay" => Ok(Box::new(&connector::Applepay)),
+            "cybersource" => Ok(Box::new(&connector::Cybersource)),
             "shift4" => Ok(Box::new(&connector::Shift4)),
             _ => Err(report!(errors::UnexpectedError)
                 .attach_printable(format!("invalid connector name: {connector_name}")))
diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs
index 630107deabe..3d417b15d5b 100644
--- a/crates/router/tests/connectors/aci.rs
+++ b/crates/router/tests/connectors/aci.rs
@@ -48,6 +48,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
             capture_method: None,
             browser_info: None,
             order_details: None,
+            email: None,
         },
         response: Err(types::ErrorResponse::default()),
         payment_method_id: None,
diff --git a/crates/router/tests/connectors/authorizedotnet.rs b/crates/router/tests/connectors/authorizedotnet.rs
index 6b9fe6b67cc..45b8b18e3d9 100644
--- a/crates/router/tests/connectors/authorizedotnet.rs
+++ b/crates/router/tests/connectors/authorizedotnet.rs
@@ -48,6 +48,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
             capture_method: None,
             browser_info: None,
             order_details: None,
+            email: None,
         },
         payment_method_id: None,
         response: Err(types::ErrorResponse::default()),
diff --git a/crates/router/tests/connectors/checkout.rs b/crates/router/tests/connectors/checkout.rs
index cefd2e1d8a8..578a7fab93e 100644
--- a/crates/router/tests/connectors/checkout.rs
+++ b/crates/router/tests/connectors/checkout.rs
@@ -45,6 +45,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
             capture_method: None,
             browser_info: None,
             order_details: None,
+            email: None,
         },
         response: Err(types::ErrorResponse::default()),
         payment_method_id: None,
diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs
index 51fdfc87109..8997da2b5ad 100644
--- a/crates/router/tests/connectors/utils.rs
+++ b/crates/router/tests/connectors/utils.rs
@@ -134,6 +134,7 @@ impl Default for PaymentAuthorizeType {
             setup_mandate_details: None,
             browser_info: None,
             order_details: None,
+            email: None,
         };
         Self(data)
     }

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

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

## Description
Adding Authorize call for `Cybersource` connector
<!-- Describe your changes in detail -->


### Additional Changes

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

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

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


## Motivation and Context
Adding another connector `Cybersource`
<!--
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).
-->


## How did you test it?
Ran it and checked in cybersource sandbox.
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->


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

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