Bug: Add Shift4 for card payments




diff --git a/config/Development.toml b/config/Development.toml
index 32c328baa11..bc2b912fa37 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"]
+cards = ["stripe","adyen","authorizedotnet","checkout","braintree","aci","shift4"]
 
 [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.shift4]
+base_url = "https://api.shift4.com/"
+
 [scheduler]
 stream = "SCHEDULER_STREAM"
 consumer_group = "SCHEDULER_GROUP"
diff --git a/config/config.example.toml b/config/config.example.toml
index 1187de15f00..6e9f4d152c0 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -119,6 +119,9 @@ base_url = "https://api-na.playground.klarna.com/"
 [connectors.applepay]
 base_url = "https://apple-pay-gateway.apple.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"]
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index 32a45dde16a..58a22c7c5c6 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -74,6 +74,9 @@ base_url = "https://api-na.playground.klarna.com/"
 [connectors.applepay]
 base_url = "https://apple-pay-gateway.apple.com/"
 
+[connectors.shift4]
+base_url = "https://api.shift4.com/"
+
 [connectors.supported]
 wallets = ["klarna","braintree","applepay"]
-cards = ["stripe","adyen","authorizedotnet","checkout","braintree"]
+cards = ["stripe","adyen","authorizedotnet","checkout","braintree","shift4"]
diff --git a/connector-template/mod.rs b/connector-template/mod.rs
index c7f3a22094b..4cf6645993a 100644
--- a/connector-template/mod.rs
+++ b/connector-template/mod.rs
@@ -6,13 +6,16 @@ use bytes::Bytes;
 use error_stack::ResultExt;
 
 use crate::{
-    configs::settings::ConnectorParams,
+    configs::settings,
     utils::{self, BytesExt},
-    core::errors::{self, CustomResult},
-    logger, services,
+    core::{
+        errors::{self, CustomResult},
+        payments,
+    },
+    headers, logger, services,
     types::{
         self,
-        api,
+        api::{self, ConnectorCommon, ConnectorCommonExt},
         ErrorResponse, Response,
     }
 };
