Bug: [FEATURE] Add External Vault Insert and Retrieve flow for Tokenex



Add External Vault Insert - Tokenize and Retrieve - Detokenize flow for Tokenex
diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs
index 52f2b3c2e02..0b4d53c1857 100644
--- a/crates/api_models/src/enums.rs
+++ b/crates/api_models/src/enums.rs
@@ -177,6 +177,7 @@ pub enum BillingConnectors {
 pub enum VaultConnectors {
     Vgs,
     HyperswitchVault,
+    Tokenex,
 }
 
 impl From<VaultConnectors> for Connector {
@@ -184,6 +185,7 @@ impl From<VaultConnectors> for Connector {
         match value {
             VaultConnectors::Vgs => Self::Vgs,
             VaultConnectors::HyperswitchVault => Self::HyperswitchVault,
+            VaultConnectors::Tokenex => Self::Tokenex,
         }
     }
 }
diff --git a/crates/common_enums/src/connector_enums.rs b/crates/common_enums/src/connector_enums.rs
index 6f429829f5f..cf2e9f1c79b 100644
--- a/crates/common_enums/src/connector_enums.rs
+++ b/crates/common_enums/src/connector_enums.rs
@@ -336,7 +336,7 @@ pub enum Connector {
     Threedsecureio,
     // Tokenio,
     //Thunes,
-    // Tokenex, added as template code for future usage
+    Tokenex,
     Tokenio,
     Trustpay,
     Trustpayments,
@@ -548,6 +548,7 @@ impl Connector {
             | Self::Cardinal
             | Self::CtpVisa
             | Self::Noon
+            | Self::Tokenex
             | Self::Tokenio
             | Self::Stripe
             | Self::Datatrans
@@ -870,7 +871,8 @@ impl TryFrom<Connector> for RoutableConnectors {
             | Connector::Threedsecureio
             | Connector::Vgs
             | Connector::CtpVisa
-            | Connector::Cardinal => Err("Invalid conversion. Not a routable connector"),
+            | Connector::Cardinal
+            | Connector::Tokenex => Err("Invalid conversion. Not a routable connector"),
         }
     }
 }
diff --git a/crates/connector_configs/src/connector.rs b/crates/connector_configs/src/connector.rs
index 9dc646f36d7..3c868782155 100644
--- a/crates/connector_configs/src/connector.rs
+++ b/crates/connector_configs/src/connector.rs
@@ -535,6 +535,7 @@ impl ConnectorConfig {
             Connector::Stax => Ok(connector_data.stax),
             Connector::Stripe => Ok(connector_data.stripe),
             Connector::Stripebilling => Ok(connector_data.stripebilling),
+            Connector::Tokenex => Ok(connector_data.tokenex),
             Connector::Tokenio => Ok(connector_data.tokenio),
             Connector::Trustpay => Ok(connector_data.trustpay),
             Connector::Trustpayments => Ok(connector_data.trustpayments),
diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml
index e27c801fafb..7be63721c9b 100644
--- a/crates/connector_configs/toml/development.toml
+++ b/crates/connector_configs/toml/development.toml
@@ -7087,8 +7087,9 @@ required=false
 type="Text"
 
 [tokenex]
-[tokenex.connector_auth.HeaderKey]
+[tokenex.connector_auth.BodyKey]
 api_key = "API Key"
+key1 = "TokenEx ID"
 
 [gigadat]
 [gigadat.connector_auth.HeaderKey]
diff --git a/crates/hyperswitch_connectors/src/connectors/tokenex.rs b/crates/hyperswitch_connectors/src/connectors/tokenex.rs
index f4477cca6aa..3dbe640beb3 100644
--- a/crates/hyperswitch_connectors/src/connectors/tokenex.rs
+++ b/crates/hyperswitch_connectors/src/connectors/tokenex.rs
@@ -7,29 +7,26 @@ use common_utils::{
     errors::CustomResult,
     ext_traits::BytesExt,
     request::{Method, Request, RequestBuilder, RequestContent},
-    types::{AmountConvertor, StringMinorUnit, StringMinorUnitForConnector},
 };
 use error_stack::{report, ResultExt};
 use hyperswitch_domain_models::{
-    payment_method_data::PaymentMethodData,
     router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
     router_flow_types::{
         access_token_auth::AccessTokenAuth,
         payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void},
         refunds::{Execute, RSync},
+        ExternalVaultInsertFlow, ExternalVaultRetrieveFlow,
     },
     router_request_types::{
         AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData,
         PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData,
-        RefundsData, SetupMandateRequestData,
+        RefundsData, SetupMandateRequestData, VaultRequestData,
     },
     router_response_types::{
         ConnectorInfo, PaymentsResponseData, RefundsResponseData, SupportedPaymentMethods,
+        VaultResponseData,
     },
-    types::{
-        PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, PaymentsSyncRouterData,
-        RefundSyncRouterData, RefundsRouterData,
-    },
+    types::VaultRouterData,
 };
 use hyperswitch_interfaces::{
     api::{
@@ -45,20 +42,10 @@ use hyperswitch_interfaces::{
 use masking::{ExposeInterface, Mask};
 use transformers as tokenex;
 
-use crate::{constants::headers, types::ResponseRouterData, utils};
+use crate::{constants::headers, types::ResponseRouterData};
 
 #[derive(Clone)]
-pub struct Tokenex {
-    amount_converter: &'static (dyn AmountConvertor<Output = StringMinorUnit> + Sync),
-}
-
-impl Tokenex {
-    pub fn new() -> &'static Self {
-        &Self {
-            amount_converter: &StringMinorUnitForConnector,
-        }
-    }
-}
+pub struct Tokenex;
 
 impl api::Payment for Tokenex {}
 impl api::PaymentSession for Tokenex {}
@@ -72,6 +59,9 @@ impl api::Refund for Tokenex {}
 impl api::RefundExecute for Tokenex {}
 impl api::RefundSync for Tokenex {}
 impl api::PaymentToken for Tokenex {}
+impl api::ExternalVaultInsert for Tokenex {}
+impl api::ExternalVault for Tokenex {}
+impl api::ExternalVaultRetrieve for Tokenex {}
 
 impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, PaymentsResponseData>
     for Tokenex
@@ -79,6 +69,13 @@ impl ConnectorIntegration<PaymentMethodToken, PaymentMethodTokenizationData, Pay
     // Not Implemented (R)
 }
 
+pub mod auth_headers {
+    pub const TOKENEX_ID: &str = "tx-tokenex-id";
+    pub const TOKENEX_API_KEY: &str = "tx-apikey";
+    pub const TOKENEX_SCHEME: &str = "tx-token-scheme";
+    pub const TOKENEX_SCHEME_VALUE: &str = "PCI";
+}
+
 impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Tokenex
 where
     Self: ConnectorIntegration<Flow, Request, Response>,
@@ -88,12 +85,26 @@ where
         req: &RouterData<Flow, Request, Response>,
         _connectors: &Connectors,
     ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
-        let mut header = vec![(
-            headers::CONTENT_TYPE.to_string(),
-            self.get_content_type().to_string().into(),
-        )];
-        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
-        header.append(&mut api_key);
+        let auth = tokenex::TokenexAuthType::try_from(&req.connector_auth_type)
+            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
+        let header = vec![
+            (
+                headers::CONTENT_TYPE.to_string(),
+                self.get_content_type().to_string().into(),
+            ),
+            (
+                auth_headers::TOKENEX_ID.to_string(),
+                auth.tokenex_id.expose().into_masked(),
+            ),
+            (
+                auth_headers::TOKENEX_API_KEY.to_string(),
+                auth.api_key.expose().into_masked(),
+            ),
+            (
+                auth_headers::TOKENEX_SCHEME.to_string(),
+                auth_headers::TOKENEX_SCHEME_VALUE.to_string().into(),
+            ),
+        ];
         Ok(header)
     }
 }
