Issue:
Bug: [FEATURE] Inclusion of Customer_ip field for PaymentConfirm flows



### Feature Description

Need to derive Ip_addr of the customer from the headers(x-forwarded-for) to the request.

### Possible Implementation

Creation of customer_ip field in PaymentData and then lower the stuffs down to the PaymentConfirm.

### Have you spent some time to check if this feature request has been raised before?

- [X] I checked and didn't find similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes I am willing to submit a PR!

Pull request description:
## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [x] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
Addition of customer_ip field to be taken from either x-forwarded-for or from request itself.


### 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
Will help Sdk team for minimizing latency as currently they are using 3rd party service for requesting the Ip addr.


## How did you test it?
Tested it manually


## 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 submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable


Testing:
Tested it manually

Patch:
diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs
index ffd4a57db57..e57e13167d8 100644
--- a/crates/router/src/connector/adyen/transformers.rs
+++ b/crates/router/src/connector/adyen/transformers.rs
@@ -1,5 +1,6 @@
 use api_models::{enums, payments, webhooks};
 use cards::CardNumber;
+use error_stack::ResultExt;
 use masking::PeekInterface;
 use reqwest::Url;
 use serde::{Deserialize, Serialize};
@@ -19,6 +20,7 @@ use crate::{
         storage::enums as storage_enums,
         transformers::ForeignFrom,
     },
+    utils::OptionExt,
 };
 
 type Error = error_stack::Report<errors::ConnectorError>;
@@ -839,25 +841,73 @@ fn get_recurring_processing_model(
     }
 }
 
-fn get_browser_info(item: &types::PaymentsAuthorizeRouterData) -> Option<AdyenBrowserInfo> {
+fn get_browser_info(
+    item: &types::PaymentsAuthorizeRouterData,
+) -> Result<Option<AdyenBrowserInfo>, Error> {
     if item.auth_type == storage_enums::AuthenticationType::ThreeDs
         || item.payment_method == storage_enums::PaymentMethod::BankRedirect
     {
         item.request
             .browser_info
             .as_ref()
-            .map(|info| AdyenBrowserInfo {
-                accept_header: info.accept_header.clone(),
-                language: info.language.clone(),
-                screen_height: info.screen_height,
-                screen_width: info.screen_width,
-                color_depth: info.color_depth,
-                user_agent: info.user_agent.clone(),
-                time_zone_offset: info.time_zone,
-                java_enabled: info.java_enabled,
+            .map(|info| {
+                Ok(AdyenBrowserInfo {
+                    accept_header: info
+                        .accept_header
+                        .clone()
+                        .get_required_value("accept_header")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "accept_header",
+                        })?,
+                    language: info
+                        .language
+                        .clone()
+                        .get_required_value("language")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "language",
+                        })?,
+                    screen_height: info
+                        .screen_height
+                        .get_required_value("screen_height")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "screen_height",
+                        })?,
+                    screen_width: info
+                        .screen_width
+                        .get_required_value("screen_width")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "screen_width",
+                        })?,
+                    color_depth: info
+                        .color_depth
+                        .get_required_value("color_depth")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "color_depth",
+                        })?,
+                    user_agent: info
+                        .user_agent
+                        .clone()
+                        .get_required_value("user_agent")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "user_agent",
+                        })?,
+                    time_zone_offset: info
+                        .time_zone
+                        .get_required_value("time_zone_offset")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "time_zone_offset",
+                        })?,
+                    java_enabled: info
+                        .java_enabled
+                        .get_required_value("java_enabled")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "java_enabled",
+                        })?,
+                })
             })
+            .transpose()
     } else {
-        None
+        Ok(None)
     }
 }
 
@@ -1246,7 +1296,7 @@ impl<'a>
         let shopper_interaction = AdyenShopperInteraction::from(item);
         let (recurring_processing_model, store_payment_method, shopper_reference) =
             get_recurring_processing_model(item)?;
-        let browser_info = get_browser_info(item);
+        let browser_info = get_browser_info(item)?;
         let additional_data = get_additional_data(item);
         let return_url = item.request.get_return_url()?;
         let payment_method = match mandate_ref_id {
@@ -1318,7 +1368,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::Card)> for AdyenPay
         let shopper_interaction = AdyenShopperInteraction::from(item);
         let (recurring_processing_model, store_payment_method, shopper_reference) =
             get_recurring_processing_model(item)?;
