Bug: [FIX][Tokenex] fix tokenize flow response handling



data in tokenize flow for tokenex accepts only length of 13-19 chars, we are sending complete card data.
diff --git a/crates/hyperswitch_connectors/src/connectors/tokenex.rs b/crates/hyperswitch_connectors/src/connectors/tokenex.rs
index 3dbe640beb3..1a4d2fc5021 100644
--- a/crates/hyperswitch_connectors/src/connectors/tokenex.rs
+++ b/crates/hyperswitch_connectors/src/connectors/tokenex.rs
@@ -151,11 +151,13 @@ impl ConnectorCommon for Tokenex {
         event_builder.map(|i| i.set_response_body(&response));
         router_env::logger::info!(connector_response=?response);
 
+        let (code, message) = response.error.split_once(':').unwrap_or(("", ""));
+
         Ok(ErrorResponse {
             status_code: res.status_code,
-            code: response.code,
-            message: response.message,
-            reason: response.reason,
+            code: code.to_string(),
+            message: message.to_string(),
+            reason: Some(response.message),
             attempt_status: None,
             connector_transaction_id: None,
             network_advice_code: None,
diff --git a/crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs b/crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs
index 9d7082746b3..1904ac1840d 100644
--- a/crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/tokenex/transformers.rs
@@ -1,10 +1,7 @@
-use common_utils::{
-    ext_traits::{Encode, StringExt},
-    types::StringMinorUnit,
-};
+use common_utils::types::StringMinorUnit;
 use error_stack::ResultExt;
 use hyperswitch_domain_models::{
-    router_data::{ConnectorAuthType, RouterData},
+    router_data::{ConnectorAuthType, ErrorResponse, RouterData},
     router_flow_types::{ExternalVaultInsertFlow, ExternalVaultRetrieveFlow},
     router_request_types::VaultRequestData,
     router_response_types::VaultResponseData,
@@ -12,7 +9,7 @@ use hyperswitch_domain_models::{
     vault::PaymentMethodVaultingData,
 };
 use hyperswitch_interfaces::errors;
-use masking::{ExposeInterface, Secret};
+use masking::Secret;
 use serde::{Deserialize, Serialize};
 
 use crate::types::ResponseRouterData;
@@ -24,7 +21,6 @@ pub struct TokenexRouterData<T> {
 
 impl<T> From<(StringMinorUnit, T)> for TokenexRouterData<T> {
     fn from((amount, item): (StringMinorUnit, T)) -> Self {
-        //Todo :  use utils to convert the amount to the type of amount that a connector accepts
         Self {
             amount,
             router_data: item,
@@ -34,21 +30,16 @@ impl<T> From<(StringMinorUnit, T)> for TokenexRouterData<T> {
 
 #[derive(Default, Debug, Serialize, PartialEq)]
 pub struct TokenexInsertRequest {
-    data: Secret<String>,
+    data: cards::CardNumber, //Currently only card number is tokenized. Data can be stringified and can be tokenized
 }
 
 impl<F> TryFrom<&VaultRouterData<F>> for TokenexInsertRequest {
     type Error = error_stack::Report<errors::ConnectorError>;
     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),
-                })
-            }
+            Some(PaymentMethodVaultingData::Card(req_card)) => Ok(Self {
+                data: req_card.card_number.clone(),
+            }),
             _ => Err(errors::ConnectorError::NotImplemented(
                 "Payment method apart from card".to_string(),
             )
@@ -56,9 +47,6 @@ impl<F> TryFrom<&VaultRouterData<F>> for TokenexInsertRequest {
         }
     }
 }
-
-//TODO: Fill the struct with respective fields
-// Auth Struct
 pub struct TokenexAuthType {
     pub(super) api_key: Secret<String>,
     pub(super) tokenex_id: Secret<String>,
@@ -78,10 +66,14 @@ impl TryFrom<&ConnectorAuthType> for TokenexAuthType {
 }
 
 #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
 pub struct TokenexInsertResponse {
-    token: String,
-    first_six: String,
+    token: Option<String>,
+    first_six: Option<String>,
+    last_four: Option<String>,
     success: bool,
+    error: String,
+    message: Option<String>,
 }
 impl
     TryFrom<
@@ -103,20 +95,49 @@ impl
         >,
     ) -> Result<Self, Self::Error> {
         let resp = item.response;
+        match resp.success && resp.error.is_empty() {
+            true => {
+                let token = resp
+                    .token
+                    .clone()
+                    .ok_or(errors::ConnectorError::ResponseDeserializationFailed)
+                    .attach_printable("Token is missing in tokenex response")?;
+                Ok(Self {
+                    status: common_enums::AttemptStatus::Started,
+                    response: Ok(VaultResponseData::ExternalVaultInsertResponse {
+                        connector_vault_id: token.clone(),
+                        //fingerprint is not provided by tokenex, using token as fingerprint
+                        fingerprint_id: token.clone(),
+                    }),
+                    ..item.data
+                })
+            }
+            false => {
+                let (code, message) = resp.error.split_once(':').unwrap_or(("", ""));
+
+                let response = Err(ErrorResponse {
+                    code: code.to_string(),
+                    message: message.to_string(),
+                    reason: resp.message,
+                    status_code: item.http_code,
+                    attempt_status: None,
+                    connector_transaction_id: None,
+                    network_decline_code: None,
+                    network_advice_code: None,
+                    network_error_message: None,
+                    connector_metadata: None,
+                });
 
-        Ok(Self {
-            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
-        })
+                Ok(Self {
+                    response,
+                    ..item.data
+                })
+            }
+        }
     }
 }
-
 #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
 pub struct TokenexRetrieveRequest {
     token: Secret<String>, //Currently only card number is tokenized. Data can be stringified and can be tokenized
     cache_cvv: bool,
@@ -124,8 +145,10 @@ pub struct TokenexRetrieveRequest {
 
 #[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq)]
 pub struct TokenexRetrieveResponse {
-    value: Secret<String>,
+    value: Option<cards::CardNumber>,
     success: bool,
+    error: String,
+    message: Option<String>,
 }
 
 impl<F> TryFrom<&VaultRouterData<F>> for TokenexRetrieveRequest {
@@ -164,30 +187,48 @@ impl
     ) -> 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)?;
+        match resp.success && resp.error.is_empty() {
+            true => {
+                let data = resp
+                    .value
+                    .clone()
+                    .ok_or(errors::ConnectorError::ResponseDeserializationFailed)
+                    .attach_printable("Card number is missing in tokenex response")?;
+                Ok(Self {
+                    status: common_enums::AttemptStatus::Started,
+                    response: Ok(VaultResponseData::ExternalVaultRetrieveResponse {
+                        vault_data: PaymentMethodVaultingData::CardNumber(data),
+                    }),
+                    ..item.data
+                })
+            }
+            false => {
+                let (code, message) = resp.error.split_once(':').unwrap_or(("", ""));
+
+                let response = Err(ErrorResponse {
+                    code: code.to_string(),
+                    message: message.to_string(),
+                    reason: resp.message,
+                    status_code: item.http_code,
+                    attempt_status: None,
+                    connector_transaction_id: None,
+                    network_decline_code: None,
+                    network_advice_code: None,
+                    network_error_message: None,
+                    connector_metadata: None,
+                });
 
-        Ok(Self {
-            status: common_enums::AttemptStatus::Started,
-            response: Ok(VaultResponseData::ExternalVaultRetrieveResponse {
-                vault_data: PaymentMethodVaultingData::Card(card_detail),
-            }),
-            ..item.data
-        })
+                Ok(Self {
+                    response,
+                    ..item.data
+                })
+            }
+        }
     }
 }
 
-#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 pub struct TokenexErrorResponse {
-    pub status_code: u16,
-    pub code: String,
+    pub error: String,
     pub message: String,
-    pub reason: Option<String>,
-    pub network_advice_code: Option<String>,
-    pub network_decline_code: Option<String>,
-    pub network_error_message: Option<String>,
 }
diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs
index 932244a986d..6bc9062eea2 100644
--- a/crates/hyperswitch_domain_models/src/payment_method_data.rs
+++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs
@@ -7,10 +7,8 @@ use api_models::{
     payments::{additional_info as payment_additional_types, ExtendedCardInfo},
 };
 use common_enums::enums as api_enums;
-#[cfg(feature = "v2")]
-use common_utils::ext_traits::OptionExt;
 use common_utils::{
-    ext_traits::StringExt,
+    ext_traits::{OptionExt, StringExt},
     id_type,
     new_type::{
         MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode, MaskedUpiVpaId,
@@ -18,7 +16,7 @@ use common_utils::{
     payout_method_utils,
     pii::{self, Email},
 };
-use masking::{PeekInterface, Secret};
+use masking::{ExposeInterface, PeekInterface, Secret};
 use serde::{Deserialize, Serialize};
 use time::Date;
 
@@ -2327,6 +2325,13 @@ impl PaymentMethodsData {
             Self::BankDetails(_) | Self::WalletDetails(_) | Self::NetworkToken(_) => None,
         }
     }
+    pub fn get_card_details(&self) -> Option<CardDetailsPaymentMethod> {
+        if let Self::Card(card) = self {
+            Some(card.clone())
+        } else {
+            None
+        }
+    }
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
@@ -2593,8 +2598,6 @@ impl
 
         // The card_holder_name from locker retrieved card is considered if it is a non-empty string or else card_holder_name is picked
         let name_on_card = if let Some(name) = card_holder_name.clone() {
-            use masking::ExposeInterface;
-
             if name.clone().expose().is_empty() {
                 card_token_data
                     .and_then(|token_data| token_data.card_holder_name.clone())
@@ -2626,3 +2629,63 @@ impl
         }
     }
 }
+
+#[cfg(feature = "v1")]
+impl
+    TryFrom<(
+        cards::CardNumber,
+        Option<&CardToken>,
+        Option<payment_methods::CoBadgedCardData>,
+        CardDetailsPaymentMethod,
+    )> for Card
+{
+    type Error = error_stack::Report<common_utils::errors::ValidationError>;
+    fn try_from(
+        value: (
+            cards::CardNumber,
+            Option<&CardToken>,
+            Option<payment_methods::CoBadgedCardData>,
+            CardDetailsPaymentMethod,
+        ),
+    ) -> Result<Self, Self::Error> {
+        let (card_number, card_token_data, co_badged_card_data, card_details) = value;
+
+        // The card_holder_name from locker retrieved card is considered if it is a non-empty string or else card_holder_name is picked
+        let name_on_card = if let Some(name) = card_details.card_holder_name.clone() {
+            if name.clone().expose().is_empty() {
+                card_token_data
+                    .and_then(|token_data| token_data.card_holder_name.clone())
+                    .or(Some(name))
+            } else {
+                Some(name)
+            }
+        } else {
+            card_token_data.and_then(|token_data| token_data.card_holder_name.clone())
+        };
+
+        Ok(Self {
+            card_number,
+            card_exp_month: card_details
+                .expiry_month
+                .get_required_value("expiry_month")?
+                .clone(),
+            card_exp_year: card_details
+                .expiry_year
+                .get_required_value("expiry_year")?
+                .clone(),
+            card_holder_name: name_on_card,
+            card_cvc: card_token_data
+                .cloned()
+                .unwrap_or_default()
+                .card_cvc
+                .unwrap_or_default(),
+            card_issuer: card_details.card_issuer,
+            card_network: card_details.card_network,
+            card_type: card_details.card_type,
+            card_issuing_country: card_details.issuer_country,
+            bank_code: None,
+            nick_name: card_details.nick_name,
+            co_badged_card_data,
+        })
+    }
+}
diff --git a/crates/hyperswitch_domain_models/src/vault.rs b/crates/hyperswitch_domain_models/src/vault.rs
index 9ba63f50233..94f23b4fbb3 100644
--- a/crates/hyperswitch_domain_models/src/vault.rs
+++ b/crates/hyperswitch_domain_models/src/vault.rs
@@ -12,6 +12,7 @@ pub enum PaymentMethodVaultingData {
     Card(payment_methods::CardDetail),
     #[cfg(feature = "v2")]
     NetworkToken(payment_method_data::NetworkTokenDetails),
+    CardNumber(cards::CardNumber),
 }
 
 impl PaymentMethodVaultingData {
@@ -20,6 +21,7 @@ impl PaymentMethodVaultingData {
             Self::Card(card) => Some(card),
             #[cfg(feature = "v2")]
             Self::NetworkToken(_) => None,
+            Self::CardNumber(_) => None,
         }
     }
     pub fn get_payment_methods_data(&self) -> payment_method_data::PaymentMethodsData {
@@ -35,6 +37,23 @@ impl PaymentMethodVaultingData {
                     ),
                 )
             }
+            Self::CardNumber(_card_number) => payment_method_data::PaymentMethodsData::Card(
+                payment_method_data::CardDetailsPaymentMethod {
+                    last4_digits: None,
+                    issuer_country: None,
+                    expiry_month: None,
+                    expiry_year: None,
+                    nick_name: None,
+                    card_holder_name: None,
+                    card_isin: None,
+                    card_issuer: None,
+                    card_network: None,
+                    card_type: None,
+                    saved_to_locker: false,
+                    #[cfg(feature = "v1")]
+                    co_badged_card_data: None,
+                },
+            ),
         }
     }
 }
