Bug: Skip session to call pay when the browser is not `Safari`



Currently, the Apple Pay session call is mandatory in all cases. This requirement also mandates configuring the initiative_context, which is the domain name where the Apple Pay payment is being processed. However, in the case of an iOS app, a domain is not required, so this field can be made optional. Additionally, in this case, the session call to Apple Pay can be skipped.

On the web, Apple Pay is supported only in Safari. Therefore, the session call should be skipped in web environments when the browser is not Safari.
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index 777e876b1b5..bf275a0dd0f 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -20,6 +20,7 @@ use serde::{
     ser::Serializer,
     Deserialize, Deserializer, Serialize,
 };
+use strum::Display;
 use time::{Date, PrimitiveDateTime};
 use url::Url;
 use utoipa::ToSchema;
@@ -592,6 +593,8 @@ pub struct HeaderPayload {
     pub client_source: Option<String>,
     pub client_version: Option<String>,
     pub x_hs_latency: Option<bool>,
+    pub browser_name: Option<api_enums::BrowserName>,
+    pub x_client_platform: Option<api_enums::ClientPlatform>,
 }
 
 impl HeaderPayload {
@@ -4299,14 +4302,21 @@ pub struct SessionTokenInfo {
     pub certificate_keys: Secret<String>,
     pub merchant_identifier: String,
     pub display_name: String,
-    pub initiative: String,
-    pub initiative_context: String,
+    pub initiative: ApplepayInitiative,
+    pub initiative_context: Option<String>,
     #[schema(value_type = Option<CountryAlpha2>)]
     pub merchant_business_country: Option<api_enums::CountryAlpha2>,
     #[serde(flatten)]
     pub payment_processing_details_at: Option<PaymentProcessingDetailsAt>,
 }
 
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Display, ToSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum ApplepayInitiative {
+    Web,
+    Ios,
+}
+
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 #[serde(tag = "payment_processing_details_at")]
 pub enum PaymentProcessingDetailsAt {
@@ -4421,7 +4431,9 @@ pub struct PaypalSessionTokenResponse {
 #[serde(rename_all = "lowercase")]
 pub struct ApplepaySessionTokenResponse {
     /// Session object for Apple Pay
-    pub session_token_data: ApplePaySessionResponse,
+    /// The session_token_data will be null for iOS devices because the Apple Pay session call is skipped, as there is no web domain involved
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub session_token_data: Option<ApplePaySessionResponse>,
     /// Payment request object for Apple Pay
     pub payment_request_data: Option<ApplePayPaymentRequest>,
     /// The session token is w.r.t this connector
diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs
index c3aa895e1ce..5ee0bae6d61 100644
--- a/crates/common_enums/src/enums.rs
+++ b/crates/common_enums/src/enums.rs
@@ -2258,6 +2258,24 @@ pub enum PaymentSource {
     ExternalAuthenticator,
 }
 
+#[derive(Default, Debug, Clone, serde::Deserialize, serde::Serialize, strum::EnumString)]
+pub enum BrowserName {
+    #[default]
+    Safari,
+    #[serde(other)]
+    Unknown,
+}
+
+#[derive(Default, Debug, Clone, serde::Deserialize, serde::Serialize, strum::EnumString)]
+#[strum(serialize_all = "snake_case")]
+pub enum ClientPlatform {
+    #[default]
+    Web,
+    Ios,
+    #[serde(other)]
+    Unknown,
+}
+
 impl PaymentSource {
     pub fn is_for_internal_use_only(&self) -> bool {
         match self {
diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs
index 0c24fba34cf..a259559c51d 100644
--- a/crates/openapi/src/openapi.rs
+++ b/crates/openapi/src/openapi.rs
@@ -317,6 +317,7 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::ApplepayConnectorMetadataRequest,
         api_models::payments::SessionTokenInfo,
         api_models::payments::PaymentProcessingDetailsAt,
+        api_models::payments::ApplepayInitiative,
         api_models::payments::PaymentProcessingDetails,
         api_models::payments::PaymentMethodDataResponseWithBilling,
         api_models::payments::PaymentMethodDataResponse,
diff --git a/crates/router/src/connector/bluesnap/transformers.rs b/crates/router/src/connector/bluesnap/transformers.rs
index 909e8120c6e..fbc7c661e4c 100644
--- a/crates/router/src/connector/bluesnap/transformers.rs
+++ b/crates/router/src/connector/bluesnap/transformers.rs
@@ -461,10 +461,16 @@ impl TryFrom<&types::PaymentsSessionRouterData> for BluesnapCreateWalletToken {
                 })
             }
         }?;
+        let domain_name = session_token_data.initiative_context.ok_or(
+            errors::ConnectorError::MissingRequiredField {
+                field_name: "apple pay initiative_context",
+            },
+        )?;
+
         Ok(Self {
             wallet_type: "APPLE_PAY".to_string(),
             validation_url: consts::APPLEPAY_VALIDATION_URL.to_string().into(),
-            domain_name: session_token_data.initiative_context,
+            domain_name,
             display_name: Some(session_token_data.display_name),
         })
     }
@@ -529,8 +535,8 @@ impl
             response: Ok(types::PaymentsResponseData::SessionResponse {
                 session_token: api::SessionToken::ApplePay(Box::new(
                     payments::ApplepaySessionTokenResponse {
-                        session_token_data: payments::ApplePaySessionResponse::NoThirdPartySdk(
-                            session_response,
+                        session_token_data: Some(
+                            payments::ApplePaySessionResponse::NoThirdPartySdk(session_response),
                         ),
                         payment_request_data: Some(payments::ApplePayPaymentRequest {
                             country_code: item.data.get_billing_country()?,
diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs
index 5cb025816d6..47942d7de43 100644
--- a/crates/router/src/connector/payme/transformers.rs
+++ b/crates/router/src/connector/payme/transformers.rs
@@ -553,8 +553,9 @@ impl<F>
                         _,
                     ))) => Some(api_models::payments::SessionToken::ApplePay(Box::new(
                         api_models::payments::ApplepaySessionTokenResponse {
-                            session_token_data:
+                            session_token_data: Some(
                                 api_models::payments::ApplePaySessionResponse::NoSessionResponse,
+                            ),
                             payment_request_data: Some(
                                 api_models::payments::ApplePayPaymentRequest {
                                     country_code: item.data.get_billing_country()?,
diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs
index b48c52c76ff..77d85393d29 100644
--- a/crates/router/src/connector/trustpay/transformers.rs
+++ b/crates/router/src/connector/trustpay/transformers.rs
@@ -1209,12 +1209,13 @@ pub fn get_apple_pay_session<F, T>(
             pre_processing_id: types::PreprocessingResponseId::ConnectorTransactionId(instance_id),
             session_token: Some(types::api::SessionToken::ApplePay(Box::new(
                 api_models::payments::ApplepaySessionTokenResponse {
-                    session_token_data:
+                    session_token_data: Some(
                         api_models::payments::ApplePaySessionResponse::ThirdPartySdk(
                             api_models::payments::ThirdPartySdkSessionResponse {
                                 secrets: secrets.to_owned().into(),
                             },
                         ),
+                    ),
                     payment_request_data: Some(api_models::payments::ApplePayPaymentRequest {
                         country_code: apple_pay_init_result.country_code,
                         currency_code: apple_pay_init_result.currency_code,
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 459ada8fb4f..8290177f21b 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -461,6 +461,7 @@ where
                         &customer,
                         session_surcharge_details,
                         &business_profile,
+                        header_payload.clone(),
                     ))
                     .await?
                 }
@@ -1610,6 +1611,7 @@ where
                 call_connector_action,
                 connector_request,
                 business_profile,
+                header_payload.clone(),
             )
             .await
     } else {
@@ -1673,6 +1675,7 @@ pub async fn call_multiple_connectors_service<F, Op, Req>(
     customer: &Option<domain::Customer>,
     session_surcharge_details: Option<api::SessionSurchargeDetails>,
     business_profile: &storage::business_profile::BusinessProfile,
+    header_payload: HeaderPayload,
 ) -> RouterResult<PaymentData<F>>
 where
     Op: Debug,
@@ -1736,6 +1739,7 @@ where
             CallConnectorAction::Trigger,
             None,
             business_profile,
+            header_payload.clone(),
         );
 
         join_handlers.push(res);
diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs
index f4609465200..aa5be3924a9 100644
--- a/crates/router/src/core/payments/flows.rs
+++ b/crates/router/src/core/payments/flows.rs
@@ -47,6 +47,7 @@ pub trait Feature<F, T> {
         call_connector_action: payments::CallConnectorAction,
         connector_request: Option<services::Request>,
         business_profile: &storage::business_profile::BusinessProfile,
+        header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self>
     where
         Self: Sized,
diff --git a/crates/router/src/core/payments/flows/approve_flow.rs b/crates/router/src/core/payments/flows/approve_flow.rs
index f15274ba5be..f4f8409912e 100644
--- a/crates/router/src/core/payments/flows/approve_flow.rs
+++ b/crates/router/src/core/payments/flows/approve_flow.rs
@@ -52,6 +52,7 @@ impl Feature<api::Approve, types::PaymentsApproveData>
         _call_connector_action: payments::CallConnectorAction,
         _connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         Err(ApiErrorResponse::NotImplemented {
             message: NotImplementedMessage::Reason("Flow not supported".to_string()),
diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs
index 5909b0841fb..23971f3696c 100644
--- a/crates/router/src/core/payments/flows/authorize_flow.rs
+++ b/crates/router/src/core/payments/flows/authorize_flow.rs
@@ -65,6 +65,7 @@ impl Feature<api::Authorize, types::PaymentsAuthorizeData> for types::PaymentsAu
         call_connector_action: payments::CallConnectorAction,
         connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
             api::Authorize,
diff --git a/crates/router/src/core/payments/flows/cancel_flow.rs b/crates/router/src/core/payments/flows/cancel_flow.rs
index 0914bd0e901..d61730117a8 100644
--- a/crates/router/src/core/payments/flows/cancel_flow.rs
+++ b/crates/router/src/core/payments/flows/cancel_flow.rs
@@ -52,6 +52,7 @@ impl Feature<api::Void, types::PaymentsCancelData>
         call_connector_action: payments::CallConnectorAction,
         connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         metrics::PAYMENT_CANCEL_COUNT.add(
             &metrics::CONTEXT,
diff --git a/crates/router/src/core/payments/flows/capture_flow.rs b/crates/router/src/core/payments/flows/capture_flow.rs
index a2c2abe7d8a..3e098043544 100644
--- a/crates/router/src/core/payments/flows/capture_flow.rs
+++ b/crates/router/src/core/payments/flows/capture_flow.rs
@@ -52,6 +52,7 @@ impl Feature<api::Capture, types::PaymentsCaptureData>
         call_connector_action: payments::CallConnectorAction,
         connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
             api::Capture,
diff --git a/crates/router/src/core/payments/flows/complete_authorize_flow.rs b/crates/router/src/core/payments/flows/complete_authorize_flow.rs
index e735278609b..bb56cb5a7c5 100644
--- a/crates/router/src/core/payments/flows/complete_authorize_flow.rs
+++ b/crates/router/src/core/payments/flows/complete_authorize_flow.rs
@@ -66,6 +66,7 @@ impl Feature<api::CompleteAuthorize, types::CompleteAuthorizeData>
         call_connector_action: payments::CallConnectorAction,
         connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
             api::CompleteAuthorize,
diff --git a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs
index 673bb8a1ace..2aa808f9532 100644
--- a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs
+++ b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs
@@ -59,6 +59,7 @@ impl Feature<api::IncrementalAuthorization, types::PaymentsIncrementalAuthorizat
         call_connector_action: payments::CallConnectorAction,
         connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
             api::IncrementalAuthorization,
diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs
index eae1d8cfd7f..5b0d1a48e67 100644
--- a/crates/router/src/core/payments/flows/psync_flow.rs
+++ b/crates/router/src/core/payments/flows/psync_flow.rs
@@ -55,6 +55,7 @@ impl Feature<api::PSync, types::PaymentsSyncData>
         call_connector_action: payments::CallConnectorAction,
         connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
             api::PSync,
diff --git a/crates/router/src/core/payments/flows/reject_flow.rs b/crates/router/src/core/payments/flows/reject_flow.rs
index 020e6ff101d..cb1dcd5b19f 100644
--- a/crates/router/src/core/payments/flows/reject_flow.rs
+++ b/crates/router/src/core/payments/flows/reject_flow.rs
@@ -51,6 +51,7 @@ impl Feature<api::Reject, types::PaymentsRejectData>
         _call_connector_action: payments::CallConnectorAction,
         _connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         Err(ApiErrorResponse::NotImplemented {
             message: NotImplementedMessage::Reason("Flow not supported".to_string()),
diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs
index 0774f0a8593..1223d861ebd 100644
--- a/crates/router/src/core/payments/flows/session_flow.rs
+++ b/crates/router/src/core/payments/flows/session_flow.rs
@@ -65,6 +65,7 @@ impl Feature<api::Session, types::PaymentsSessionData> for types::PaymentsSessio
         call_connector_action: payments::CallConnectorAction,
         _connector_request: Option<services::Request>,
         business_profile: &storage::business_profile::BusinessProfile,
+        header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         metrics::SESSION_TOKEN_CREATED.add(
             &metrics::CONTEXT,
@@ -77,6 +78,7 @@ impl Feature<api::Session, types::PaymentsSessionData> for types::PaymentsSessio
             Some(true),
             call_connector_action,
             business_profile,
+            header_payload,
         )
         .await
     }
@@ -155,6 +157,7 @@ async fn create_applepay_session_token(
     router_data: &types::PaymentsSessionRouterData,
     connector: &api::ConnectorData,
     business_profile: &storage::business_profile::BusinessProfile,
+    header_payload: api_models::payments::HeaderPayload,
 ) -> RouterResult<types::PaymentsSessionRouterData> {
     let delayed_response = is_session_response_delayed(state, connector);
     if delayed_response {
@@ -188,9 +191,10 @@ async fn create_applepay_session_token(
         // Get payment request data , apple pay session request and merchant keys
         let (
             payment_request_data,
-            apple_pay_session_request,
+            apple_pay_session_request_optional,
             apple_pay_merchant_cert,
             apple_pay_merchant_cert_key,
+            apple_pay_merchant_identifier,
             merchant_business_country,
         ) = match apple_pay_metadata {
             payment_types::ApplepaySessionTokenMetadata::ApplePayCombined(
@@ -213,7 +217,7 @@ async fn create_applepay_session_token(
                     let merchant_business_country = session_token_data.merchant_business_country;
 
                     let apple_pay_session_request = get_session_request_for_simplified_apple_pay(
-                        merchant_identifier,
+                        merchant_identifier.clone(),
                         session_token_data,
                     );
 
@@ -233,9 +237,10 @@ async fn create_applepay_session_token(
 
                     (
                         payment_request_data,
-                        apple_pay_session_request,
+                        Ok(apple_pay_session_request),
                         apple_pay_merchant_cert,
                         apple_pay_merchant_cert_key,
+                        merchant_identifier,
                         merchant_business_country,
                     )
                 }
@@ -255,6 +260,7 @@ async fn create_applepay_session_token(
                         apple_pay_session_request,
                         session_token_data.certificate.clone(),
                         session_token_data.certificate_keys,
+                        session_token_data.merchant_identifier,
                         merchant_business_country,
                     )
                 }
@@ -273,7 +279,11 @@ async fn create_applepay_session_token(
                     apple_pay_metadata.payment_request_data,
                     apple_pay_session_request,
                     apple_pay_metadata.session_token_data.certificate.clone(),
-                    apple_pay_metadata.session_token_data.certificate_keys,
+                    apple_pay_metadata
+                        .session_token_data
+                        .certificate_keys
+                        .clone(),
+                    apple_pay_metadata.session_token_data.merchant_identifier,
                     merchant_business_country,
                 )
             }
@@ -323,48 +333,63 @@ async fn create_applepay_session_token(
             amount_info,
             payment_request_data,
             router_data.request.to_owned(),
-            apple_pay_session_request.merchant_identifier.as_str(),
+            apple_pay_merchant_identifier.as_str(),
             merchant_business_country,
             required_billing_contact_fields,
             required_shipping_contact_fields,
         )?;
 
-        let applepay_session_request = build_apple_pay_session_request(
-            state,
-            apple_pay_session_request,
-            apple_pay_merchant_cert,
-            apple_pay_merchant_cert_key,
-        )?;
-        let response = services::call_connector_api(
-            state,
-            applepay_session_request,
-            "create_apple_pay_session_token",
-        )
-        .await;
-
-        // logging the error if present in session call response
-        log_session_response_if_error(&response);
-
-        let apple_pay_session_response = response
-            .ok()
-            .and_then(|apple_pay_res| {
-                apple_pay_res
-                    .map(|res| {
-                        let response: Result<
-                            payment_types::NoThirdPartySdkSessionResponse,
-                            Report<common_utils::errors::ParsingError>,
-                        > = res.response.parse_struct("NoThirdPartySdkSessionResponse");
-
-                        // logging the parsing failed error
-                        if let Err(error) = response.as_ref() {
-                            logger::error!(?error);
-                        };
-
-                        response.ok()
-                    })
+        let apple_pay_session_response = match (
+            header_payload.browser_name,
+            header_payload.x_client_platform,
+        ) {
+            (Some(common_enums::BrowserName::Safari), Some(common_enums::ClientPlatform::Web))
+            | (None, None) => {
+                let apple_pay_session_request = apple_pay_session_request_optional
+                    .attach_printable("Failed to obtain apple pay session request")?;
+                let applepay_session_request = build_apple_pay_session_request(
+                    state,
+                    apple_pay_session_request,
+                    apple_pay_merchant_cert,
+                    apple_pay_merchant_cert_key,
+                )?;
+
+                let response = services::call_connector_api(
+                    state,
+                    applepay_session_request,
+                    "create_apple_pay_session_token",
+                )
+                .await;
+
+                // logging the error if present in session call response
+                log_session_response_if_error(&response);
+
+                response
                     .ok()
-            })
-            .flatten();
+                    .and_then(|apple_pay_res| {
+                        apple_pay_res
+                            .map(|res| {
+                                let response: Result<
+                                    payment_types::NoThirdPartySdkSessionResponse,
+                                    Report<common_utils::errors::ParsingError>,
+                                > = res.response.parse_struct("NoThirdPartySdkSessionResponse");
+
+                                // logging the parsing failed error
+                                if let Err(error) = response.as_ref() {
+                                    logger::error!(?error);
+                                };
+
+                                response.ok()
+                            })
+                            .ok()
+                    })
+                    .flatten()
+            }
+            _ => {
+                logger::debug!("Skipping apple pay session call based on the browser name");
+                None
+            }
+        };
 
         let session_response =
             apple_pay_session_response.map(payment_types::ApplePaySessionResponse::NoThirdPartySdk);
@@ -394,13 +419,17 @@ fn get_session_request_for_simplified_apple_pay(
 
 fn get_session_request_for_manual_apple_pay(
     session_token_data: payment_types::SessionTokenInfo,
-) -> payment_types::ApplepaySessionRequest {
-    payment_types::ApplepaySessionRequest {
+) -> RouterResult<payment_types::ApplepaySessionRequest> {
+    let initiative_context = session_token_data
+        .initiative_context
+        .ok_or(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to get initiative_context for apple pay session call")?;
+    Ok(payment_types::ApplepaySessionRequest {
         merchant_identifier: session_token_data.merchant_identifier.clone(),
         display_name: session_token_data.display_name.clone(),
-        initiative: session_token_data.initiative.clone(),
-        initiative_context: session_token_data.initiative_context,
-    }
+        initiative: session_token_data.initiative.to_string(),
+        initiative_context,
+    })
 }
 
 fn get_apple_pay_amount_info(
@@ -461,7 +490,7 @@ fn create_apple_pay_session_response(
             response: Ok(types::PaymentsResponseData::SessionResponse {
                 session_token: payment_types::SessionToken::ApplePay(Box::new(
                     payment_types::ApplepaySessionTokenResponse {
-                        session_token_data: response,
+                        session_token_data: Some(response),
                         payment_request_data: apple_pay_payment_request,
                         connector: connector_name,
                         delayed_session_token: delayed_response,
@@ -476,7 +505,18 @@ fn create_apple_pay_session_response(
         }),
         None => Ok(types::PaymentsSessionRouterData {
             response: Ok(types::PaymentsResponseData::SessionResponse {
-                session_token: payment_types::SessionToken::NoSessionTokenReceived,
+                session_token: payment_types::SessionToken::ApplePay(Box::new(
+                    payment_types::ApplepaySessionTokenResponse {
+                        session_token_data: None,
+                        payment_request_data: apple_pay_payment_request,
+                        connector: connector_name,
+                        delayed_session_token: delayed_response,
+                        sdk_next_action: { payment_types::SdkNextAction { next_action } },
+                        connector_reference_id: None,
+                        connector_sdk_public_key: None,
+                        connector_merchant_id: None,
+                    },
+                )),
             }),
             ..router_data.clone()
         }),
@@ -650,6 +690,7 @@ where
         _confirm: Option<bool>,
         call_connector_action: payments::CallConnectorAction,
         business_profile: &storage::business_profile::BusinessProfile,
+        header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self>;
 }
 
@@ -698,13 +739,21 @@ impl RouterDataSession for types::PaymentsSessionRouterData {
         _confirm: Option<bool>,
         call_connector_action: payments::CallConnectorAction,
         business_profile: &storage::business_profile::BusinessProfile,
+        header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         match connector.get_token {
             api::GetToken::GpayMetadata => {
                 create_gpay_session_token(state, self, connector, business_profile)
             }
             api::GetToken::ApplePayMetadata => {
-                create_applepay_session_token(state, self, connector, business_profile).await
+                create_applepay_session_token(
+                    state,
+                    self,
+                    connector,
+                    business_profile,
+                    header_payload,
+                )
+                .await
             }
             api::GetToken::PaypalSdkMetadata => {
                 create_paypal_sdk_session_token(state, self, connector, business_profile)
diff --git a/crates/router/src/core/payments/flows/setup_mandate_flow.rs b/crates/router/src/core/payments/flows/setup_mandate_flow.rs
index 7a876779033..07803a0c0fb 100644
--- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs
+++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs
@@ -57,6 +57,7 @@ impl Feature<api::SetupMandate, types::SetupMandateRequestData> for types::Setup
         call_connector_action: payments::CallConnectorAction,
         connector_request: Option<services::Request>,
         _business_profile: &storage::business_profile::BusinessProfile,
+        _header_payload: api_models::payments::HeaderPayload,
     ) -> RouterResult<Self> {
         let connector_integration: services::BoxedPaymentConnectorIntegrationInterface<
             api::SetupMandate,
diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs
index c543be8cc92..f0d332514d1 100644
--- a/crates/router/src/lib.rs
+++ b/crates/router/src/lib.rs
@@ -77,6 +77,8 @@ pub mod headers {
     pub const X_CLIENT_SOURCE: &str = "X-Client-Source";
     pub const X_PAYMENT_CONFIRM_SOURCE: &str = "X-Payment-Confirm-Source";
     pub const CONTENT_LENGTH: &str = "Content-Length";
+    pub const BROWSER_NAME: &str = "browsername";
+    pub const X_CLIENT_PLATFORM: &str = "x-client-platform";
 }
 
 pub mod pii {
diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs
index 912421f4650..84c7986dd8a 100644
--- a/crates/router/src/routes/payments.rs
+++ b/crates/router/src/routes/payments.rs
@@ -8,7 +8,7 @@ use actix_web::{web, Responder};
 use api_models::payments::HeaderPayload;
 use error_stack::report;
 use masking::PeekInterface;
-use router_env::{env, instrument, tracing, types, Flow};
+use router_env::{env, instrument, logger, tracing, types, Flow};
 
 use super::app::ReqState;
 use crate::{
@@ -593,6 +593,14 @@ pub async fn payments_connector_session(
     let flow = Flow::PaymentsSessionToken;
     let payload = json_payload.into_inner();
 
+    let header_payload = match HeaderPayload::foreign_try_from(req.headers()) {
+        Ok(headers) => headers,
+        Err(err) => {
+            logger::error!(?err, "Failed to get headers in payments_connector_session");
+            HeaderPayload::default()
+        }
+    };
+
     tracing::Span::current().record("payment_id", &payload.payment_id);
 
     let locking_action = payload.get_locking_input(flow.clone());
@@ -619,7 +627,7 @@ pub async fn payments_connector_session(
                 api::AuthFlow::Client,
                 payments::CallConnectorAction::Trigger,
                 None,
-                HeaderPayload::default(),
+                header_payload.clone(),
             )
         },
         &auth::PublishableKeyAuth,
diff --git a/crates/router/src/types/transformers.rs b/crates/router/src/types/transformers.rs
index f754b31e0b0..57fc613af77 100644
--- a/crates/router/src/types/transformers.rs
+++ b/crates/router/src/types/transformers.rs
@@ -19,7 +19,10 @@ use masking::{ExposeInterface, PeekInterface};
 use super::domain;
 use crate::{
     core::errors,
-    headers::{X_CLIENT_SOURCE, X_CLIENT_VERSION, X_PAYMENT_CONFIRM_SOURCE},
+    headers::{
+        BROWSER_NAME, X_CLIENT_PLATFORM, X_CLIENT_SOURCE, X_CLIENT_VERSION,
+        X_PAYMENT_CONFIRM_SOURCE,
+    },
     services::authentication::get_header_value_by_key,
     types::{
         api::{self as api_types, routing as routing_types},
@@ -1106,11 +1109,32 @@ impl ForeignTryFrom<&HeaderMap> for payments::HeaderPayload {
         let client_version =
             get_header_value_by_key(X_CLIENT_VERSION.into(), headers)?.map(|val| val.to_string());
 
+        let browser_name_str =
+            get_header_value_by_key(BROWSER_NAME.into(), headers)?.map(|val| val.to_string());
+
+        let browser_name: Option<api_enums::BrowserName> = browser_name_str.map(|browser_name| {
+            browser_name
+                .parse_enum("BrowserName")
+                .unwrap_or(api_enums::BrowserName::Unknown)
+        });
+
+        let x_client_platform_str =
+            get_header_value_by_key(X_CLIENT_PLATFORM.into(), headers)?.map(|val| val.to_string());
+
+        let x_client_platform: Option<api_enums::ClientPlatform> =
+            x_client_platform_str.map(|x_client_platform| {
+                x_client_platform
+                    .parse_enum("ClientPlatform")
+                    .unwrap_or(api_enums::ClientPlatform::Unknown)
+            });
+
         Ok(Self {
             payment_confirm_source,
             client_source,
             client_version,
             x_hs_latency: Some(x_hs_latency),
+            browser_name,
+            x_client_platform,
         })
     }
 }
diff --git a/crates/router/tests/connectors/payme.rs b/crates/router/tests/connectors/payme.rs
index 590ad15d7f6..605f63d0f64 100644
--- a/crates/router/tests/connectors/payme.rs
+++ b/crates/router/tests/connectors/payme.rs
@@ -68,6 +68,7 @@ fn get_default_payment_info() -> Option<utils::PaymentInfo> {
         return_url: None,
         connector_customer: None,
         payment_method_token: None,
+        #[cfg(feature = "payouts")]
         currency: None,
         #[cfg(feature = "payouts")]
         payout_method_data: None,
diff --git a/crates/router/tests/connectors/square.rs b/crates/router/tests/connectors/square.rs
index 322708c1da6..f7b633e8a15 100644
--- a/crates/router/tests/connectors/square.rs
+++ b/crates/router/tests/connectors/square.rs
@@ -47,6 +47,7 @@ fn get_default_payment_info(payment_method_token: Option<String>) -> Option<util
         payment_method_token,
         #[cfg(feature = "payouts")]
         payout_method_data: None,
+        #[cfg(feature = "payouts")]
         currency: None,
     })
 }
diff --git a/crates/router/tests/connectors/stax.rs b/crates/router/tests/connectors/stax.rs
index 573bdd93802..f3d0f06ec1b 100644
--- a/crates/router/tests/connectors/stax.rs
+++ b/crates/router/tests/connectors/stax.rs
@@ -50,6 +50,7 @@ fn get_default_payment_info(
         payment_method_token,
         #[cfg(feature = "payouts")]
         payout_method_data: None,
+        #[cfg(feature = "payouts")]
         currency: None,
     })
 }
diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs
index d1c3f40f388..ea7787a2c21 100644
--- a/crates/router/tests/connectors/utils.rs
+++ b/crates/router/tests/connectors/utils.rs
@@ -68,6 +68,7 @@ pub struct PaymentInfo {
     pub payment_method_token: Option<String>,
     #[cfg(feature = "payouts")]
     pub payout_method_data: Option<types::api::PayoutMethodData>,
+    #[cfg(feature = "payouts")]
     pub currency: Option<enums::Currency>,
 }
 

## 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 -->
Currently, the Apple Pay session call is mandatory in all cases. This requirement also mandates configuring the initiative_context, which is the domain name where the Apple Pay payment is being processed. However, in the case of an iOS app, a domain is not required, so this field can be made optional. Additionally, in this case, the session call to Apple Pay can be skipped.

On the web, Apple Pay is supported only in Safari. Therefore, the session call should be skipped in web environments when the browser is not Safari.

### 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)?
-->
-> Create merchant connector account with apple pay manual flow. Below is the metadata for the manual flow.
```
"session_token_data": {
                    "initiative": "web",
                    "certificate": "==",
                    "display_name": "applepay",
                    "certificate_keys": "",
                    "payment_processing_details_at": "Hyperswitch",
                    "payment_processing_certificate": "",
                    "payment_processing_certificate_key": "",
                    "initiative_context": "sdk-test-app.netlify.app",
                    "merchant_identifier": "",
                    "merchant_business_country": "US"
                }
```
-> Currently we make session call only if `x_client_platform` and `browsername` header None or if it is web and Safari respectively.

-> When mca is configured with write domain and header is not passed
```
curl --location 'http://localhost:8080/payments/session_tokens' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_7e0d9f48e20b430baa86eb956dc99142' \
--data '{
    "payment_id": "pay_7WAejcRN248R0Y7Kwsfh",
    "wallets": [],
    "client_secret": "pay_7WAejcRN248R0Y7Kwsfh_secret_CDL03LbGwQQnMPVA0Lq0"
}'
```
<img width="1135" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/2b02346c-0013-432b-be1e-72fd4769f4a4">

-> When mca is configured with write domain and header is passed as 
```
curl --location 'http://localhost:8080/payments/session_tokens' \
--header 'Content-Type: application/json' \
--header 'browsername: Safari' \
--header 'x_client_platform: web' \
--header 'api-key: pk_dev_7e0d9f48e20b430baa86eb956dc99142' \
--data '{
    "payment_id": "pay_7WAejcRN248R0Y7Kwsfh",
    "wallets": [],
    "client_secret": "pay_7WAejcRN248R0Y7Kwsfh_secret_CDL03LbGwQQnMPVA0Lq0"
}'
```
<img width="1140" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/e041b783-034a-46ca-a7f3-8c2c0ea03f07">

-> mac with write domain and wrong value in header
```
curl --location 'http://localhost:8080/payments/session_tokens' \
--header 'Content-Type: application/json' \
--header 'browsername: aa' \
--header 'x-client-platform: bb' \
--header 'api-key: pk_dev_7e0d9f48e20b430baa86eb956dc99142' \
--data '{
    "payment_id": "pay_oisWpJs0i1gXIpdYMqFp",
    "wallets": [],
    "client_secret": "pay_oisWpJs0i1gXIpdYMqFp_secret_fkzm5bW5WR5wssQxEo3f"
}'
```
<img width="1141" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/ce7416de-ec0b-4e5d-b863-bb62b84f2c36">

-> If only one header is passed
```
curl --location 'http://localhost:8080/payments/session_tokens' \
--header 'Content-Type: application/json' \
--header 'x-client-platform: ios' \
--header 'api-key: pk_dev_7e0d9f48e20b430baa86eb956dc99142' \
--data '{
    "payment_id": "pay_oisWpJs0i1gXIpdYMqFp",
    "wallets": [],
    "client_secret": "pay_oisWpJs0i1gXIpdYMqFp_secret_fkzm5bW5WR5wssQxEo3f"
}'
```
<img width="1145" alt="image" src="https://github.com/juspay/hyperswitch/assets/83439957/babba52d-0ee2-4b5f-a989-ca4a7317c7d1">


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

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