-        let browser_info = get_browser_info(item);
+        let browser_info = get_browser_info(item)?;
         let additional_data = get_additional_data(item);
         let return_url = item.request.get_return_url()?;
         let payment_method = AdyenPaymentMethod::try_from(card_data)?;
@@ -1365,7 +1415,7 @@ impl<'a>
         let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
         let shopper_interaction = AdyenShopperInteraction::from(item);
         let recurring_processing_model = get_recurring_processing_model(item)?.0;
-        let browser_info = get_browser_info(item);
+        let browser_info = get_browser_info(item)?;
         let additional_data = get_additional_data(item);
         let return_url = item.request.get_return_url()?;
         let payment_method = AdyenPaymentMethod::try_from(bank_debit_data)?;
@@ -1414,7 +1464,7 @@ impl<'a>
         let shopper_interaction = AdyenShopperInteraction::from(item);
         let (recurring_processing_model, store_payment_method, shopper_reference) =
             get_recurring_processing_model(item)?;
-        let browser_info = get_browser_info(item);
+        let browser_info = get_browser_info(item)?;
         let additional_data = get_additional_data(item);
         let return_url = item.request.get_return_url()?;
         let payment_method = AdyenPaymentMethod::try_from(bank_redirect_data)?;
@@ -1478,7 +1528,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::WalletData)>
         let (item, wallet_data) = value;
         let amount = get_amount_data(item);
         let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
-        let browser_info = get_browser_info(item);
+        let browser_info = get_browser_info(item)?;
         let additional_data = get_additional_data(item);
         let payment_method = AdyenPaymentMethod::try_from(wallet_data)?;
         let shopper_interaction = AdyenShopperInteraction::from(item);
@@ -1519,7 +1569,7 @@ impl<'a> TryFrom<(&types::PaymentsAuthorizeRouterData, &api::PayLaterData)>
         let (item, paylater_data) = value;
         let amount = get_amount_data(item);
         let auth_type = AdyenAuthType::try_from(&item.connector_auth_type)?;
-        let browser_info = get_browser_info(item);
+        let browser_info = get_browser_info(item)?;
         let additional_data = get_additional_data(item);
         let payment_method = AdyenPaymentMethod::try_from(paylater_data)?;
         let shopper_interaction = AdyenShopperInteraction::from(item);
diff --git a/crates/router/src/connector/bambora/transformers.rs b/crates/router/src/connector/bambora/transformers.rs
index e3b02b995b2..7417d0459d1 100644
--- a/crates/router/src/connector/bambora/transformers.rs
+++ b/crates/router/src/connector/bambora/transformers.rs
@@ -10,6 +10,7 @@ use crate::{
     core::errors,
     services,
     types::{self, api, storage::enums},
+    utils::OptionExt,
 };
 
 #[derive(Default, Debug, Serialize, Eq, PartialEq)]
@@ -55,24 +56,77 @@ pub struct BamboraPaymentsRequest {
     card: BamboraCard,
 }
 
-fn get_browser_info(item: &types::PaymentsAuthorizeRouterData) -> Option<BamboraBrowserInfo> {
+fn get_browser_info(
+    item: &types::PaymentsAuthorizeRouterData,
+) -> Result<Option<BamboraBrowserInfo>, error_stack::Report<errors::ConnectorError>> {
     if matches!(item.auth_type, enums::AuthenticationType::ThreeDs) {
         item.request
             .browser_info
             .as_ref()
-            .map(|info| BamboraBrowserInfo {
-                accept_header: info.accept_header.clone(),
-                java_enabled: info.java_enabled,
-                language: info.language.clone(),
-                color_depth: info.color_depth,
-                screen_height: info.screen_height,
-                screen_width: info.screen_width,
-                time_zone: info.time_zone,
-                user_agent: info.user_agent.clone(),
-                javascript_enabled: info.java_script_enabled,
+            .map(|info| {
+                Ok(BamboraBrowserInfo {
+                    accept_header: info
+                        .accept_header
+                        .clone()
+                        .get_required_value("accept_header")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "accept_header",
+                        })?,
+                    java_enabled: info
+                        .java_enabled
+                        .get_required_value("java_enabled")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "java_enabled",
+                        })?,
+                    language: info
+                        .language
+                        .clone()
+                        .get_required_value("language")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "language",
+                        })?,
+                    screen_height: info
+                        .screen_height
+                        .get_required_value("screen_height")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "screen_height",
+                        })?,
+                    screen_width: info
+                        .screen_width
+                        .get_required_value("screen_width")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "screen_width",
+                        })?,
+                    color_depth: info
+                        .color_depth
+                        .get_required_value("color_depth")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "color_depth",
+                        })?,
+                    user_agent: info
+                        .user_agent
+                        .clone()
+                        .get_required_value("user_agent")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "user_agent",
+                        })?,
+                    time_zone: info
+                        .time_zone
+                        .get_required_value("time_zone")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "time_zone",
+                        })?,
+                    javascript_enabled: info
+                        .java_script_enabled
+                        .get_required_value("javascript_enabled")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "javascript_enabled",
+                        })?,
+                })
             })