@@ -49,6 +68,7 @@ impl VaultingDataInterface for PaymentMethodVaultingData {
             Self::Card(card) => card.card_number.to_string(),
             #[cfg(feature = "v2")]
             Self::NetworkToken(network_token) => network_token.network_token.to_string(),
+            Self::CardNumber(card_number) => card_number.to_string(),
         }
     }
 }
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index b07b89e1328..ed78b942e9c 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -2201,18 +2201,7 @@ pub async fn create_pm_additional_data_update(
     external_vault_source: Option<id_type::MerchantConnectorAccountId>,
 ) -> RouterResult<storage::PaymentMethodUpdate> {
     let encrypted_payment_method_data = pmd
-        .map(
-            |payment_method_vaulting_data| match payment_method_vaulting_data {
-                domain::PaymentMethodVaultingData::Card(card) => domain::PaymentMethodsData::Card(
-                    domain::CardDetailsPaymentMethod::from(card.clone()),
-                ),
-                domain::PaymentMethodVaultingData::NetworkToken(network_token) => {
-                    domain::PaymentMethodsData::NetworkToken(
-                        domain::NetworkTokenDetailsPaymentMethod::from(network_token.clone()),
-                    )
-                }
-            },
-        )
+        .map(|payment_method_vaulting_data| payment_method_vaulting_data.get_payment_methods_data())
         .async_map(|payment_method_details| async {
             let key_manager_state = &(state).into();
 
diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs
index 771df3d97c7..98888520d59 100644
--- a/crates/router/src/core/payment_methods/vault.rs
+++ b/crates/router/src/core/payment_methods/vault.rs
@@ -1964,9 +1964,12 @@ pub fn get_vault_response_for_retrieve_payment_method_data_v1<F>(
             }
         },
         Err(err) => {
-            logger::error!("Failed to retrieve payment method: {:?}", err);
+            logger::error!(
+                "Failed to retrieve payment method from external vault: {:?}",
+                err
+            );
             Err(report!(errors::ApiErrorResponse::InternalServerError)
-                .attach_printable("Failed to retrieve payment method"))
+                .attach_printable("Failed to retrieve payment method from external vault"))
         }
     }
 }
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 044466523d4..10d72baf282 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -2512,10 +2512,30 @@ pub async fn fetch_card_details_from_external_vault(
     )
     .await?;
 