@@ -21,15 +24,14 @@ use crate::{
 use transformers as {{project-name | downcase}};
 
 #[derive(Debug, Clone)]
-pub struct {{project-name | downcase | pascal_case}} {
-    pub base_url: String,
-}
+pub struct {{project-name | downcase | pascal_case}};
 
-impl {{project-name | downcase | pascal_case}} {
-    pub fn make(params: &ConnectorParams) -> Self {
-        Self {
-            base_url: params.base_url.to_owned(),
-        }
+impl api::ConnectorCommonExt for {{project-name | downcase | pascal_case}} {
+    fn build_headers<Flow, Request, Response>(
+        &self,
+        req: &types::RouterData<Flow, Request, Response>,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        todo!()
     }
 }
 
@@ -43,8 +45,8 @@ impl api::ConnectorCommon for {{project-name | downcase | pascal_case}} {
         // Ex: "application/x-www-form-urlencoded"
     }
 
-    fn base_url(&self) -> &str {
-        &self.base_url
+    fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
+        connectors.{{project-name}}.base_url.as_ref()
     }
 
     fn get_auth_header(&self,_auth_type:&types::ConnectorAuthType)-> CustomResult<Vec<(String,String)>,errors::ConnectorError> {
@@ -54,19 +56,151 @@ impl api::ConnectorCommon for {{project-name | downcase | pascal_case}} {
 
 impl api::Payment for {{project-name | downcase | pascal_case}} {}
 
-impl api::PaymentAuthorize for {{project-name | downcase | pascal_case}} {}
+impl api::PreVerify for {{project-name | downcase | pascal_case}} {}
+impl
+    services::ConnectorIntegration<
+        api::Verify,
+        types::VerifyRequestData,
+        types::PaymentsResponseData,
+    > for {{project-name | downcase | pascal_case}}
+{
+}
+
+impl api::PaymentVoid for {{project-name | downcase | pascal_case}} {}
+
+impl
+    services::ConnectorIntegration<
+        api::Void,
+        types::PaymentsCancelData,
+        types::PaymentsResponseData,
+    > for {{project-name | downcase | pascal_case}}
+{}
+
+impl api::PaymentSync for {{project-name | downcase | pascal_case}} {}
+impl
+    services::ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
+    for {{project-name | downcase | pascal_case}}
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        todo!()
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        todo!()
+    }
 
-type Authorize = dyn services::ConnectorIntegration<
-    api::Authorize,
-    types::PaymentsRequestData,
-    types::PaymentsResponseData,
->;
+    fn get_url(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        todo!()
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        todo!()
+    }
 
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        todo!()
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsSyncRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
+        todo!()
+    }
+}
+
+
+impl api::PaymentCapture for {{project-name | downcase | pascal_case}} {}
+impl
+    services::ConnectorIntegration<
+        api::Capture,
+        types::PaymentsCaptureData,
+        types::PaymentsResponseData,
+    > for {{project-name | downcase | pascal_case}}
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        todo!()
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        todo!()
+    }
+
+    fn get_request_body(
+        &self,
+        _req: &types::PaymentsCaptureRouterData,
+    ) -> CustomResult<Option<String>, errors::ConnectorError> {
+        todo!()
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        todo!()
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsCaptureRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsCaptureRouterData, errors::ConnectorError> {
+        todo!()
+    }
+
+    fn get_url(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        todo!()
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        todo!()
+    }
+}
+
+impl api::PaymentSession for {{project-name | downcase | pascal_case}} {}
+
+impl
+    services::ConnectorIntegration<
+        api::Session,
+        types::PaymentsSessionData,
+        types::PaymentsResponseData,
+    > for {{project-name | downcase | pascal_case}}
+{
+    //TODO: implement sessions flow
+}
+
+impl api::PaymentAuthorize for {{project-name | downcase | pascal_case}} {}
 
 impl
     services::ConnectorIntegration<
         api::Authorize,
-        types::PaymentsRequestData,
+        types::PaymentsAuthorizeData,
         types::PaymentsResponseData,
     > for {{project-name | downcase | pascal_case}} {
     fn get_headers(&self, _req: &types::PaymentsAuthorizeRouterData) -> CustomResult<Vec<(String, String)>,errors::ConnectorError> {
@@ -77,7 +211,7 @@ impl
         todo!()
     }
 
-    fn get_url(&self, _req: &types::PaymentsAuthorizeRouterData) -> CustomResult<String,errors::ConnectorError> {
+    fn get_url(&self, _req: &types::PaymentsAuthorizeRouterData, connectors: &settings::Connectors,) -> CustomResult<String,errors::ConnectorError> {
         todo!()
     }
 
@@ -112,19 +246,13 @@ impl api::Refund for {{project-name | downcase | pascal_case}} {}
 impl api::RefundExecute for {{project-name | downcase | pascal_case}} {}
 impl api::RefundSync for {{project-name | downcase | pascal_case}} {}
 
-type Execute = dyn services::ConnectorIntegration<
-    api::Execute,
-    types::RefundsRequestData,
-    types::RefundsResponseData,
->;
-
 impl
     services::ConnectorIntegration<
         api::Execute,
-        types::RefundsRequestData,
+        types::RefundsData,
         types::RefundsResponseData,
     > for {{project-name | downcase | pascal_case}} {
-    fn get_headers(&self, _req: &types::RefundsRouterData) -> CustomResult<Vec<(String,String)>,errors::ConnectorError> {
+    fn get_headers(&self, _req: &types::RefundsRouterData<api::Execute>) -> CustomResult<Vec<(String,String)>,errors::ConnectorError> {
         todo!()
     }
 
@@ -132,32 +260,32 @@ impl
         todo!()
     }
 
-    fn get_url(&self, _req: &types::RefundsRouterData) -> CustomResult<String,errors::ConnectorError> {
+    fn get_url(&self, _req: &types::RefundsRouterData<api::Execute>, connectors: &settings::Connectors,) -> CustomResult<String,errors::ConnectorError> {
         todo!()
     }
 
-    fn get_request_body(&self, req: &types::RefundsRouterData) -> CustomResult<Option<String>,errors::ConnectorError> {
+    fn get_request_body(&self, req: &types::RefundsRouterData<api::Execute>) -> CustomResult<Option<String>,errors::ConnectorError> {
         let {{project-name | downcase}}_req = utils::Encode::<{{project-name| downcase}}::{{project-name | downcase | pascal_case}}RefundRequest>::convert_and_url_encode(req).change_context(errors::ConnectorError::RequestEncodingFailed)?;
         Ok(Some({{project-name | downcase}}_req))
     }
 
-    fn build_request(&self, req: &types::RefundsRouterData) -> CustomResult<Option<services::Request>,errors::ConnectorError> {
+    fn build_request(&self, req: &types::RefundsRouterData<api::Execute>, connectors: &settings::Connectors,) -> CustomResult<Option<services::Request>,errors::ConnectorError> {
         let request = services::RequestBuilder::new()
             .method(services::Method::Post)
-            .url(&Execute::get_url(self, req)?)
-            .headers(Execute::get_headers(self, req)?)
-            .body(Execute::get_request_body(self, req)?)
+            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
+            .headers(types::RefundExecuteType::get_headers(self, req)?)
+            .body(types::RefundExecuteType::get_request_body(self, req)?)
             .build();
         Ok(Some(request))
     }
 
     fn handle_response(
         &self,
-        data: &types::RefundsRouterData,
+        data: &types::RefundsRouterData<api::Execute>,
         res: Response,
-    ) -> CustomResult<types::RefundsRouterData,errors::ConnectorError> {
+    ) -> CustomResult<types::RefundsRouterData<api::Execute>,errors::ConnectorError> {
         logger::debug!(target: "router::connector::{{project-name | downcase}}", response=?res);
-        let response: {{project-name| downcase}}::{{project-name | downcase| pascal_case}}RefundResponse = res.response.parse_struct("{{project-name | downcase}} RefundResponse").change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        let response: {{project-name| downcase}}::RefundResponse = res.response.parse_struct("{{project-name | downcase}} RefundResponse").change_context(errors::ConnectorError::RequestEncodingFailed)?;
         types::ResponseRouterData {
             response,
             data: data.clone(),
@@ -172,14 +300,9 @@ impl
     }
 }
 
-type RSync = dyn services::ConnectorIntegration<
-    api::Sync,
-    types::RefundsRequestData,
-    types::RefundsResponseData,
->;
 impl
-    services::ConnectorIntegration<api::Sync, types::RefundsRequestData, types::RefundsResponseData> for {{project-name | downcase | pascal_case}} {
-    fn get_headers(&self, _req: &types::RefundsRouterData) -> CustomResult<Vec<(String, String)>,errors::ConnectorError> {
+    services::ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for {{project-name | downcase | pascal_case}} {
+    fn get_headers(&self, _req: &types::RefundSyncRouterData) -> CustomResult<Vec<(String, String)>,errors::ConnectorError> {
         todo!()
     }
 
@@ -187,17 +310,17 @@ impl
         todo!()
     }
 
-    fn get_url(&self, _req: &types::RefundsRouterData) -> CustomResult<String,errors::ConnectorError> {
+    fn get_url(&self, _req: &types::RefundSyncRouterData,_connectors: &settings::Connectors,) -> CustomResult<String,errors::ConnectorError> {
         todo!()
     }
 
     fn handle_response(
         &self,
-        data: &types::RefundsRouterData,
+        data: &types::RefundSyncRouterData,
         res: Response,
-    ) -> CustomResult<types::RefundsRouterData,errors::ConnectorError> {
+    ) -> CustomResult<types::RefundSyncRouterData,errors::ConnectorError,> {
         logger::debug!(target: "router::connector::{{project-name | downcase}}", response=?res);
-        let response: {{project-name | downcase}}::{{project-name | downcase | pascal_case}}RefundResponse = res.response.parse_struct("{{project-name | downcase}} RefundResponse").change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        let response: {{project-name | downcase}}::RefundResponse = res.response.parse_struct("{{project-name | downcase}} RefundResponse").change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
         types::ResponseRouterData {
             response,
             data: data.clone(),
@@ -224,7 +347,7 @@ impl api::IncomingWebhook for {{project-name | downcase | pascal_case}} {
     fn get_webhook_event_type(
         &self,
         _body: &[u8],
-    ) -> CustomResult<String, errors::ConnectorError> {
+    ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
         todo!()
     }
 
@@ -235,3 +358,12 @@ impl api::IncomingWebhook for {{project-name | downcase | pascal_case}} {
         todo!()
     }
 }
+
+impl services::ConnectorRedirectResponse for {{project-name | downcase | pascal_case}} {
+    fn get_flow_type(
+        &self,
+        _query_params: &str,
+    ) -> CustomResult<payments::CallConnectorAction, errors::ConnectorError> {
+        Ok(payments::CallConnectorAction::Trigger)
+    }
+}
diff --git a/connector-template/test.rs b/connector-template/test.rs
new file mode 100644
index 00000000000..1ba4de5e6f5
--- /dev/null
+++ b/connector-template/test.rs
@@ -0,0 +1,92 @@
+use futures::future::OptionFuture;
+use masking::Secret;
+use router::types::{self, api, storage::enums};
+
+use crate::{
+    connector_auth,
+    utils::{self, ConnectorActions},
+};
+
+struct {{project-name | downcase | pascal_case}};
+impl utils::ConnectorActions for {{project-name | downcase | pascal_case}} {}
+impl utils::Connector for {{project-name | downcase | pascal_case}} {
+    fn get_data(&self) -> types::api::ConnectorData {
+        use router::connector::{{project-name | downcase | pascal_case}};
+        types::api::ConnectorData {
+            connector: Box::new(&{{project-name | downcase | pascal_case}}),
+            connector_name: types::Connector::{{project-name | downcase | pascal_case}},
+            get_token: types::api::GetToken::Connector,
+        }
+    }
+
+    fn get_auth_token(&self) -> types::ConnectorAuthType {
+        types::ConnectorAuthType::from(
+            connector_auth::ConnectorAuthentication::new()
+                .{{project-name | downcase }}
+                .expect("Missing connector authentication configuration"),
+        )
+    }
+
+    fn get_name(&self) -> String {
+        "{{project-name | downcase }}".to_string()
+    }
+}
+
+#[actix_web::test]
+async fn should_only_authorize_payment() {
+    let response = {{project-name | downcase | pascal_case}} {}.authorize_payment(None).await;
+    assert_eq!(response.status, enums::AttemptStatus::Authorized);
+}
+
+#[actix_web::test]
+async fn should_authorize_and_capture_payment() {
+    let response = {{project-name | downcase | pascal_case}} {}.make_payment(None).await;
+    assert_eq!(response.status, enums::AttemptStatus::Charged);
+}
+
+#[actix_web::test]
+async fn should_capture_already_authorized_payment() {
+    let connector = {{project-name | downcase | pascal_case}} {};
+    let authorize_response = connector.authorize_payment(None).await;
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Authorized);
+    let txn_id = utils::get_connector_transaction_id(authorize_response);
+    let response: OptionFuture<_> = txn_id
+        .map(|transaction_id| async move {
+            connector.capture_payment(transaction_id, None).await.status
+        })
+        .into();
+    assert_eq!(response.await, Some(enums::AttemptStatus::Charged));
+}
+
+#[actix_web::test]
+async fn should_fail_payment_for_incorrect_cvc() {
+    let response = {{project-name | downcase | pascal_case}} {}.make_payment(Some(types::PaymentsAuthorizeData {
+            payment_method_data: types::api::PaymentMethod::Card(api::CCard {
+                card_number: Secret::new("4024007134364842".to_string()),
+                ..utils::CCardType::default().0
+            }),
+            ..utils::PaymentAuthorizeType::default().0
+        }))
+        .await;
+    let x = response.response.unwrap_err();
+    assert_eq!(
+        x.message,
+        "The card's security code failed verification.".to_string(),
+    );
+}
+
+#[actix_web::test]
+async fn should_refund_succeeded_payment() {
+    let connector = {{project-name | downcase | pascal_case}} {};
+    //make a successful payment
+    let response = connector.make_payment(None).await;
+
+    //try refund for previous payment
+    if let Some(transaction_id) = utils::get_connector_transaction_id(response) {
+        let response = connector.refund_payment(transaction_id, None).await;
+        assert_eq!(
+            response.response.unwrap().refund_status,
+            enums::RefundStatus::Success,
+        );
+    }
+}
diff --git a/connector-template/transformers.rs b/connector-template/transformers.rs
index 34ac1e95892..2d81e2d57c1 100644
--- a/connector-template/transformers.rs
+++ b/connector-template/transformers.rs
@@ -1,8 +1,8 @@
 use serde::{Deserialize, Serialize};
-use crate::{core::errors,types::{self,storage::enums}};
+use crate::{core::errors,pii::PeekInterface,types::{self,api, storage::enums}};
 
 //TODO: Fill the struct with respective fields
-#[derive(Default, Debug, Serialize, PartialEq)]
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
 pub struct {{project-name | downcase | pascal_case}}PaymentsRequest {}
 
 impl TryFrom<&types::PaymentsAuthorizeRouterData> for {{project-name | downcase | pascal_case}}PaymentsRequest  {
@@ -24,21 +24,15 @@ impl TryFrom<&types::ConnectorAuthType> for {{project-name | downcase | pascal_c
 }
 // PaymentsResponse
 //TODO: Append the remaining status flags
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "lowercase")]
 pub enum {{project-name | downcase | pascal_case}}PaymentStatus {
     Succeeded,
     Failed,
+    #[default]
     Processing,
 }
 
-// Default should be Processing
-impl Default for {{project-name | downcase | pascal_case}}PaymentStatus {
-    fn default() -> Self {
-        {{project-name | downcase | pascal_case}}PaymentStatus::Processing
-    }
-}
-
 impl From<{{project-name | downcase | pascal_case}}PaymentStatus> for enums::AttemptStatus {
     fn from(item: {{project-name | downcase | pascal_case}}PaymentStatus) -> Self {
         match item {
@@ -66,9 +60,9 @@ impl TryFrom<types::PaymentsResponseRouterData<{{project-name | downcase | pasca
 #[derive(Default, Debug, Serialize)]
 pub struct {{project-name | downcase | pascal_case}}RefundRequest {}
 
-impl TryFrom<&types::RefundsRouterData> for {{project-name | downcase | pascal_case}}RefundRequest {
+impl<F> TryFrom<&types::RefundsRouterData<F>> for {{project-name | downcase | pascal_case}}RefundRequest {
     type Error = error_stack::Report<errors::ParsingError>;
-    fn try_from(_item: &types::RefundsRouterData) -> Result<Self,Self::Error> {
+    fn try_from(_item: &types::RefundsRouterData<F>) -> Result<Self,Self::Error> {
        todo!()
     }
 }
@@ -76,22 +70,16 @@ impl TryFrom<&types::RefundsRouterData> for {{project-name | downcase | pascal_c
 // Type definition for Refund Response
 
 #[allow(dead_code)]
-#[derive(Debug, Serialize, Deserialize, Clone)]
+#[derive(Debug, Serialize, Default, Deserialize, Clone)]
 pub enum RefundStatus {
     Succeeded,
     Failed,
+    #[default]
     Processing,
 }
 
-// Default should be Processing
-impl Default for RefundStatus {
-    fn default() -> Self {
-        RefundStatus::Processing
-    }
-}
-
-impl From<RefundStatus> for enums::RefundStatus {
-    fn from(item: RefundStatus) -> Self {
+impl From<self::RefundStatus> for enums::RefundStatus {
+    fn from(item: self::RefundStatus) -> Self {
         match item {
             RefundStatus::Succeeded => Self::Success,
             RefundStatus::Failed => Self::Failure,
@@ -103,15 +91,28 @@ impl From<RefundStatus> for enums::RefundStatus {
 
 //TODO: Fill the struct with respective fields
 #[derive(Default, Debug, Clone, Serialize, Deserialize)]
-pub struct {{project-name | downcase | pascal_case}}RefundResponse {}
+pub struct RefundResponse {
+}
 
-impl TryFrom<types::RefundsResponseRouterData<{{project-name | downcase | pascal_case}}RefundResponse>> for types::RefundsRouterData {
+impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
+    for types::RefundsRouterData<api::Execute>
+{
     type Error = error_stack::Report<errors::ParsingError>;
-    fn try_from(_item: types::RefundsResponseRouterData<{{project-name | downcase | pascal_case}}RefundResponse>) -> Result<Self,Self::Error> {
+    fn try_from(
+        item: types::RefundsResponseRouterData<api::Execute, RefundResponse>,
+    ) -> Result<Self, Self::Error> {
         todo!()
     }
 }
 
+impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundResponse>> for types::RefundsRouterData<api::RSync>
+{
+     type Error = error_stack::Report<errors::ParsingError>;
+    fn try_from(_item: types::RefundsResponseRouterData<api::RSync, RefundResponse>) -> Result<Self,Self::Error> {
+         todo!()
+     }
+ }
+
 //TODO: Fill the struct with respective fields
 #[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
 pub struct {{project-name | downcase | pascal_case}}ErrorResponse {}
diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs
index 8e1c71c2279..4b11ecb08ed 100644
--- a/crates/api_models/src/enums.rs
+++ b/crates/api_models/src/enums.rs
@@ -494,6 +494,7 @@ pub enum Connector {
     #[default]
     Dummy,
     Klarna,
+    Shift4,
     Stripe,
 }
 
diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs
index fa7fdefe7a9..e0cc902531b 100644
--- a/crates/router/src/configs/settings.rs
+++ b/crates/router/src/configs/settings.rs
@@ -110,10 +110,11 @@ pub struct Connectors {
     pub aci: ConnectorParams,
     pub adyen: ConnectorParams,
     pub authorizedotnet: ConnectorParams,
-    pub checkout: ConnectorParams,
-    pub stripe: ConnectorParams,
     pub braintree: ConnectorParams,
+    pub checkout: ConnectorParams,
     pub klarna: ConnectorParams,
+    pub shift4: ConnectorParams,
+    pub stripe: ConnectorParams,
     pub supported: SupportedConnectors,
     pub applepay: ConnectorParams,
 }
diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs
index 9db784acd2f..9476a026693 100644
--- a/crates/router/src/connector.rs
+++ b/crates/router/src/connector.rs
@@ -7,7 +7,9 @@ pub mod checkout;
 pub mod klarna;
 pub mod stripe;
 
+pub mod shift4;
+
 pub use self::{
     aci::Aci, adyen::Adyen, applepay::Applepay, authorizedotnet::Authorizedotnet,
-    braintree::Braintree, checkout::Checkout, klarna::Klarna, stripe::Stripe,
+    braintree::Braintree, checkout::Checkout, klarna::Klarna, shift4::Shift4, stripe::Stripe,
 };
diff --git a/crates/router/src/connector/shift4.rs b/crates/router/src/connector/shift4.rs
new file mode 100644
index 00000000000..4ba448dec70
--- /dev/null
+++ b/crates/router/src/connector/shift4.rs
@@ -0,0 +1,527 @@
+mod transformers;
+
+use std::fmt::Debug;
+
+use bytes::Bytes;
+use common_utils::ext_traits::ByteSliceExt;
+use error_stack::ResultExt;
+use transformers as shift4;
+
+use crate::{
+    configs::settings,
+    consts,
+    core::{
+        errors::{self, CustomResult},
+        payments,
+    },
+    headers, logger,
+    services::{self, ConnectorIntegration},
+    types::{
+        self,
+        api::{self, ConnectorCommon, ConnectorCommonExt},
+        ErrorResponse, Response,
+    },
+    utils::{self, BytesExt},
+};
+
+#[derive(Debug, Clone)]
+pub struct Shift4;
+
+impl<Flow, Request, Response> api::ConnectorCommonExt<Flow, Request, Response> for Shift4
+where
+    Self: ConnectorIntegration<Flow, Request, Response>,
+{
+    fn build_headers(
+        &self,
+        req: &types::RouterData<Flow, Request, Response>,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        let mut headers = vec![
+            (
+                headers::CONTENT_TYPE.to_string(),
+                self.get_content_type().to_string(),
+            ),
+            (
+                headers::ACCEPT.to_string(),
+                self.get_content_type().to_string(),
+            ),
+        ];
+        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
+        headers.append(&mut api_key);
+        Ok(headers)
+    }
+}
+impl api::ConnectorCommon for Shift4 {
+    fn id(&self) -> &'static str {
+        "shift4"
+    }
+
+    fn common_get_content_type(&self) -> &'static str {
+        "application/json"
+    }
+
+    fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
+        connectors.shift4.base_url.as_ref()
+    }
+
+    fn get_auth_header(
+        &self,
+        auth_type: &types::ConnectorAuthType,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        let auth: shift4::Shift4AuthType = auth_type
+            .try_into()
+            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
+        Ok(vec![(headers::AUTHORIZATION.to_string(), auth.api_key)])
+    }
+
+    fn build_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        let response: shift4::ErrorResponse = res
+            .parse_struct("Shift4 ErrorResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+
+        Ok(ErrorResponse {
+            code: response
+                .error
+                .code
+                .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()),
+            message: response.error.message,
+            reason: None,
+        })
+    }
+}
+
+impl api::Payment for Shift4 {}
+
+impl api::PreVerify for Shift4 {}
+impl
+    services::ConnectorIntegration<
+        api::Verify,
+        types::VerifyRequestData,
+        types::PaymentsResponseData,
+    > for Shift4
+{
+}
+
+impl api::PaymentVoid for Shift4 {}
+
+impl
+    services::ConnectorIntegration<
+        api::Void,
+        types::PaymentsCancelData,
+        types::PaymentsResponseData,
+    > for Shift4
+{
+}
+
+impl api::PaymentSync for Shift4 {}
+impl
+    services::ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
+    for Shift4
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        let connector_payment_id = req
+            .request
+            .connector_transaction_id
+            .get_connector_transaction_id()
+            .change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
+        Ok(format!(
+            "{}charges/{}",
+            self.base_url(connectors),
+            connector_payment_id
+        ))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Get)
+                .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
+                .headers(types::PaymentsSyncType::get_headers(self, req)?)
+                .build(),
+        ))
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsSyncRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
+        logger::debug!(payment_sync_response=?res);
+        let response: shift4::Shift4PaymentsResponse = res
+            .response
+            .parse_struct("shift4 PaymentsResponse")
+            .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)
+    }
+}
+
+impl api::PaymentCapture for Shift4 {}
+
+impl
+    services::ConnectorIntegration<
+        api::Capture,
+        types::PaymentsCaptureData,
+        types::PaymentsResponseData,
+    > for Shift4
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Post)
+                .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
+                .headers(types::PaymentsCaptureType::get_headers(self, req)?)
+                .build(),
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsCaptureRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsCaptureRouterData, errors::ConnectorError> {
+        let response: shift4::Shift4PaymentsResponse = res
+            .response
+            .parse_struct("Shift4PaymentsResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        logger::debug!(shift4payments_create_response=?response);
+        types::ResponseRouterData {
+            response,
+            data: data.clone(),
+            http_code: res.status_code,
+        }
+        .try_into()
+        .change_context(errors::ConnectorError::ResponseHandlingFailed)
+    }
+
+    fn get_url(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        let connector_payment_id = req.request.connector_transaction_id.clone();
+        Ok(format!(
+            "{}charges/{}/capture",
+            self.base_url(connectors),
+            connector_payment_id
+        ))
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+impl api::PaymentSession for Shift4 {}
+
+impl
+    services::ConnectorIntegration<
+        api::Session,
+        types::PaymentsSessionData,
+        types::PaymentsResponseData,
+    > for Shift4
+{
+    //TODO: implement sessions flow
+}
+
+impl api::PaymentAuthorize for Shift4 {}
+
+impl
+    services::ConnectorIntegration<
+        api::Authorize,
+        types::PaymentsAuthorizeData,
+        types::PaymentsResponseData,
+    > for Shift4
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsAuthorizeRouterData,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        _req: &types::PaymentsAuthorizeRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!("{}charges", self.base_url(connectors)))
+    }
+
+    fn get_request_body(
+        &self,
+        req: &types::PaymentsAuthorizeRouterData,
+    ) -> CustomResult<Option<String>, errors::ConnectorError> {
+        let shift4_req = utils::Encode::<shift4::Shift4PaymentsRequest>::convert_and_encode(req)
+            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        Ok(Some(shift4_req))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsAuthorizeRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Post)
+                .url(&types::PaymentsAuthorizeType::get_url(
+                    self, req, connectors,
+                )?)
+                .headers(types::PaymentsAuthorizeType::get_headers(self, req)?)
+                .body(types::PaymentsAuthorizeType::get_request_body(self, req)?)
+                .build(),
+        ))
+    }
+    fn handle_response(
+        &self,
+        data: &types::PaymentsAuthorizeRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
+        let response: shift4::Shift4PaymentsResponse = res
+            .response
+            .parse_struct("Shift4PaymentsResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        logger::debug!(shift4payments_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<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+impl api::Refund for Shift4 {}
+impl api::RefundExecute for Shift4 {}
+impl api::RefundSync for Shift4 {}
+
+impl services::ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
+    for Shift4
+{
+    fn get_headers(
+        &self,
+        req: &types::RefundsRouterData<api::Execute>,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        _req: &types::RefundsRouterData<api::Execute>,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!("{}refunds", self.base_url(connectors),))
+    }
+
+    fn get_request_body(
+        &self,
+        req: &types::RefundsRouterData<api::Execute>,
+    ) -> CustomResult<Option<String>, errors::ConnectorError> {
+        let shift4_req = utils::Encode::<shift4::Shift4RefundRequest>::convert_and_encode(req)
+            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        Ok(Some(shift4_req))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::RefundsRouterData<api::Execute>,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        let request = services::RequestBuilder::new()
+            .method(services::Method::Post)
+            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
+            .headers(types::RefundExecuteType::get_headers(self, req)?)
+            .body(types::RefundExecuteType::get_request_body(self, req)?)
+            .build();
+        Ok(Some(request))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::RefundsRouterData<api::Execute>,
+        res: Response,
+    ) -> CustomResult<types::RefundsRouterData<api::Execute>, errors::ConnectorError> {
+        logger::debug!(target: "router::connector::shift4", response=?res);
+        let response: shift4::RefundResponse = res
+            .response
+            .parse_struct("RefundResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        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<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+impl services::ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData>
+    for Shift4
+{
+    fn get_headers(
+        &self,
+        req: &types::RefundSyncRouterData,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        _req: &types::RefundSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!("{}refunds", self.base_url(connectors),))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::RefundSyncRouterData,
+        res: Response,
+    ) -> CustomResult<types::RefundSyncRouterData, errors::ConnectorError> {
+        logger::debug!(target: "router::connector::shift4", response=?res);
+        let response: shift4::RefundResponse =
+            res.response
+                .parse_struct("shift4 RefundResponse")
+                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        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<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+#[async_trait::async_trait]
+impl api::IncomingWebhook for Shift4 {
+    fn get_webhook_object_reference_id(
+        &self,
+        body: &[u8],
+    ) -> CustomResult<String, errors::ConnectorError> {
+        let details: shift4::Shift4WebhookObjectId = body
+            .parse_struct("Shift4WebhookObjectId")
+            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
+
+        Ok(details.data.id)
+    }
+
+    fn get_webhook_event_type(
+        &self,
+        body: &[u8],
+    ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
+        let details: shift4::Shift4WebhookObjectEventType = body
+            .parse_struct("Shift4WebhookObjectEventType")
+            .change_context(errors::ConnectorError::WebhookEventTypeNotFound)?;
+        Ok(match details.event_type {
+            shift4::Shift4WebhookEvent::ChargeSucceeded => {
+                api::IncomingWebhookEvent::PaymentIntentSuccess
+            }
+        })
+    }
+
+    fn get_webhook_resource_object(
+        &self,
+        body: &[u8],
+    ) -> CustomResult<serde_json::Value, errors::ConnectorError> {
+        let details: shift4::Shift4WebhookObjectResource = body
+            .parse_struct("Shift4WebhookObjectResource")
+            .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?;
+        Ok(details.data)
+    }
+}
+
+impl services::ConnectorRedirectResponse for Shift4 {
+    fn get_flow_type(
+        &self,
+        _query_params: &str,
+    ) -> CustomResult<payments::CallConnectorAction, errors::ConnectorError> {
+        Ok(payments::CallConnectorAction::Trigger)
+    }
+}
diff --git a/crates/router/src/connector/shift4/transformers.rs b/crates/router/src/connector/shift4/transformers.rs
new file mode 100644
index 00000000000..dbcd99afaf6
--- /dev/null
+++ b/crates/router/src/connector/shift4/transformers.rs
@@ -0,0 +1,257 @@
+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 Shift4PaymentsRequest {
+    amount: String,
+    card: Card,
+    currency: String,
+    description: Option<String>,
+    captured: bool,
+}
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+pub struct DeviceData;
+
+#[derive(Default, Debug, Serialize, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct Card {
+    number: String,
+    exp_month: String,
+    exp_year: String,
+    cardholder_name: String,
+}
+
+impl TryFrom<&types::PaymentsAuthorizeRouterData> for Shift4PaymentsRequest {
+    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 submit_for_settlement = matches!(
+                    item.request.capture_method,
+                    Some(enums::CaptureMethod::Automatic) | None
+                );
+                let payment_request = Self {
+                    amount: item.request.amount.to_string(),
+                    card: Card {
+                        number: ccard.card_number.peek().clone(),
+                        exp_month: ccard.card_exp_month.peek().clone(),
+                        exp_year: ccard.card_exp_year.peek().clone(),
+                        cardholder_name: ccard.card_holder_name.peek().clone(),
+                    },
+                    currency: item.request.currency.to_string(),
+                    description: item.description.clone(),
+                    captured: submit_for_settlement,
+                };
+                Ok(payment_request)
+            }
+            _ => Err(
+                errors::ConnectorError::NotImplemented("Current Payment Method".to_string()).into(),
+            ),
+        }
+    }
+}
+
+// Auth Struct
+pub struct Shift4AuthType {
+    pub(super) api_key: String,
+}
+
+impl TryFrom<&types::ConnectorAuthType> for Shift4AuthType {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(item: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
+        if let types::ConnectorAuthType::HeaderKey { api_key } = item {
+            Ok(Self {
+                api_key: api_key.to_string(),
+            })
+        } else {
+            Err(errors::ConnectorError::FailedToObtainAuthType)?
+        }
+    }
+}
+// PaymentsResponse
+#[derive(Debug, Clone, Default, Serialize, Deserialize, Eq, PartialEq)]
+#[serde(rename_all = "lowercase")]
+pub enum Shift4PaymentStatus {
+    Successful,
+    Failed,
+    #[default]
+    Pending,
+}
+
+impl From<Shift4PaymentStatus> for enums::AttemptStatus {
+    fn from(item: Shift4PaymentStatus) -> Self {
+        match item {
+            Shift4PaymentStatus::Successful => Self::Charged,
+            Shift4PaymentStatus::Failed => Self::Failure,
+            Shift4PaymentStatus::Pending => Self::Pending,
+        }
+    }
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Shift4WebhookObjectEventType {
+    #[serde(rename = "type")]
+    pub event_type: Shift4WebhookEvent,
+}
+
+#[derive(Debug, Deserialize)]
+pub enum Shift4WebhookEvent {
+    ChargeSucceeded,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Shift4WebhookObjectData {
+    pub id: String,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Shift4WebhookObjectId {
+    pub data: Shift4WebhookObjectData,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct Shift4WebhookObjectResource {
+    pub data: serde_json::Value,
+}
+
+fn get_payment_status(response: &Shift4PaymentsResponse) -> enums::AttemptStatus {
+    let is_authorized =
+        !response.captured && matches!(response.status, Shift4PaymentStatus::Successful);
+    if is_authorized {
+        enums::AttemptStatus::Authorized
+    } else {
+        enums::AttemptStatus::from(response.status.clone())
+    }
+}
+
+#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+pub struct Shift4PaymentsResponse {
+    id: String,
+    currency: String,
+    amount: u32,
+    status: Shift4PaymentStatus,
+    captured: bool,
+    refunded: bool,
+}
+
+impl<F, T>
+    TryFrom<types::ResponseRouterData<F, Shift4PaymentsResponse, T, types::PaymentsResponseData>>
+    for types::RouterData<F, T, types::PaymentsResponseData>
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: types::ResponseRouterData<F, Shift4PaymentsResponse, T, types::PaymentsResponseData>,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            status: get_payment_status(&item.response),
+            response: Ok(types::PaymentsResponseData::TransactionResponse {
+                resource_id: types::ResponseId::ConnectorTransactionId(item.response.id),
+                redirection_data: None,
+                redirect: false,
+                mandate_reference: None,
+            }),
+            ..item.data
+        })
+    }
+}
+
+// REFUND :
+// Type definition for RefundRequest
+#[derive(Default, Debug, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Shift4RefundRequest {
+    charge_id: String,
+    amount: i64,
+}
+
+impl<F> TryFrom<&types::RefundsRouterData<F>> for Shift4RefundRequest {
+    type Error = error_stack::Report<errors::ParsingError>;
+    fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
+        Ok(Self {
+            charge_id: item.request.connector_transaction_id.clone(),
+            amount: item.request.amount,
+        })
+    }
+}
+
+impl From<self::Shift4RefundStatus> for enums::RefundStatus {
+    fn from(item: self::Shift4RefundStatus) -> Self {
+        match item {
+            self::Shift4RefundStatus::Successful => Self::Success,
+            self::Shift4RefundStatus::Failed => Self::Failure,
+            self::Shift4RefundStatus::Processing => Self::Pending,
+        }
+    }
+}
+
+#[derive(Default, Debug, Clone, Serialize, Deserialize)]
+pub struct RefundResponse {
+    pub id: String,
+    pub amount: i64,
+    pub currency: String,
+    pub charge: String,
+    pub status: Shift4RefundStatus,
+}
+
+#[derive(Debug, Clone, Default, Serialize, Deserialize, Eq, PartialEq)]
+#[serde(rename_all = "lowercase")]
+pub enum Shift4RefundStatus {
+    Successful,
+    Processing,
+    #[default]
+    Failed,
+}
+
+impl TryFrom<types::RefundsResponseRouterData<api::Execute, RefundResponse>>
+    for types::RefundsRouterData<api::Execute>
+{
+    type Error = error_stack::Report<errors::ParsingError>;
+    fn try_from(
+        item: types::RefundsResponseRouterData<api::Execute, RefundResponse>,
+    ) -> Result<Self, Self::Error> {
+        let refund_status = enums::RefundStatus::from(item.response.status);
+        Ok(Self {
+            response: Ok(types::RefundsResponseData {
+                connector_refund_id: item.response.id,
+                refund_status,
+            }),
+            ..item.data
+        })
+    }
+}
+
+impl TryFrom<types::RefundsResponseRouterData<api::RSync, RefundResponse>>
+    for types::RefundsRouterData<api::RSync>
+{
+    type Error = error_stack::Report<errors::ParsingError>;
+    fn try_from(
+        item: types::RefundsResponseRouterData<api::RSync, RefundResponse>,
+    ) -> Result<Self, Self::Error> {
+        let refund_status = enums::RefundStatus::from(item.response.status);
+        Ok(Self {
+            response: Ok(types::RefundsResponseData {
+                connector_refund_id: item.response.id,
+                refund_status,
+            }),
+            ..item.data
+        })
+    }
+}
+
+#[derive(Debug, Default, Deserialize)]
+pub struct ErrorResponse {
+    pub error: ApiErrorResponse,
+}
+
+#[derive(Default, Debug, Clone, Deserialize, Eq, PartialEq)]
+pub struct ApiErrorResponse {
+    pub code: Option<String>,
+    pub message: String,
+}
diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs
index e044d16421a..9e7fcf55fd2 100644
--- a/crates/router/src/core/refunds.rs
+++ b/crates/router/src/core/refunds.rs
@@ -417,10 +417,10 @@ pub async fn validate_and_create_refund(
             validator::validate_maximum_refund_against_payment_attempt(&all_refunds)
                 .change_context(errors::ApiErrorResponse::MaximumRefundCount)?;
 
-            let connector = payment_attempt
-                .connector
-                .clone()
-                .ok_or(errors::ApiErrorResponse::InternalServerError)?;
+            let connector = payment_attempt.connector.clone().ok_or_else(|| {
+                report!(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("connector not populated in payment attempt.")
+            })?;
 
             refund_create_req = mk_new_refund(
                 req,
diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs
index c69105df6b4..96a5c559082 100644
--- a/crates/router/src/services/api.rs
+++ b/crates/router/src/services/api.rs
@@ -35,11 +35,11 @@ use crate::{
 pub type BoxedConnectorIntegration<'a, T, Req, Resp> =
     Box<&'a (dyn ConnectorIntegration<T, Req, Resp> + Send + Sync)>;
 
-pub trait ConnectorIntegrationExt<T, Req, Resp>: Send + Sync + 'static {
+pub trait ConnectorIntegrationAny<T, Req, Resp>: Send + Sync + 'static {
     fn get_connector_integration(&self) -> BoxedConnectorIntegration<T, Req, Resp>;
 }
 
-impl<S, T, Req, Resp> ConnectorIntegrationExt<T, Req, Resp> for S
+impl<S, T, Req, Resp> ConnectorIntegrationAny<T, Req, Resp> for S
 where
     S: ConnectorIntegration<T, Req, Resp> + Send + Sync,
 {
@@ -48,7 +48,7 @@ where
     }
 }
 
-pub trait ConnectorIntegration<T, Req, Resp>: ConnectorIntegrationExt<T, Req, Resp> {
+pub trait ConnectorIntegration<T, Req, Resp>: ConnectorIntegrationAny<T, Req, Resp> {
     fn get_headers(
         &self,
         _req: &types::RouterData<T, Req, Resp>,
diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs
index 5aed689c9e3..088e009038c 100644
--- a/crates/router/src/types.rs
+++ b/crates/router/src/types.rs
@@ -7,7 +7,6 @@
 // Separation of concerns instead of separation of forms.
 
 pub mod api;
-pub mod connector;
 pub mod storage;
 pub mod transformers;
 
@@ -29,6 +28,8 @@ pub type PaymentsCancelRouterData = RouterData<api::Void, PaymentsCancelData, Pa
 pub type PaymentsSessionRouterData =
     RouterData<api::Session, PaymentsSessionData, PaymentsResponseData>;
 pub type RefundsRouterData<F> = RouterData<F, RefundsData, RefundsResponseData>;
+pub type RefundExecuteRouterData = RouterData<api::Execute, RefundsData, RefundsResponseData>;
+pub type RefundSyncRouterData = RouterData<api::RSync, RefundsData, RefundsResponseData>;
 
 pub type PaymentsResponseRouterData<R> =
     ResponseRouterData<api::Authorize, R, PaymentsAuthorizeData, PaymentsResponseData>;
diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs
index fb96a9d8a86..d390388b35a 100644
--- a/crates/router/src/types/api.rs
+++ b/crates/router/src/types/api.rs
@@ -9,14 +9,16 @@ pub mod webhooks;
 
 use std::{fmt::Debug, marker, str::FromStr};
 
+use bytes::Bytes;
 use error_stack::{report, IntoReport, ResultExt};
 
 pub use self::{admin::*, customers::*, payment_methods::*, payments::*, refunds::*, webhooks::*};
+use super::ErrorResponse;
 use crate::{
     configs::settings::Connectors,
-    connector,
+    connector, consts,
     core::errors::{self, CustomResult},
-    services::ConnectorRedirectResponse,
+    services::{ConnectorIntegration, ConnectorRedirectResponse},
     types::{self, api::enums as api_enums},
 };
 
@@ -43,6 +45,31 @@ pub trait ConnectorCommon {
 
     /// The base URL for interacting with the connector's API.
     fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str;
+
+    /// common error response for a connector if it is same in all case
+    fn build_error_response(
+        &self,
+        _res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        Ok(ErrorResponse {
+            code: consts::NO_ERROR_CODE.to_string(),
+            message: consts::NO_ERROR_MESSAGE.to_string(),
+            reason: None,
+        })
+    }
+}
+
+/// Extended trait for connector common to allow functions with generic type
+pub trait ConnectorCommonExt<Flow, Req, Resp>:
+    ConnectorCommon + ConnectorIntegration<Flow, Req, Resp>
+{
+    /// common header builder when every request for the connector have same headers
+    fn build_headers(
+        &self,
+        _req: &types::RouterData<Flow, Req, Resp>,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        Ok(Vec::new())
+    }
 }
 
 pub trait Router {}
@@ -119,6 +146,7 @@ impl ConnectorData {
             "braintree" => Ok(Box::new(&connector::Braintree)),
             "klarna" => Ok(Box::new(&connector::Klarna)),
             "applepay" => Ok(Box::new(&connector::Applepay)),
+            "shift4" => Ok(Box::new(&connector::Shift4)),
             _ => Err(report!(errors::UnexpectedError)
                 .attach_printable(format!("invalid connector name: {connector_name}")))
             .change_context(errors::ConnectorError::InvalidConnectorName)
diff --git a/crates/router/src/types/connector.rs b/crates/router/src/types/connector.rs
deleted file mode 100644
index 8b137891791..00000000000
--- a/crates/router/src/types/connector.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/crates/router/tests/connectors/connector_auth.rs b/crates/router/tests/connectors/connector_auth.rs
index 33ac398f923..e06897d9ab1 100644
--- a/crates/router/tests/connectors/connector_auth.rs
+++ b/crates/router/tests/connectors/connector_auth.rs
@@ -6,6 +6,7 @@ pub(crate) struct ConnectorAuthentication {
     pub aci: Option<BodyKey>,
     pub authorizedotnet: Option<BodyKey>,
     pub checkout: Option<BodyKey>,
+    pub shift4: Option<HeaderKey>,
 }
 
 impl ConnectorAuthentication {
@@ -18,6 +19,19 @@ impl ConnectorAuthentication {
     }
 }
 
+#[derive(Debug, Deserialize, Clone)]
+pub(crate) struct HeaderKey {
+    pub api_key: String,
+}
+
+impl From<HeaderKey> for ConnectorAuthType {
+    fn from(key: HeaderKey) -> Self {
+        ConnectorAuthType::HeaderKey {
+            api_key: key.api_key,
+        }
+    }
+}
+
 #[derive(Debug, Deserialize, Clone)]
 pub(crate) struct BodyKey {
     pub api_key: String,
diff --git a/crates/router/tests/connectors/main.rs b/crates/router/tests/connectors/main.rs
index 7f852689d04..93c55c6e580 100644
--- a/crates/router/tests/connectors/main.rs
+++ b/crates/router/tests/connectors/main.rs
@@ -2,3 +2,5 @@ mod aci;
 mod authorizedotnet;
 mod checkout;
 mod connector_auth;
+mod shift4;
+mod utils;
diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml
index 21b599d9d6b..23b7a383ab5 100644
--- a/crates/router/tests/connectors/sample_auth.toml
+++ b/crates/router/tests/connectors/sample_auth.toml
@@ -12,3 +12,6 @@ key1 = "MyTransactionKey"
 [checkout]
 api_key = "Bearer MyApiKey"
 key1 = "MyProcessingChannelId"
+
+[shift4]
+api_key = "Bearer MyApiKey"
\ No newline at end of file
diff --git a/crates/router/tests/connectors/shift4.rs b/crates/router/tests/connectors/shift4.rs
new file mode 100644
index 00000000000..dd4f68f4e72
--- /dev/null
+++ b/crates/router/tests/connectors/shift4.rs
@@ -0,0 +1,93 @@
+use futures::future::OptionFuture;
+use masking::Secret;
+use router::types::{self, api, storage::enums};
+
+use crate::{
+    connector_auth,
+    utils::{self, ConnectorActions},
+};
+
+struct Shift4;
+impl utils::ConnectorActions for Shift4 {}
+impl utils::Connector for Shift4 {
+    fn get_data(&self) -> types::api::ConnectorData {
+        use router::connector::Shift4;
+        types::api::ConnectorData {
+            connector: Box::new(&Shift4),
+            connector_name: types::Connector::Shift4,
+            get_token: types::api::GetToken::Connector,
+        }
+    }
+
+    fn get_auth_token(&self) -> types::ConnectorAuthType {
+        types::ConnectorAuthType::from(
+            connector_auth::ConnectorAuthentication::new()
+                .shift4
+                .expect("Missing connector authentication configuration"),
+        )
+    }
+
+    fn get_name(&self) -> String {
+        "shift4".to_string()
+    }
+}
+
+#[actix_web::test]
+async fn should_only_authorize_payment() {
+    let response = Shift4 {}.authorize_payment(None).await;
+    assert_eq!(response.status, enums::AttemptStatus::Authorized);
+}
+
+#[actix_web::test]
+async fn should_authorize_and_capture_payment() {
+    let response = Shift4 {}.make_payment(None).await;
+    assert_eq!(response.status, enums::AttemptStatus::Charged);
+}
+
+#[actix_web::test]
+async fn should_capture_already_authorized_payment() {
+    let connector = Shift4 {};
+    let authorize_response = connector.authorize_payment(None).await;
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Authorized);
+    let txn_id = utils::get_connector_transaction_id(authorize_response);
+    let response: OptionFuture<_> = txn_id
+        .map(|transaction_id| async move {
+            connector.capture_payment(transaction_id, None).await.status
+        })
+        .into();
+    assert_eq!(response.await, Some(enums::AttemptStatus::Charged));
+}
+
+#[actix_web::test]
+async fn should_fail_payment_for_incorrect_cvc() {
+    let response = Shift4 {}
+        .make_payment(Some(types::PaymentsAuthorizeData {
+            payment_method_data: types::api::PaymentMethod::Card(api::CCard {
+                card_number: Secret::new("4024007134364842".to_string()),
+                ..utils::CCardType::default().0
+            }),
+            ..utils::PaymentAuthorizeType::default().0
+        }))
+        .await;
+    let x = response.response.unwrap_err();
+    assert_eq!(
+        x.message,
+        "The card's security code failed verification.".to_string(),
+    );
+}
+
+#[actix_web::test]
+async fn should_refund_succeeded_payment() {
+    let connector = Shift4 {};
+    //make a successful payment
+    let response = connector.make_payment(None).await;
+
+    //try refund for previous payment
+    if let Some(transaction_id) = utils::get_connector_transaction_id(response) {
+        let response = connector.refund_payment(transaction_id, None).await;
+        assert_eq!(
+            response.response.unwrap().refund_status,
+            enums::RefundStatus::Success,
+        );
+    }
+}
diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs
new file mode 100644
index 00000000000..569a38586d2
--- /dev/null
+++ b/crates/router/tests/connectors/utils.rs
@@ -0,0 +1,197 @@
+use std::{fmt::Debug, marker::PhantomData};
+
+use async_trait::async_trait;
+use masking::Secret;
+use router::{
+    core::payments,
+    db::StorageImpl,
+    routes,
+    services::{self},
+    types::{
+        self,
+        api::{self},
+        storage::enums,
+        PaymentAddress, RouterData,
+    },
+};
+
+pub trait Connector {
+    fn get_data(&self) -> types::api::ConnectorData;
+    fn get_auth_token(&self) -> types::ConnectorAuthType;
+    fn get_name(&self) -> String;
+}
+
+#[async_trait]
+pub trait ConnectorActions: Connector {
+    async fn authorize_payment(
+        &self,
+        payment_data: Option<types::PaymentsAuthorizeData>,
+    ) -> types::PaymentsAuthorizeRouterData {
+        let integration = self.get_data().connector.get_connector_integration();
+        let request = generate_data(
+            self.get_name(),
+            self.get_auth_token(),
+            payment_data.unwrap_or_else(|| types::PaymentsAuthorizeData {
+                capture_method: Some(storage_models::enums::CaptureMethod::Manual),
+                ..PaymentAuthorizeType::default().0
+            }),
+        );
+        call_connector(request, integration).await
+    }
+    async fn make_payment(
+        &self,
+        payment_data: Option<types::PaymentsAuthorizeData>,
+    ) -> types::PaymentsAuthorizeRouterData {
+        let integration = self.get_data().connector.get_connector_integration();
+        let request = generate_data(
+            self.get_name(),
+            self.get_auth_token(),
+            payment_data.unwrap_or_else(|| PaymentAuthorizeType::default().0),
+        );
+        call_connector(request, integration).await
+    }
+    async fn capture_payment(
+        &self,
+        transaction_id: String,
+        payment_data: Option<types::PaymentsCaptureData>,
+    ) -> types::PaymentsCaptureRouterData {
+        let integration = self.get_data().connector.get_connector_integration();
+        let request = generate_data(
+            self.get_name(),
+            self.get_auth_token(),
+            payment_data.unwrap_or(types::PaymentsCaptureData {
+                amount_to_capture: Some(100),
+                connector_transaction_id: transaction_id,
+            }),
+        );
+        call_connector(request, integration).await
+    }
+    async fn refund_payment(
+        &self,
+        transaction_id: String,
+        payment_data: Option<types::RefundsData>,
+    ) -> types::RefundExecuteRouterData {
+        let integration = self.get_data().connector.get_connector_integration();
+        let request = generate_data(
+            self.get_name(),
+            self.get_auth_token(),
+            payment_data.unwrap_or_else(|| types::RefundsData {
+                amount: 100,
+                currency: enums::Currency::USD,
+                refund_id: uuid::Uuid::new_v4().to_string(),
+                payment_method_data: types::api::PaymentMethod::Card(CCardType::default().0),
+                connector_transaction_id: transaction_id,
+                refund_amount: 100,
+            }),
+        );
+        call_connector(request, integration).await
+    }
+}
+
+async fn call_connector<
+    T: Debug + Clone + 'static,
+    Req: Debug + Clone + 'static,
+    Resp: Debug + Clone + 'static,
+>(
+    request: RouterData<T, Req, Resp>,
+    integration: services::BoxedConnectorIntegration<'_, T, Req, Resp>,
+) -> types::RouterData<T, Req, Resp> {
+    use router::configs::settings::Settings;
+    let conf = Settings::new().unwrap();
+    let state = routes::AppState::with_storage(conf, StorageImpl::PostgresqlTest).await;
+    services::api::execute_connector_processing_step(
+        &state,
+        integration,
+        &request,
+        payments::CallConnectorAction::Trigger,
+    )
+    .await
+    .unwrap()
+}
+
+pub struct PaymentAuthorizeType(pub types::PaymentsAuthorizeData);
+pub struct PaymentRefundType(pub types::RefundsData);
+pub struct CCardType(pub api::CCard);
+
+impl Default for CCardType {
+    fn default() -> Self {
+        CCardType(api::CCard {
+            card_number: Secret::new("4200000000000000".to_string()),
+            card_exp_month: Secret::new("10".to_string()),
+            card_exp_year: Secret::new("2025".to_string()),
+            card_holder_name: Secret::new("John Doe".to_string()),
+            card_cvc: Secret::new("999".to_string()),
+        })
+    }
+}
+
+impl Default for PaymentAuthorizeType {
+    fn default() -> Self {
+        let data = types::PaymentsAuthorizeData {
+            payment_method_data: types::api::PaymentMethod::Card(CCardType::default().0),
+            amount: 100,
+            currency: enums::Currency::USD,
+            confirm: true,
+            statement_descriptor_suffix: None,
+            capture_method: None,
+            setup_future_usage: None,
+            mandate_id: None,
+            off_session: None,
+            setup_mandate_details: None,
+            browser_info: None,
+            order_details: None,
+        };
+        PaymentAuthorizeType(data)
+    }
+}
+
+impl Default for PaymentRefundType {
+    fn default() -> Self {
+        let data = types::RefundsData {
+            amount: 1000,
+            currency: enums::Currency::USD,
+            refund_id: uuid::Uuid::new_v4().to_string(),
+            payment_method_data: types::api::PaymentMethod::Card(CCardType::default().0),
+            connector_transaction_id: String::new(),
+            refund_amount: 100,
+        };
+        PaymentRefundType(data)
+    }
+}
+
+pub fn get_connector_transaction_id(
+    response: types::PaymentsAuthorizeRouterData,
+) -> Option<String> {
+    match response.response {
+        Ok(types::PaymentsResponseData::TransactionResponse { resource_id, .. }) => {
+            resource_id.get_connector_transaction_id().ok()
+        }
+        Ok(types::PaymentsResponseData::SessionResponse { .. }) => None,
+        Err(_) => None,
+    }
+}
+
+fn generate_data<Flow, Req: From<Req>, Res>(
+    connector: String,
+    connector_auth_type: types::ConnectorAuthType,
+    req: Req,
+) -> types::RouterData<Flow, Req, Res> {
+    types::RouterData {
+        flow: PhantomData,
+        merchant_id: connector.clone(),
+        connector,
+        payment_id: uuid::Uuid::new_v4().to_string(),
+        status: enums::AttemptStatus::default(),
+        orca_return_url: None,
+        auth_type: enums::AuthenticationType::NoThreeDs,
+        payment_method: enums::PaymentMethodType::Card,
+        connector_auth_type,
+        description: Some("This is a test".to_string()),
+        return_url: None,
+        request: req,
+        response: Err(types::ErrorResponse::default()),
+        payment_method_id: None,
+        address: PaymentAddress::default(),
+        connector_meta_data: None,
+    }
+}
diff --git a/keys.conf b/keys.conf
index 9471e84cf99..772aca35eeb 100644
--- a/keys.conf
+++ b/keys.conf
@@ -22,4 +22,4 @@ aci_api_key: <API-KEY>
 aci_key1: <ADDITONAL-KEY>
 
 braintree_api_key: <API-KEY>
-braintree_key1: <ADDITIONAL-KEY>
+braintree_key1: <ADDITIONAL-KEY>
\ No newline at end of file
diff --git a/scripts/add_connector.sh b/scripts/add_connector.sh
new file mode 100644
index 00000000000..38addff3b89
--- /dev/null
+++ b/scripts/add_connector.sh
@@ -0,0 +1,25 @@
+pg=$1;
+pgc="$(tr '[:lower:]' '[:upper:]' <<< ${pg:0:1})${pg:1}"
+src="crates/router/src"
+conn="$src/connector"
+SCRIPT="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
+if [[ -z "$pg" ]]; then 
+    echo 'Connector name not present: try "sh add_connector.sh <adyen>"'
+    exit
+fi
+cd $SCRIPT/..
+rm -rf $conn/$pg $conn/$pg.rs
+git checkout $conn.rs $src/types/api.rs scripts/create_connector_account.sh $src/configs/settings.rs
+sed -i'' -e "s/pub use self::{/pub mod ${pg};\n\npub use self::{/" $conn.rs
+sed -i'' -e "s/};/${pg}::${pgc},\n};/" $conn.rs 
+sed -i'' -e "s/_ => Err/\"${pg}\" => Ok(Box::new(\&connector::${pgc})),\n\t\t\t_ => Err/" $src/types/api.rs
+sed -i'' -e "s/*) echo \"This connector/${pg}) required_connector=\"${pg}\";;\n\t\t*) echo \"This connector/" scripts/create_connector_account.sh
+sed -i'' -e "s/pub supported: SupportedConnectors,/pub supported: SupportedConnectors,\n\tpub ${pg}: ConnectorParams,/" $src/configs/settings.rs
+rm $conn.rs-e $src/types/api.rs-e scripts/create_connector_account.sh-e $src/configs/settings.rs-e
+cd $conn/ 
+cargo gen-pg $pg
+mv $pg/mod.rs $pg.rs
+mv $pg/test.rs ../../tests/connectors/$pg.rs
+sed -i'' -e "s/mod utils;/mod ${pg};\nmod utils;/" ../../tests/connectors/main.rs
+rm ../../tests/connectors/main.rs-e
+echo "Successfully created connector: try running the tests of "$pg.rs
\ No newline at end of file
diff --git a/scripts/create_connector_account.sh b/scripts/create_connector_account.sh
index 4815197ebac..c03a3a44269 100644
--- a/scripts/create_connector_account.sh
+++ b/scripts/create_connector_account.sh
@@ -40,6 +40,7 @@ case "$connector" in
     aci) required_connector="aci";;
     adyen) required_connector="adyen";;
     braintree) required_connector="braintree";;
+    shift4) required_connector="shift4";;
     *) echo "This connector is not supported" 1>&2;exit 1;;
 esac
 

## 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 -->
- Adding support for [shift4](https://www.shift4.com/) payment gateway
- Updated connector template files which are outdated
- Added script to handle manual changes while adding new connector, this can be updated in future to handle all new scenarios

**Payment Method**: card
**Supported payment flows**
- [Authorize](https://dev.shift4.com/docs/api#charge-create)
- [Capture](https://dev.shift4.com/docs/api#charge-capture)
- [PSync](https://dev.shift4.com/docs/api#charge-retrieve)
- [Refund](https://dev.shift4.com/docs/api#refund-create)
- [RSync](https://dev.shift4.com/docs/api#refund-retrieve)
- [Webhook](https://dev.shift4.com/docs/webhooks)


### 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
<!--
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).
-->
Adding new connector [shift4](https://www.shift4.com/)

## 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)?
-->
Added units tests for authorize, capture and refund flows. 
<img width="934" alt="Screenshot 2022-12-21 at 4 24 49 PM" src="https://user-images.githubusercontent.com/20727598/208892758-ae62a963-c087-46fb-8a49-e9fc74fb3e06.png">

## 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
- [X] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