+            .transpose()
     } else {
-        None
+        Ok(None)
     }
 }
 
@@ -104,7 +158,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for BamboraPaymentsRequest {
                 let three_ds = match item.auth_type {
                     enums::AuthenticationType::ThreeDs => Some(ThreeDSecure {
                         enabled: true,
-                        browser: get_browser_info(item),
+                        browser: get_browser_info(item)?,
                         version: Some(2),
                         auth_required: Some(true),
                     }),
diff --git a/crates/router/src/connector/nuvei/transformers.rs b/crates/router/src/connector/nuvei/transformers.rs
index 35ff9833ba3..232d7bdaf3d 100644
--- a/crates/router/src/connector/nuvei/transformers.rs
+++ b/crates/router/src/connector/nuvei/transformers.rs
@@ -760,19 +760,72 @@ fn get_card_info<F>(
         let three_d = if item.is_three_ds() {
             Some(ThreeD {
                 browser_details: Some(BrowserDetails {
-                    accept_header: browser_info.accept_header,
-                    ip: browser_info.ip_address,
-                    java_enabled: browser_info.java_enabled.to_string().to_uppercase(),
+                    accept_header: browser_info
+                        .accept_header
+                        .get_required_value("accept_header")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "accept_header",
+                        })?,
+                    ip: Some(
+                        browser_info
+                            .ip_address
+                            .get_required_value("ip_address")
+                            .change_context(errors::ConnectorError::MissingRequiredField {
+                                field_name: "ip_address",
+                            })?,
+                    ),
+                    java_enabled: browser_info
+                        .java_enabled
+                        .get_required_value("java_enabled")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "java_enabled",
+                        })?
+                        .to_string()
+                        .to_uppercase(),
                     java_script_enabled: browser_info
                         .java_script_enabled
+                        .get_required_value("java_script_enabled")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "java_script_enabled",
+                        })?
                         .to_string()
                         .to_uppercase(),
-                    language: browser_info.language,
-                    color_depth: browser_info.color_depth,
-                    screen_height: browser_info.screen_height,
-                    screen_width: browser_info.screen_width,
-                    time_zone: browser_info.time_zone,
-                    user_agent: browser_info.user_agent,
+                    language: browser_info
+                        .language
+                        .get_required_value("language")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "language",
+                        })?,
+                    color_depth: browser_info
+                        .color_depth
+                        .get_required_value("color_depth")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "color_depth",
+                        })?,
+                    screen_height: browser_info
+                        .screen_height
+                        .get_required_value("screen_height")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "screen_height",
+                        })?,
+                    screen_width: browser_info
+                        .screen_width
+                        .get_required_value("screen_width")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "screen_width",
+                        })?,
+                    time_zone: browser_info
+                        .time_zone
+                        .get_required_value("time_zone_offset")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "time_zone_offset",
+                        })?,
+                    user_agent: browser_info
+                        .user_agent
+                        .get_required_value("user_agent")
+                        .change_context(errors::ConnectorError::MissingRequiredField {
+                            field_name: "user_agent",
+                        })?,
                 }),
                 v2_additional_params: additional_params,
                 notification_url: item.request.complete_authorize_url.clone(),
diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs
index 35124b5236d..babe63278e4 100644
--- a/crates/router/src/connector/trustpay/transformers.rs
+++ b/crates/router/src/connector/trustpay/transformers.rs
@@ -15,6 +15,7 @@ use crate::{
     core::errors,
     services,
     types::{self, api, storage::enums, BrowserInformation},
+    utils::OptionExt,
 };
 
 type Error = error_stack::Report<errors::ConnectorError>;