+    let payment_methods_data = payment_method_info.get_payment_methods_data();
+
     match vault_resp {
         hyperswitch_domain_models::vault::PaymentMethodVaultingData::Card(card) => Ok(
             domain::Card::from((card, card_token_data, co_badged_card_data)),
         ),
+        hyperswitch_domain_models::vault::PaymentMethodVaultingData::CardNumber(card_number) => {
+            let payment_methods_data = payment_methods_data
+                .get_required_value("PaymentMethodsData")
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Payment methods data not present")?;
+
+            let card = payment_methods_data
+                .get_card_details()
+                .get_required_value("CardDetails")
+                .change_context(errors::ApiErrorResponse::InternalServerError)
+                .attach_printable("Card details not present")?;
+
+            Ok(
+                domain::Card::try_from((card_number, card_token_data, co_badged_card_data, card))
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed to generate card data")?,
+            )
+        }
     }
 }
 #[cfg(feature = "v1")]

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

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

## Description
<!-- Describe your changes in detail -->
data in tokenize flow for tokenex accepts only length of 13-19 chars,  we are sending complete card data.

### 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)?
-->
Please refer to this pr - https://github.com/juspay/hyperswitch/pull/9274 on how to enable external vault for profile
- create tokenex mca
```
curl --location 'http://localhost:8080/account/merchant_1758632854/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: api-key' \
--data '{
    "connector_type": "vault_processor",
    "connector_name": "tokenex",
    "connector_account_details": {
        "auth_type": "BodyKey",
        "api_key": "api_key",
        "key1": "key1"
        
    },
    "test_mode": true,
    "disabled": false,
    "business_country": "US",
    "business_label": "default",
    "payment_methods_enabled": [
    ],
    "metadata": {
        "endpoint_prefix": "ghjg",
        "google_pay": {
            "allowed_payment_methods": [
                {
                    "type": "CARD",
                    "parameters": {
                        "allowed_auth_methods": [
                            "PAN_ONLY",
                            "CRYPTOGRAM_3DS"
                        ],
                        "allowed_card_networks": [
                            "AMEX",
                            "DISCOVER",
                            "INTERAC",
                            "JCB",
                            "MASTERCARD",
                            "VISA"
                        ]
                    },
                    "tokenization_specification": {
                        "type": "PAYMENT_GATEWAY"
                    }
                }
            ],
            "merchant_info": {
                "merchant_name": "Narayan Bhat"
            }
        }
    },
     "connector_webhook_details": {
        "merchant_secret": "7091687210DF6DCA38B2E670B3D68EB53516A26CA85590E29024FFBD7CD23980"
    },
    "profile_id":"pro_KH7MujUjH2miLhfzGlAB"
}'
```
- enable external vault for profile
- make a payment with customer acceptance and setup_future_usage - on_session/off_session
<img width="1055" height="941" alt="Screenshot 2025-09-24 at 10 48 05 AM" src="https://github.com/user-attachments/assets/46c43aed-022d-4cad-8204-912357f1a298" />
<img width="1059" height="947" alt="Screenshot 2025-09-24 at 12 48 36 PM" src="https://github.com/user-attachments/assets/31cf863a-a126-4ac2-bd76-1d08950dae10" />
request - 