@@ -155,31 +166,7 @@ impl ConnectorCommon for Tokenex {
     }
 }
 
-impl ConnectorValidation for Tokenex {
-    fn validate_mandate_payment(
-        &self,
-        _pm_type: Option<enums::PaymentMethodType>,
-        pm_data: PaymentMethodData,
-    ) -> CustomResult<(), errors::ConnectorError> {
-        match pm_data {
-            PaymentMethodData::Card(_) => Err(errors::ConnectorError::NotImplemented(
-                "validate_mandate_payment does not support cards".to_string(),
-            )
-            .into()),
-            _ => Ok(()),
-        }
-    }
-
-    fn validate_psync_reference_id(
-        &self,
-        _data: &PaymentsSyncData,
-        _is_three_ds: bool,
-        _status: enums::AttemptStatus,
-        _connector_meta_data: Option<common_utils::pii::SecretSerdeValue>,
-    ) -> CustomResult<(), errors::ConnectorError> {
-        Ok(())
-    }
-}
+impl ConnectorValidation for Tokenex {}
 
 impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> for Tokenex {
     //TODO: implement sessions flow
@@ -189,200 +176,62 @@ impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken>
 
 impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Tokenex {}
 
-impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Tokenex {
-    fn get_headers(
-        &self,
-        req: &PaymentsAuthorizeRouterData,
-        connectors: &Connectors,
-    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
-        self.build_headers(req, connectors)
-    }
-
-    fn get_content_type(&self) -> &'static str {
-        self.common_get_content_type()
-    }
+impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Tokenex {}
 
-    fn get_url(
-        &self,
-        _req: &PaymentsAuthorizeRouterData,
-        _connectors: &Connectors,
-    ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
-    }
+impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Tokenex {}
 
-    fn get_request_body(
-        &self,
-        req: &PaymentsAuthorizeRouterData,
-        _connectors: &Connectors,
-    ) -> CustomResult<RequestContent, errors::ConnectorError> {
-        let amount = utils::convert_amount(
-            self.amount_converter,
-            req.request.minor_amount,
-            req.request.currency,
-        )?;
-
-        let connector_router_data = tokenex::TokenexRouterData::from((amount, req));
-        let connector_req = tokenex::TokenexPaymentsRequest::try_from(&connector_router_data)?;
-        Ok(RequestContent::Json(Box::new(connector_req)))
-    }
+impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Tokenex {}
 
-    fn build_request(
-        &self,
-        req: &PaymentsAuthorizeRouterData,
-        connectors: &Connectors,
-    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
-        Ok(Some(
-            RequestBuilder::new()
-                .method(Method::Post)
-                .url(&types::PaymentsAuthorizeType::get_url(
-                    self, req, connectors,
-                )?)
-                .attach_default_headers()
-                .headers(types::PaymentsAuthorizeType::get_headers(
-                    self, req, connectors,
-                )?)
-                .set_body(types::PaymentsAuthorizeType::get_request_body(
-                    self, req, connectors,
-                )?)
-                .build(),
-        ))
-    }
+impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Tokenex {}
 
-    fn handle_response(
-        &self,
-        data: &PaymentsAuthorizeRouterData,
-        event_builder: Option<&mut ConnectorEvent>,
-        res: Response,
-    ) -> CustomResult<PaymentsAuthorizeRouterData, errors::ConnectorError> {
-        let response: tokenex::TokenexPaymentsResponse = res
-            .response
-            .parse_struct("Tokenex PaymentsAuthorizeResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        event_builder.map(|i| i.set_response_body(&response));
-        router_env::logger::info!(connector_response=?response);
-        RouterData::try_from(ResponseRouterData {
-            response,
-            data: data.clone(),
-            http_code: res.status_code,
-        })
-    }
+impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Tokenex {}
 
-    fn get_error_response(
-        &self,
-        res: Response,
-        event_builder: Option<&mut ConnectorEvent>,
-    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
-        self.build_error_response(res, event_builder)
-    }
-}
-
-impl ConnectorIntegration<PSync, PaymentsSyncData, PaymentsResponseData> for Tokenex {
-    fn get_headers(
-        &self,
-        req: &PaymentsSyncRouterData,
-        connectors: &Connectors,
-    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
-        self.build_headers(req, connectors)
-    }
-
-    fn get_content_type(&self) -> &'static str {
-        self.common_get_content_type()
-    }
+impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Tokenex {}
 
+impl ConnectorIntegration<ExternalVaultInsertFlow, VaultRequestData, VaultResponseData>
+    for Tokenex
+{
     fn get_url(
         &self,
-        _req: &PaymentsSyncRouterData,
-        _connectors: &Connectors,
-    ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
-    }
-
-    fn build_request(
-        &self,
-        req: &PaymentsSyncRouterData,
+        _req: &VaultRouterData<ExternalVaultInsertFlow>,
         connectors: &Connectors,
-    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
-        Ok(Some(
-            RequestBuilder::new()
-                .method(Method::Get)
-                .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
-                .attach_default_headers()
-                .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
-                .build(),
-        ))
-    }
-
-    fn handle_response(
-        &self,
-        data: &PaymentsSyncRouterData,
-        event_builder: Option<&mut ConnectorEvent>,
-        res: Response,
-    ) -> CustomResult<PaymentsSyncRouterData, errors::ConnectorError> {
-        let response: tokenex::TokenexPaymentsResponse = res
-            .response
-            .parse_struct("tokenex PaymentsSyncResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        event_builder.map(|i| i.set_response_body(&response));
-        router_env::logger::info!(connector_response=?response);
-        RouterData::try_from(ResponseRouterData {
-            response,
-            data: data.clone(),
-            http_code: res.status_code,
-        })
-    }
-
-    fn get_error_response(
-        &self,
-        res: Response,
-        event_builder: Option<&mut ConnectorEvent>,
-    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
-        self.build_error_response(res, event_builder)
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!("{}/v2/Pci/Tokenize", self.base_url(connectors)))
     }
-}
 
-impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> for Tokenex {
     fn get_headers(
         &self,
-        req: &PaymentsCaptureRouterData,
+        req: &VaultRouterData<ExternalVaultInsertFlow>,
         connectors: &Connectors,
     ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
         self.build_headers(req, connectors)
     }
 
-    fn get_content_type(&self) -> &'static str {
-        self.common_get_content_type()
-    }
-
-    fn get_url(
-        &self,
-        _req: &PaymentsCaptureRouterData,
-        _connectors: &Connectors,
-    ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
-    }
-
     fn get_request_body(
         &self,
-        _req: &PaymentsCaptureRouterData,
+        req: &VaultRouterData<ExternalVaultInsertFlow>,
         _connectors: &Connectors,
     ) -> CustomResult<RequestContent, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_request_body method".to_string()).into())
+        let connector_req = tokenex::TokenexInsertRequest::try_from(req)?;
+        Ok(RequestContent::Json(Box::new(connector_req)))
     }
 
     fn build_request(
         &self,
-        req: &PaymentsCaptureRouterData,
+        req: &VaultRouterData<ExternalVaultInsertFlow>,
         connectors: &Connectors,
     ) -> CustomResult<Option<Request>, errors::ConnectorError> {
         Ok(Some(
             RequestBuilder::new()
                 .method(Method::Post)
-                .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
+                .url(&types::ExternalVaultInsertType::get_url(
+                    self, req, connectors,
+                )?)
                 .attach_default_headers()
-                .headers(types::PaymentsCaptureType::get_headers(
+                .headers(types::ExternalVaultInsertType::get_headers(
                     self, req, connectors,
                 )?)
-                .set_body(types::PaymentsCaptureType::get_request_body(
+                .set_body(types::ExternalVaultInsertType::get_request_body(
                     self, req, connectors,
                 )?)
                 .build(),
@@ -391,13 +240,13 @@ impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> fo
 
     fn handle_response(
         &self,
-        data: &PaymentsCaptureRouterData,
+        data: &VaultRouterData<ExternalVaultInsertFlow>,
         event_builder: Option<&mut ConnectorEvent>,
         res: Response,
-    ) -> CustomResult<PaymentsCaptureRouterData, errors::ConnectorError> {
-        let response: tokenex::TokenexPaymentsResponse = res
+    ) -> CustomResult<VaultRouterData<ExternalVaultInsertFlow>, errors::ConnectorError> {
+        let response: tokenex::TokenexInsertResponse = res
             .response
-            .parse_struct("Tokenex PaymentsCaptureResponse")
+            .parse_struct("TokenexInsertResponse")
             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
@@ -417,125 +266,53 @@ impl ConnectorIntegration<Capture, PaymentsCaptureData, PaymentsResponseData> fo
     }
 }
 
-impl ConnectorIntegration<Void, PaymentsCancelData, PaymentsResponseData> for Tokenex {}
-
-impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Tokenex {
-    fn get_headers(
-        &self,
-        req: &RefundsRouterData<Execute>,
-        connectors: &Connectors,
-    ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
-        self.build_headers(req, connectors)
-    }
-
-    fn get_content_type(&self) -> &'static str {
-        self.common_get_content_type()
-    }
-
+impl ConnectorIntegration<ExternalVaultRetrieveFlow, VaultRequestData, VaultResponseData>
+    for Tokenex
+{
     fn get_url(
         &self,
-        _req: &RefundsRouterData<Execute>,
-        _connectors: &Connectors,
-    ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
-    }
-
-    fn get_request_body(
-        &self,
-        req: &RefundsRouterData<Execute>,
-        _connectors: &Connectors,
-    ) -> CustomResult<RequestContent, errors::ConnectorError> {
-        let refund_amount = utils::convert_amount(
-            self.amount_converter,
-            req.request.minor_refund_amount,
-            req.request.currency,
-        )?;
-
-        let connector_router_data = tokenex::TokenexRouterData::from((refund_amount, req));
-        let connector_req = tokenex::TokenexRefundRequest::try_from(&connector_router_data)?;
-        Ok(RequestContent::Json(Box::new(connector_req)))
-    }
-
-    fn build_request(
-        &self,
-        req: &RefundsRouterData<Execute>,
+        _req: &VaultRouterData<ExternalVaultRetrieveFlow>,
         connectors: &Connectors,
-    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
-        let request = RequestBuilder::new()
-            .method(Method::Post)
-            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
-            .attach_default_headers()
-            .headers(types::RefundExecuteType::get_headers(
-                self, req, connectors,
-            )?)
-            .set_body(types::RefundExecuteType::get_request_body(
-                self, req, connectors,
-            )?)
-            .build();
-        Ok(Some(request))
-    }
-
-    fn handle_response(
-        &self,
-        data: &RefundsRouterData<Execute>,
-        event_builder: Option<&mut ConnectorEvent>,
-        res: Response,
-    ) -> CustomResult<RefundsRouterData<Execute>, errors::ConnectorError> {
-        let response: tokenex::RefundResponse = res
-            .response
-            .parse_struct("tokenex RefundResponse")
-            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
-        event_builder.map(|i| i.set_response_body(&response));
-        router_env::logger::info!(connector_response=?response);
-        RouterData::try_from(ResponseRouterData {
-            response,
-            data: data.clone(),
-            http_code: res.status_code,
-        })
-    }
-
-    fn get_error_response(
-        &self,
-        res: Response,
-        event_builder: Option<&mut ConnectorEvent>,
-    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
-        self.build_error_response(res, event_builder)
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!(
+            "{}/v2/Pci/DetokenizeWithCvv",
+            self.base_url(connectors)
+        ))
     }
-}
 
-impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Tokenex {
     fn get_headers(
         &self,
-        req: &RefundSyncRouterData,
+        req: &VaultRouterData<ExternalVaultRetrieveFlow>,
         connectors: &Connectors,
     ) -> CustomResult<Vec<(String, masking::Maskable<String>)>, errors::ConnectorError> {
         self.build_headers(req, connectors)
     }
 
-    fn get_content_type(&self) -> &'static str {
-        self.common_get_content_type()
-    }
-
-    fn get_url(
+    fn get_request_body(
         &self,
-        _req: &RefundSyncRouterData,
+        req: &VaultRouterData<ExternalVaultRetrieveFlow>,
         _connectors: &Connectors,
-    ) -> CustomResult<String, errors::ConnectorError> {
-        Err(errors::ConnectorError::NotImplemented("get_url method".to_string()).into())
+    ) -> CustomResult<RequestContent, errors::ConnectorError> {
+        let connector_req = tokenex::TokenexRetrieveRequest::try_from(req)?;
+        Ok(RequestContent::Json(Box::new(connector_req)))
     }
 
     fn build_request(
         &self,
-        req: &RefundSyncRouterData,
+        req: &VaultRouterData<ExternalVaultRetrieveFlow>,
         connectors: &Connectors,
     ) -> CustomResult<Option<Request>, errors::ConnectorError> {
         Ok(Some(
             RequestBuilder::new()
-                .method(Method::Get)
-                .url(&types::RefundSyncType::get_url(self, req, connectors)?)
+                .method(Method::Post)
+                .url(&types::ExternalVaultRetrieveType::get_url(
+                    self, req, connectors,
+                )?)
                 .attach_default_headers()
-                .headers(types::RefundSyncType::get_headers(self, req, connectors)?)
-                .set_body(types::RefundSyncType::get_request_body(
+                .headers(types::ExternalVaultRetrieveType::get_headers(
+                    self, req, connectors,
+                )?)
+                .set_body(types::ExternalVaultRetrieveType::get_request_body(
                     self, req, connectors,
                 )?)
                 .build(),
@@ -544,13 +321,13 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Tokenex {
 
     fn handle_response(
         &self,
-        data: &RefundSyncRouterData,
+        data: &VaultRouterData<ExternalVaultRetrieveFlow>,
         event_builder: Option<&mut ConnectorEvent>,
         res: Response,
-    ) -> CustomResult<RefundSyncRouterData, errors::ConnectorError> {
-        let response: tokenex::RefundResponse = res
+    ) -> CustomResult<VaultRouterData<ExternalVaultRetrieveFlow>, errors::ConnectorError> {
+        let response: tokenex::TokenexRetrieveResponse = res
             .response
-            .parse_struct("tokenex RefundSyncResponse")
+            .parse_struct("TokenexRetrieveResponse")
             .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
diff --git a/crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs b/crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs
index 163fa16fa29..9d7082746b3 100644
--- a/crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs
@@ -1,20 +1,22 @@
-use common_enums::enums;
-use common_utils::types::StringMinorUnit;
+use common_utils::{
+    ext_traits::{Encode, StringExt},
+    types::StringMinorUnit,
+};
+use error_stack::ResultExt;
 use hyperswitch_domain_models::{
-    payment_method_data::PaymentMethodData,
     router_data::{ConnectorAuthType, RouterData},
-    router_flow_types::refunds::{Execute, RSync},
-    router_request_types::ResponseId,
-    router_response_types::{PaymentsResponseData, RefundsResponseData},
-    types::{PaymentsAuthorizeRouterData, RefundsRouterData},
+    router_flow_types::{ExternalVaultInsertFlow, ExternalVaultRetrieveFlow},
+    router_request_types::VaultRequestData,
+    router_response_types::VaultResponseData,
+    types::VaultRouterData,
+    vault::PaymentMethodVaultingData,
 };
 use hyperswitch_interfaces::errors;
-use masking::Secret;
+use masking::{ExposeInterface, Secret};
 use serde::{Deserialize, Serialize};
 
-use crate::types::{RefundsResponseRouterData, ResponseRouterData};
+use crate::types::ResponseRouterData;
 
-//TODO: Fill the struct with respective fields
 pub struct TokenexRouterData<T> {
     pub amount: StringMinorUnit, // The type of amount that a connector accepts, for example, String, i64, f64, etc.
     pub router_data: T,
@@ -30,33 +32,27 @@ impl<T> From<(StringMinorUnit, T)> for TokenexRouterData<T> {
     }
 }
 
-//TODO: Fill the struct with respective fields
 #[derive(Default, Debug, Serialize, PartialEq)]
-pub struct TokenexPaymentsRequest {
-    amount: StringMinorUnit,
-    card: TokenexCard,
+pub struct TokenexInsertRequest {
+    data: Secret<String>,
 }
 
-#[derive(Default, Debug, Serialize, Eq, PartialEq)]
-pub struct TokenexCard {
-    number: cards::CardNumber,
-    expiry_month: Secret<String>,
-    expiry_year: Secret<String>,
-    cvc: Secret<String>,
-    complete: bool,
-}
-
-impl TryFrom<&TokenexRouterData<&PaymentsAuthorizeRouterData>> for TokenexPaymentsRequest {
+impl<F> TryFrom<&VaultRouterData<F>> for TokenexInsertRequest {
     type Error = error_stack::Report<errors::ConnectorError>;
-    fn try_from(
-        item: &TokenexRouterData<&PaymentsAuthorizeRouterData>,
-    ) -> Result<Self, Self::Error> {
-        match item.router_data.request.payment_method_data.clone() {
-            PaymentMethodData::Card(_) => Err(errors::ConnectorError::NotImplemented(
-                "Card payment method not implemented".to_string(),
+    fn try_from(item: &VaultRouterData<F>) -> Result<Self, Self::Error> {
+        match item.request.payment_method_vaulting_data.clone() {
+            Some(PaymentMethodVaultingData::Card(req_card)) => {
+                let stringified_card = req_card
+                    .encode_to_string_of_json()
+                    .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+                Ok(Self {
+                    data: Secret::new(stringified_card),
+                })
+            }
+            _ => Err(errors::ConnectorError::NotImplemented(
+                "Payment method apart from card".to_string(),
             )
             .into()),
-            _ => Err(errors::ConnectorError::NotImplemented("Payment method".to_string()).into()),
         }
     }
 }
@@ -65,148 +61,126 @@ impl TryFrom<&TokenexRouterData<&PaymentsAuthorizeRouterData>> for TokenexPaymen
 // Auth Struct
 pub struct TokenexAuthType {
     pub(super) api_key: Secret<String>,
+    pub(super) tokenex_id: Secret<String>,
 }
 
 impl TryFrom<&ConnectorAuthType> for TokenexAuthType {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(auth_type: &ConnectorAuthType) -> Result<Self, Self::Error> {
         match auth_type {
-            ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
+            ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self {
                 api_key: api_key.to_owned(),
+                tokenex_id: key1.to_owned(),
             }),
             _ => Err(errors::ConnectorError::FailedToObtainAuthType.into()),
         }
     }
 }
-// PaymentsResponse
-//TODO: Append the remaining status flags
-#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "lowercase")]
-pub enum TokenexPaymentStatus {
-    Succeeded,
-    Failed,
-    #[default]
-    Processing,
-}
 
-impl From<TokenexPaymentStatus> for common_enums::AttemptStatus {
-    fn from(item: TokenexPaymentStatus) -> Self {
-        match item {
-            TokenexPaymentStatus::Succeeded => Self::Charged,
-            TokenexPaymentStatus::Failed => Self::Failure,
-            TokenexPaymentStatus::Processing => Self::Authorizing,
-        }
-    }
-}
-
-//TODO: Fill the struct with respective fields
 #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct TokenexPaymentsResponse {
-    status: TokenexPaymentStatus,
-    id: String,
-}
-
-impl<F, T> TryFrom<ResponseRouterData<F, TokenexPaymentsResponse, T, PaymentsResponseData>>
-    for RouterData<F, T, PaymentsResponseData>
+pub struct TokenexInsertResponse {
+    token: String,
+    first_six: String,
+    success: bool,
+}
+impl
+    TryFrom<
+        ResponseRouterData<
+            ExternalVaultInsertFlow,
+            TokenexInsertResponse,
+            VaultRequestData,
+            VaultResponseData,
+        >,
+    > for RouterData<ExternalVaultInsertFlow, VaultRequestData, VaultResponseData>
 {
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(
-        item: ResponseRouterData<F, TokenexPaymentsResponse, T, PaymentsResponseData>,
+        item: ResponseRouterData<
+            ExternalVaultInsertFlow,
+            TokenexInsertResponse,
+            VaultRequestData,
+            VaultResponseData,
+        >,
     ) -> Result<Self, Self::Error> {
+        let resp = item.response;
+
         Ok(Self {
-            status: common_enums::AttemptStatus::from(item.response.status),
-            response: Ok(PaymentsResponseData::TransactionResponse {
-                resource_id: ResponseId::ConnectorTransactionId(item.response.id),
-                redirection_data: Box::new(None),
-                mandate_reference: Box::new(None),
-                connector_metadata: None,
-                network_txn_id: None,
-                connector_response_reference_id: None,
-                incremental_authorization_allowed: None,
-                charges: None,
+            status: common_enums::AttemptStatus::Started,
+            response: Ok(VaultResponseData::ExternalVaultInsertResponse {
+                connector_vault_id: resp.token.clone(),
+                //fingerprint is not provided by tokenex, using token as fingerprint
+                fingerprint_id: resp.token.clone(),
             }),
             ..item.data
         })
     }
 }
 
-//TODO: Fill the struct with respective fields
-// REFUND :
-// Type definition for RefundRequest
-#[derive(Default, Debug, Serialize)]
-pub struct TokenexRefundRequest {
-    pub amount: StringMinorUnit,
-}
-
-impl<F> TryFrom<&TokenexRouterData<&RefundsRouterData<F>>> for TokenexRefundRequest {
-    type Error = error_stack::Report<errors::ConnectorError>;
-    fn try_from(item: &TokenexRouterData<&RefundsRouterData<F>>) -> Result<Self, Self::Error> {
-        Ok(Self {
-            amount: item.amount.to_owned(),
-        })
-    }
-}
-
-// Type definition for Refund Response
-
-#[allow(dead_code)]
-#[derive(Debug, Copy, Serialize, Default, Deserialize, Clone)]
-pub enum RefundStatus {
-    Succeeded,
-    Failed,
-    #[default]
-    Processing,
-}
-
-impl From<RefundStatus> for enums::RefundStatus {
-    fn from(item: RefundStatus) -> Self {
-        match item {
-            RefundStatus::Succeeded => Self::Success,
-            RefundStatus::Failed => Self::Failure,
-            RefundStatus::Processing => Self::Pending,
-            //TODO: Review mapping
-        }
-    }
+#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
+pub struct TokenexRetrieveRequest {
+    token: Secret<String>, //Currently only card number is tokenized. Data can be stringified and can be tokenized
+    cache_cvv: bool,
 }
 
-//TODO: Fill the struct with respective fields
-#[derive(Default, Debug, Clone, Serialize, Deserialize)]
-pub struct RefundResponse {
-    id: String,
-    status: RefundStatus,
+#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
+pub struct TokenexRetrieveResponse {
+    value: Secret<String>,
+    success: bool,
 }
 
-impl TryFrom<RefundsResponseRouterData<Execute, RefundResponse>> for RefundsRouterData<Execute> {
+impl<F> TryFrom<&VaultRouterData<F>> for TokenexRetrieveRequest {
     type Error = error_stack::Report<errors::ConnectorError>;
-    fn try_from(
-        item: RefundsResponseRouterData<Execute, RefundResponse>,
-    ) -> Result<Self, Self::Error> {
+    fn try_from(item: &VaultRouterData<F>) -> Result<Self, Self::Error> {
+        let connector_vault_id = item.request.connector_vault_id.as_ref().ok_or(
+            errors::ConnectorError::MissingRequiredField {
+                field_name: "connector_vault_id",
+            },
+        )?;
         Ok(Self {
-            response: Ok(RefundsResponseData {
-                connector_refund_id: item.response.id.to_string(),
-                refund_status: enums::RefundStatus::from(item.response.status),
-            }),
-            ..item.data
+            token: Secret::new(connector_vault_id.clone()),
+            cache_cvv: false, //since cvv is not stored at tokenex
         })
     }
 }
 
-impl TryFrom<RefundsResponseRouterData<RSync, RefundResponse>> for RefundsRouterData<RSync> {
+impl
+    TryFrom<
+        ResponseRouterData<
+            ExternalVaultRetrieveFlow,
+            TokenexRetrieveResponse,
+            VaultRequestData,
+            VaultResponseData,
+        >,
+    > for RouterData<ExternalVaultRetrieveFlow, VaultRequestData, VaultResponseData>
+{
     type Error = error_stack::Report<errors::ConnectorError>;
     fn try_from(
-        item: RefundsResponseRouterData<RSync, RefundResponse>,
+        item: ResponseRouterData<
+            ExternalVaultRetrieveFlow,
+            TokenexRetrieveResponse,
+            VaultRequestData,
+            VaultResponseData,
+        >,
     ) -> Result<Self, Self::Error> {
+        let resp = item.response;
+
+        let card_detail: api_models::payment_methods::CardDetail = resp
+            .value
+            .clone()
+            .expose()
+            .parse_struct("CardDetail")
+            .change_context(errors::ConnectorError::ParsingFailed)?;
+
         Ok(Self {
-            response: Ok(RefundsResponseData {
-                connector_refund_id: item.response.id.to_string(),
-                refund_status: enums::RefundStatus::from(item.response.status),
+            status: common_enums::AttemptStatus::Started,
+            response: Ok(VaultResponseData::ExternalVaultRetrieveResponse {
+                vault_data: PaymentMethodVaultingData::Card(card_detail),
             }),
             ..item.data
         })
     }
 }
 
-//TODO: Fill the struct with respective fields
 #[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
 pub struct TokenexErrorResponse {
     pub status_code: u16,
diff --git a/crates/hyperswitch_connectors/src/default_implementations.rs b/crates/hyperswitch_connectors/src/default_implementations.rs
index 057aca866f4..ad6a276b672 100644
--- a/crates/hyperswitch_connectors/src/default_implementations.rs
+++ b/crates/hyperswitch_connectors/src/default_implementations.rs
@@ -7765,7 +7765,6 @@ default_imp_for_external_vault!(
     connectors::Taxjar,
     connectors::Threedsecureio,
     connectors::Thunes,
-    connectors::Tokenex,
     connectors::Tokenio,
     connectors::Trustpay,
     connectors::Trustpayments,
@@ -7911,7 +7910,6 @@ default_imp_for_external_vault_insert!(
     connectors::Taxjar,
     connectors::Threedsecureio,
     connectors::Thunes,
-    connectors::Tokenex,
     connectors::Tokenio,
     connectors::Trustpay,
     connectors::Trustpayments,
@@ -8202,7 +8200,6 @@ default_imp_for_external_vault_retrieve!(
     connectors::Taxjar,
     connectors::Threedsecureio,
     connectors::Thunes,
-    connectors::Tokenex,
     connectors::Tokenio,
     connectors::Trustpay,
     connectors::Trustpayments,
diff --git a/crates/router/src/core/connector_validation.rs b/crates/router/src/core/connector_validation.rs
index 29e13cfd378..a4bc945b935 100644
--- a/crates/router/src/core/connector_validation.rs
+++ b/crates/router/src/core/connector_validation.rs
@@ -492,6 +492,10 @@ impl ConnectorAuthTypeAndMetadataValidation<'_> {
                 trustpayments::transformers::TrustpaymentsAuthType::try_from(self.auth_type)?;
                 Ok(())
             }
+            api_enums::Connector::Tokenex => {
+                tokenex::transformers::TokenexAuthType::try_from(self.auth_type)?;
+                Ok(())
+            }
             api_enums::Connector::Tokenio => {
                 tokenio::transformers::TokenioAuthType::try_from(self.auth_type)?;
                 Ok(())
diff --git a/crates/router/src/core/unified_connector_service.rs b/crates/router/src/core/unified_connector_service.rs
index 32953cd5eaf..3792cfa280e 100644
--- a/crates/router/src/core/unified_connector_service.rs
+++ b/crates/router/src/core/unified_connector_service.rs
@@ -550,7 +550,7 @@ pub fn build_unified_connector_service_external_vault_proxy_metadata(
                 }
             ))
         }
-        api_enums::VaultConnectors::HyperswitchVault => None,
+        api_enums::VaultConnectors::HyperswitchVault | api_enums::VaultConnectors::Tokenex => None,
     };
 
     match unified_service_vault_metdata {
diff --git a/crates/router/src/types/api/connector_mapping.rs b/crates/router/src/types/api/connector_mapping.rs
index adef987b03d..3c20816b68b 100644
--- a/crates/router/src/types/api/connector_mapping.rs
+++ b/crates/router/src/types/api/connector_mapping.rs
@@ -434,6 +434,7 @@ impl ConnectorData {
                     Ok(ConnectorEnum::Old(Box::new(connector::Paystack::new())))
                 }
                 // enums::Connector::Thunes => Ok(ConnectorEnum::Old(Box::new(connector::Thunes))),
+                enums::Connector::Tokenex => Ok(ConnectorEnum::Old(Box::new(&connector::Tokenex))),
                 enums::Connector::Tokenio => {
                     Ok(ConnectorEnum::Old(Box::new(connector::Tokenio::new())))
                 }
diff --git a/crates/router/src/types/api/feature_matrix.rs b/crates/router/src/types/api/feature_matrix.rs
index bad9c07fe2c..9f514337a68 100644
--- a/crates/router/src/types/api/feature_matrix.rs
+++ b/crates/router/src/types/api/feature_matrix.rs
@@ -353,6 +353,7 @@ impl FeatureMatrixConnectorData {
                     Ok(ConnectorEnum::Old(Box::new(connector::Paystack::new())))
                 }
                 // enums::Connector::Thunes => Ok(ConnectorEnum::Old(Box::new(connector::Thunes))),
+                enums::Connector::Tokenex => Ok(ConnectorEnum::Old(Box::new(&connector::Tokenex))),
                 enums::Connector::Tokenio => {
                     Ok(ConnectorEnum::Old(Box::new(connector::Tokenio::new())))
                 }
diff --git a/crates/router/src/types/connector_transformers.rs b/crates/router/src/types/connector_transformers.rs
index ee9ec93c5a1..ae8dfa26727 100644
--- a/crates/router/src/types/connector_transformers.rs
+++ b/crates/router/src/types/connector_transformers.rs
@@ -145,6 +145,11 @@ impl ForeignTryFrom<api_enums::Connector> for common_enums::RoutableConnectors {
             api_enums::Connector::Stripe => Self::Stripe,
             api_enums::Connector::Stripebilling => Self::Stripebilling,
             // api_enums::Connector::Thunes => Self::Thunes,
+            api_enums::Connector::Tokenex => {
+                Err(common_utils::errors::ValidationError::InvalidValue {
+                    message: "Tokenex is not a routable connector".to_string(),
+                })?
+            }
             api_enums::Connector::Tokenio => Self::Tokenio,
             api_enums::Connector::Trustpay => Self::Trustpay,
             api_enums::Connector::Trustpayments => Self::Trustpayments,
diff --git a/crates/router/tests/connectors/tokenex.rs b/crates/router/tests/connectors/tokenex.rs
index fbcbe13019a..72fe2daacce 100644
--- a/crates/router/tests/connectors/tokenex.rs
+++ b/crates/router/tests/connectors/tokenex.rs
@@ -12,8 +12,8 @@ impl utils::Connector for TokenexTest {
     fn get_data(&self) -> api::ConnectorData {
         use router::connector::Tokenex;
         utils::construct_connector_data_old(
-            Box::new(Tokenex::new()),
-            types::Connector::Plaid,
+            Box::new(&Tokenex),
+            types::Connector::Tokenex,
             api::GetToken::Connector,
             None,
         )
diff --git a/crates/test_utils/src/connector_auth.rs b/crates/test_utils/src/connector_auth.rs
index d58a1d8388f..e44d56a57d6 100644
--- a/crates/test_utils/src/connector_auth.rs
+++ b/crates/test_utils/src/connector_auth.rs
@@ -121,7 +121,7 @@ pub struct ConnectorAuthentication {
     pub taxjar: Option<HeaderKey>,
     pub threedsecureio: Option<HeaderKey>,
     pub thunes: Option<HeaderKey>,
-    pub tokenex: Option<HeaderKey>,
+    pub tokenex: Option<BodyKey>,
     pub tokenio: Option<HeaderKey>,
     pub stripe_au: Option<HeaderKey>,
     pub stripe_uk: Option<HeaderKey>,

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

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

## Description
<!-- Describe your changes in detail -->
Add external vault insert - tokenize and retrieve - detokenize flows for tokenex vault connector

### Additional Changes

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

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

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


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

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


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Currently this cannot be tested.
since external vault support is added in this pr - https://github.com/juspay/hyperswitch/pull/9274



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

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