@@ -218,35 +219,91 @@ fn get_card_request_data(
     amount: String,
     ccard: &api_models::payments::Card,
     return_url: String,
-) -> TrustpayPaymentsRequest {
-    TrustpayPaymentsRequest::CardsPaymentRequest(Box::new(PaymentRequestCards {
-        amount,
-        currency: item.request.currency.to_string(),
-        pan: ccard.card_number.clone(),
-        cvv: ccard.card_cvc.clone(),
-        expiry_date: ccard.get_card_expiry_month_year_2_digit_with_delimiter("/".to_owned()),
-        cardholder: ccard.card_holder_name.clone(),
-        reference: item.attempt_id.clone(),
-        redirect_url: return_url,
-        billing_city: params.billing_city,
-        billing_country: params.billing_country,
-        billing_street1: params.billing_street1,
-        billing_postcode: params.billing_postcode,
-        customer_email: item.request.email.clone(),
-        customer_ip_address: browser_info.ip_address,
-        browser_accept_header: browser_info.accept_header.clone(),
-        browser_language: browser_info.language.clone(),
-        browser_screen_height: browser_info.screen_height.clone().to_string(),
-        browser_screen_width: browser_info.screen_width.clone().to_string(),
-        browser_timezone: browser_info.time_zone.clone().to_string(),
-        browser_user_agent: browser_info.user_agent.clone(),
-        browser_java_enabled: browser_info.java_enabled.clone().to_string(),
-        browser_java_script_enabled: browser_info.java_script_enabled.clone().to_string(),
-        browser_screen_color_depth: browser_info.color_depth.clone().to_string(),
-        browser_challenge_window: "1".to_string(),
-        payment_action: None,
-        payment_type: "Plain".to_string(),
-    }))
+) -> Result<TrustpayPaymentsRequest, Error> {
+    Ok(TrustpayPaymentsRequest::CardsPaymentRequest(Box::new(
+        PaymentRequestCards {
+            amount,
+            currency: item.request.currency.to_string(),
+            pan: ccard.card_number.clone(),
+            cvv: ccard.card_cvc.clone(),
+            expiry_date: ccard.get_card_expiry_month_year_2_digit_with_delimiter("/".to_owned()),
+            cardholder: ccard.card_holder_name.clone(),
+            reference: item.attempt_id.clone(),
+            redirect_url: return_url,
+            billing_city: params.billing_city,
+            billing_country: params.billing_country,
+            billing_street1: params.billing_street1,
+            billing_postcode: params.billing_postcode,
+            customer_email: item.request.email.clone(),
+            customer_ip_address: browser_info.ip_address,
+            browser_accept_header: browser_info
+                .accept_header
+                .clone()
+                .get_required_value("accept_header")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "accept_header",
+                })?,
+            browser_language: browser_info
+                .language
+                .clone()
+                .get_required_value("language")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "language",
+                })?,
+            browser_screen_height: browser_info
+                .screen_height
+                .get_required_value("screen_height")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "screen_height",
+                })?
+                .to_string(),
+            browser_screen_width: browser_info
+                .screen_width
+                .get_required_value("screen_width")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "screen_width",
+                })?
+                .to_string(),
+            browser_timezone: browser_info
+                .time_zone
+                .get_required_value("time_zone_offset")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "time_zone_offset",
+                })?
+                .to_string(),
+            browser_user_agent: browser_info
+                .user_agent
+                .clone()
+                .get_required_value("user_agent")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "user_agent",
+                })?,
+            browser_java_enabled: browser_info
+                .java_enabled
+                .get_required_value("java_enabled")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "java_enabled",
+                })?
+                .to_string(),
+            browser_java_script_enabled: browser_info
+                .java_script_enabled
+                .get_required_value("java_script_enabled")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "java_script_enabled",
+                })?
+                .to_string(),
+            browser_screen_color_depth: browser_info
+                .color_depth
+                .get_required_value("color_depth")
+                .change_context(errors::ConnectorError::MissingRequiredField {
+                    field_name: "color_depth",
+                })?
+                .to_string(),
+            browser_challenge_window: "1".to_string(),
+            payment_action: None,
+            payment_type: "Plain".to_string(),
+        },
+    )))
 }
 
 fn get_bank_redirection_request_data(
@@ -284,15 +341,15 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
     type Error = Error;
     fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
         let default_browser_info = BrowserInformation {
-            color_depth: 24,
-            java_enabled: false,
-            java_script_enabled: true,
-            language: "en-US".to_string(),
-            screen_height: 1080,
-            screen_width: 1920,
-            time_zone: 3600,
-            accept_header: "*".to_string(),
-            user_agent: "none".to_string(),
+            color_depth: Some(24),
+            java_enabled: Some(false),
+            java_script_enabled: Some(true),
+            language: Some("en-US".to_string()),
+            screen_height: Some(1080),
+            screen_width: Some(1920),
+            time_zone: Some(3600),
+            accept_header: Some("*".to_string()),
+            user_agent: Some("none".to_string()),
             ip_address: None,
         };
         let browser_info = item
@@ -318,7 +375,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for TrustpayPaymentsRequest {
                 amount,
                 ccard,
                 item.request.get_return_url()?,
-            )),
+            )?),
             api::PaymentMethodData::BankRedirect(ref bank_redirection_data) => {
                 get_bank_redirection_request_data(item, bank_redirection_data, amount, auth)
             }