```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_jN7RVfxJgyz3GB7OASKFved09yY2lA17xEJSBbj47tBN03inP9rCADUooCF5Ozz6' \
--data-raw '
{
    "amount": 1000,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "customer_id":"cu_1758488194",
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
"payment_method": "card",
    "payment_method_type": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "card_cvc": "737"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX",
            "last_name": "ss"
        }
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "John",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "browser_info": {
        "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.110 Safari\/537.36",
        "accept_header": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "125.0.0.1"
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {},
    "order_details": [
        {
            "product_name": "Apple iphone 15",
            "quantity": 1,
            "amount": 0,
            "account_name": "transaction_processing"
        }
    ],
    "profile_id": "pro_KH7MujUjH2miLhfzGlAB"
}'
```

response-
```
{
    "payment_id": "pay_yx1fFGndifp7EQB3opNZ",
    "merchant_id": "merchant_1758632854",
    "status": "succeeded",
    "amount": 1000,
    "net_amount": 1000,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 1000,
    "connector": "adyen",
    "client_secret": "pay_yx1fFGndifp7EQB3opNZ_secret_0RiRDFg3M0R56irWcNPa",
    "created": "2025-09-24T05:13:52.934Z",
    "currency": "USD",
    "customer_id": "cu_1758488194",
    "customer": {
        "id": "cu_1758488194",
        "name": "John Doe",
        "email": "guest@example.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "on_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1111",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "411111",
            "card_extended_bin": null,
            "card_exp_month": "03",
            "card_exp_year": "2030",
            "card_holder_name": "joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "John",
            "last_name": "Doe",
            "origin_zip": null
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": "ss",
            "origin_zip": null
        },
        "phone": null,
        "email": null
    },
    "order_details": [
        {
            "sku": null,
            "upc": null,
            "brand": null,
            "amount": 0,
            "category": null,
            "quantity": 1,
            "tax_rate": null,
            "product_id": null,
            "description": null,
            "product_name": "Apple iphone 15",
            "product_type": null,
            "sub_category": null,
            "total_amount": null,
            "commodity_code": null,
            "unit_of_measure": null,
            "product_img_link": null,
            "product_tax_code": null,
            "total_tax_amount": null,
            "requires_shipping": null,
            "unit_discount_amount": null
        }
    ],
    "email": "guest@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cu_1758488194",
        "created_at": 1758690832,
        "expires": 1758694432,
        "secret": "epk_5ee608c074874637922ff9a945f075d9"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": "TLVXXSHZFB55CG75",
    "frm_message": null,
    "metadata": {},
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": null,
        "gateway_system": "direct"
    },
    "reference_id": "pay_yx1fFGndifp7EQB3opNZ_1",
    "payment_link": null,
    "profile_id": "pro_KH7MujUjH2miLhfzGlAB",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_K1J4djESc692nk5upGnL",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-09-24T05:28:52.934Z",
    "fingerprint": null,
    "browser_info": {
        "language": "nl-NL",
        "time_zone": 0,
        "ip_address": "125.0.0.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1536,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 723,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": null,
    "network_transaction_id": "043891143898481",
    "payment_method_status": null,
    "updated": "2025-09-24T05:13:55.173Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null,
    "enable_partial_authorization": null,
    "enable_overcapture": null,
    "is_overcapture_enabled": null,
    "network_details": null
}

```

- payment method entry will be created.
<img width="1728" height="624" alt="Screenshot 2025-09-24 at 10 47 48 AM" src="https://github.com/user-attachments/assets/56a4f33e-ac42-4763-8ba5-cafa37581fc9" />

- raw connector request & response of  tokenex 
<img width="1714" height="475" alt="Screenshot 2025-09-24 at 10 46 20 AM" src="https://github.com/user-attachments/assets/51704ea6-0846-4fee-8b69-77f0d4310eb4" />
![Screenshot 2025-09-25 at 1 10 38 PM](https://github.com/user-attachments/assets/09b7a3e7-733c-4482-bb2a-2e43e33455e3)
<img width="1004" height="960" alt="Screenshot 2025-09-25 at 1 12 28 PM" src="https://github.com/user-attachments/assets/2b074348-d4f0-4317-bcfe-fcb708670727" />



## 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