diff --git a/crates/router/src/connector/zen/transformers.rs b/crates/router/src/connector/zen/transformers.rs
index 9a8055cab86..fb986efa5c2 100644
--- a/crates/router/src/connector/zen/transformers.rs
+++ b/crates/router/src/connector/zen/transformers.rs
@@ -13,11 +13,11 @@ use crate::{
     connector::utils::{
         self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, RouterData,
     },
-    core::errors,
+    core::errors::{self, CustomResult},
     services::{self, Method},
-    types::{self, api, storage::enums, transformers::ForeignTryFrom, BrowserInformation},
+    types::{self, api, storage::enums, transformers::ForeignTryFrom},
+    utils::OptionExt,
 };
-
 // Auth Struct
 pub struct ZenAuthType {
     pub(super) api_key: String,
@@ -345,9 +345,23 @@ fn get_item_object(
 }
 
 fn get_browser_details(
-    browser_info: &BrowserInformation,
-) -> Result<ZenBrowserDetails, error_stack::Report<errors::ConnectorError>> {
-    let window_size = match (browser_info.screen_height, browser_info.screen_width) {
+    browser_info: &types::BrowserInformation,
+) -> CustomResult<ZenBrowserDetails, errors::ConnectorError> {
+    let screen_height = browser_info
+        .screen_height
+        .get_required_value("screen_height")
+        .change_context(errors::ConnectorError::MissingRequiredField {
+            field_name: "screen_height",
+        })?;
+
+    let screen_width = browser_info
+        .screen_width
+        .get_required_value("screen_width")
+        .change_context(errors::ConnectorError::MissingRequiredField {
+            field_name: "screen_width",
+        })?;
+
+    let window_size = match (screen_height, screen_width) {
         (250, 400) => "01",
         (390, 400) => "02",
         (500, 600) => "03",
@@ -355,16 +369,52 @@ fn get_browser_details(
         _ => "05",
     }
     .to_string();
+
     Ok(ZenBrowserDetails {
-        color_depth: browser_info.color_depth.to_string(),
-        java_enabled: browser_info.java_enabled,
-        lang: browser_info.language.clone(),
-        screen_height: browser_info.screen_height.to_string(),
-        screen_width: browser_info.screen_width.to_string(),
-        timezone: browser_info.time_zone.to_string(),
-        accept_header: browser_info.accept_header.clone(),
+        color_depth: browser_info
+            .color_depth
+            .get_required_value("color_depth")
+            .change_context(errors::ConnectorError::MissingRequiredField {
+                field_name: "color_depth",
+            })?
+            .to_string(),
+        java_enabled: browser_info
+            .java_enabled
+            .get_required_value("java_enabled")
+            .change_context(errors::ConnectorError::MissingRequiredField {
+                field_name: "java_enabled",
+            })?,
+        lang: browser_info
+            .language
+            .clone()
+            .get_required_value("language")
+            .change_context(errors::ConnectorError::MissingRequiredField {
+                field_name: "language",
+            })?,
+        screen_height: screen_height.to_string(),
+        screen_width: screen_width.to_string(),
+        timezone: browser_info
+            .time_zone
+            .get_required_value("time_zone")
+            .change_context(errors::ConnectorError::MissingRequiredField {
+                field_name: "time_zone",
+            })?
+            .to_string(),
+        accept_header: browser_info
+            .accept_header
+            .clone()
+            .get_required_value("accept_header")
+            .change_context(errors::ConnectorError::MissingRequiredField {
+                field_name: "accept_header",
+            })?,
+        user_agent: browser_info
+            .user_agent
+            .clone()
+            .get_required_value("user_agent")
+            .change_context(errors::ConnectorError::MissingRequiredField {
+                field_name: "user_agent",
+            })?,
         window_size,
-        user_agent: browser_info.user_agent.clone(),
     })
 }
 
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index c746be71c5c..53469925064 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -9,7 +9,7 @@ pub mod transformers;
 use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant};
 
 use api_models::payments::Metadata;
-use common_utils::pii::Email;
+use common_utils::pii;
 use error_stack::{IntoReport, ResultExt};
 use futures::future::join_all;
 use masking::Secret;
@@ -970,7 +970,7 @@ where
     pub disputes: Vec<storage::Dispute>,
     pub sessions_token: Vec<api::SessionToken>,
     pub card_cvc: Option<Secret<String>>,
-    pub email: Option<Email>,
+    pub email: Option<pii::Email>,
     pub creds_identifier: Option<String>,
     pub pm_token: Option<String>,
     pub connector_customer_id: Option<String>,
@@ -982,7 +982,7 @@ where
 pub struct CustomerDetails {
     pub customer_id: Option<String>,
     pub name: Option<Secret<String, masking::WithType>>,
-    pub email: Option<Email>,
+    pub email: Option<pii::Email>,
     pub phone: Option<Secret<String, masking::WithType>>,
     pub phone_country_code: Option<String>,
 }
diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs
index 380448bab7b..a81a619ceb7 100644
--- a/crates/router/src/lib.rs
+++ b/crates/router/src/lib.rs
@@ -56,6 +56,7 @@ pub mod headers {
     pub const TOKEN: &str = "token";
     pub const X_API_KEY: &str = "X-API-KEY";
     pub const X_API_VERSION: &str = "X-ApiVersion";
+    pub const X_FORWARDED_FOR: &str = "X-Forwarded-For";
     pub const X_MERCHANT_ID: &str = "X-Merchant-Id";
     pub const X_LOGIN: &str = "X-Login";
     pub const X_TRANS_KEY: &str = "X-Trans-Key";
diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs
index 25724a549b8..49935c1488f 100644
--- a/crates/router/src/routes/payments.rs
+++ b/crates/router/src/routes/payments.rs
@@ -1,3 +1,5 @@
+pub mod helpers;
+
 use actix_web::{web, Responder};
 use error_stack::report;
 use router_env::{instrument, tracing, Flow};
@@ -321,6 +323,10 @@ pub async fn payments_confirm(
         return http_not_implemented();
     };
 
+    if let Err(err) = helpers::populate_ip_into_browser_info(&req, &mut payload) {
+        return api::log_and_return_error_response(err);
+    }
+
     let payment_id = path.into_inner();
     payload.payment_id = Some(payment_types::PaymentIdType::PaymentIntentId(payment_id));
     payload.confirm = Some(true);
diff --git a/crates/router/src/routes/payments/helpers.rs b/crates/router/src/routes/payments/helpers.rs
new file mode 100644
index 00000000000..f5a87eee197
--- /dev/null
+++ b/crates/router/src/routes/payments/helpers.rs
@@ -0,0 +1,67 @@
+use error_stack::ResultExt;
+
+use crate::{
+    core::errors::{self, RouterResult},
+    headers, logger,
+    types::{self, api::payments as payment_types},
+    utils::{Encode, ValueExt},
+};
+
+pub fn populate_ip_into_browser_info(
+    req: &actix_web::HttpRequest,
+    payload: &mut payment_types::PaymentsRequest,
+) -> RouterResult<()> {
+    let mut browser_info: types::BrowserInformation = payload
+        .browser_info
+        .clone()
+        .map(|v| v.parse_value("BrowserInformation"))
+        .transpose()
+        .change_context_lazy(|| errors::ApiErrorResponse::InvalidRequestData {
+            message: "invalid format for 'browser_info' provided".to_string(),
+        })?
+        .unwrap_or(types::BrowserInformation {
+            color_depth: None,
+            java_enabled: None,
+            java_script_enabled: None,
+            language: None,
+            screen_height: None,
+            screen_width: None,
+            time_zone: None,
+            accept_header: None,
+            user_agent: None,
+            ip_address: None,
+        });
+
+    browser_info.ip_address = browser_info
+        .ip_address
+        .or_else(|| {
+            // Parse the IP Address from the "X-Forwarded-For" header
+            // This header will contain multiple IP addresses for each ALB hop which has
+            // a comma separated list of IP addresses: 'X.X.X.X, Y.Y.Y.Y, Z.Z.Z.Z'
+            // The first one here will be the client IP which we want to retrieve
+            req.headers()
+                .get(headers::X_FORWARDED_FOR)
+                .map(|val| val.to_str())
+                .transpose()
+                .unwrap_or_else(|e| {
+                    logger::error!(error=?e, message="failed to retrieve ip address from X-Forwarded-For header");
+                    None
+                })
+                .and_then(|ips| ips.split(',').next())
+                .map(|ip| ip.parse())
+                .transpose()
+                .unwrap_or_else(|e| {
+                    logger::error!(error=?e, message="failed to parse ip address from X-Forwarded-For");
+                    None
+                })
+        });
+
+    let encoded = Encode::<types::BrowserInformation>::encode_to_value(&browser_info)
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable(
+            "failed to re-encode browser information to json after setting ip address",
+        )?;
+
+    payload.browser_info = Some(encoded);
+    Ok(())
+}
diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs
index cb9647a291d..6cbe85f52f7 100644
--- a/crates/router/src/types.rs
+++ b/crates/router/src/types.rs
@@ -444,16 +444,16 @@ pub struct RefundsData {
 
 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 pub struct BrowserInformation {
-    pub color_depth: u8,
-    pub java_enabled: bool,
-    pub java_script_enabled: bool,
-    pub language: String,
-    pub screen_height: u32,
-    pub screen_width: u32,
-    pub time_zone: i32,
+    pub color_depth: Option<u8>,
+    pub java_enabled: Option<bool>,
+    pub java_script_enabled: Option<bool>,
+    pub language: Option<String>,
+    pub screen_height: Option<u32>,
+    pub screen_width: Option<u32>,
+    pub time_zone: Option<i32>,
     pub ip_address: Option<std::net::IpAddr>,
-    pub accept_header: String,
-    pub user_agent: String,
+    pub accept_header: Option<String>,
+    pub user_agent: Option<String>,
 }
 
 #[derive(Debug, Clone)]
diff --git a/crates/router/tests/connectors/trustpay.rs b/crates/router/tests/connectors/trustpay.rs
index 9d8355d17bc..7ce38336daa 100644
--- a/crates/router/tests/connectors/trustpay.rs
+++ b/crates/router/tests/connectors/trustpay.rs
@@ -36,15 +36,15 @@ impl utils::Connector for TrustpayTest {
 
 fn get_default_browser_info() -> BrowserInformation {
     BrowserInformation {
-        color_depth: 24,
-        java_enabled: false,
-        java_script_enabled: true,
-        language: "en-US".to_string(),
-        screen_height: 1080,
-        screen_width: 1920,
-        time_zone: 3600,
-        accept_header: "*".to_string(),
-        user_agent: "none".to_string(),
+        color_depth: Some(24),
+        java_enabled: Some(false),
+        java_script_enabled: Some(true),
+        language: Some("en-US".to_string()),
+        screen_height: Some(1080),
+        screen_width: Some(1920),
+        time_zone: Some(3600),
+        accept_header: Some("*".to_string()),
+        user_agent: Some("none".to_string()),
         ip_address: None,
     }
 }
diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs
index 6f0a39dc415..81b2677c9bb 100644
--- a/crates/router/tests/connectors/utils.rs
+++ b/crates/router/tests/connectors/utils.rs
@@ -549,15 +549,15 @@ impl Default for PaymentCancelType {
 impl Default for BrowserInfoType {
     fn default() -> Self {
         let data = types::BrowserInformation {
-            user_agent: "".to_string(),
-            accept_header: "".to_string(),
-            language: "nl-NL".to_string(),
-            color_depth: 24,
-            screen_height: 723,
-            screen_width: 1536,
-            time_zone: 0,
-            java_enabled: true,
-            java_script_enabled: true,
+            user_agent: Some("".to_string()),
+            accept_header: Some("".to_string()),
+            language: Some("nl-NL".to_string()),
+            color_depth: Some(24),
+            screen_height: Some(723),
+            screen_width: Some(1536),
+            time_zone: Some(0),
+            java_enabled: Some(true),
+            java_script_enabled: Some(true),
             ip_address: Some("127.0.0.1".parse().unwrap()),
         };
         Self(data)