Issue:
Bug: [FEATURE] add connector_metadata, metadata and feature_metadata fields in payments, remove udf field 



### Feature Description

Add connector_metadata, metadata and feature_metadata fields in payments, remove udf field 

### Possible Implementation

Add them 

### 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
<!-- Describe your changes in detail -->
In this PR , 
#### API CONTRACT CHANGES
In `PaymentsRequest` 3 fields are added : 
- connector_metadata(typed),
- feature_metadata(typed), 
-  metadata(can take any json),

also previous backwards compatibility to accept order_details in metadata is removed. 

This is a breaking change and it has been decided to not make it backwards compatible.

#### DB  CHANGES
- removed udf field from payments.
- added fields :
    - allowed_payment_method_types JSON,
    - connector_metadata JSON,
    - feature_metadata JSON;

### Additional Changes

- [x] This PR modifies the API contract
- [x] 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 its 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)?
-->
Tested order_category. It works. And made sure get_trackers payment_data.payment_intent is populated with the fields. 


## 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 order_category. It works. And made sure get_trackers payment_data.payment_intent is populated with the fields. 

Patch:
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index e2410699e1c..1f7b3050430 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -3,6 +3,7 @@ use std::num::NonZeroI64;
 use cards::CardNumber;
 use common_utils::{
     crypto,
+    ext_traits::Encode,
     pii::{self, Email},
 };
 use masking::{PeekInterface, Secret};
@@ -215,9 +216,6 @@ pub struct PaymentsRequest {
     #[schema(max_length = 255, example = "Payment for shoes purchase")]
     pub statement_descriptor_suffix: Option<String>,
 
-    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
-    pub metadata: Option<Metadata>,
-
     /// Information about the product , quantity and amount for connectors. (e.g. Klarna)
     #[schema(value_type = Option<Vec<OrderDetailsWithAmount>>, example = r#"[{
         "product_name": "gillete creme",
@@ -282,9 +280,72 @@ pub struct PaymentsRequest {
     #[schema(value_type = Option<RetryAction>)]
     pub retry_action: Option<api_enums::RetryAction>,
 
-    /// Any user defined fields can be passed here.
+    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
     #[schema(value_type = Option<Object>, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)]
-    pub udf: Option<pii::SecretSerdeValue>,
+    pub metadata: Option<pii::SecretSerdeValue>,
+
+    /// additional data related to some connectors
+    pub connector_metadata: Option<ConnectorMetadata>,
+
+    /// additional data that might be required by hyperswitch
+    pub feature_metadata: Option<FeatureMetadata>,
+}
+
+impl PaymentsRequest {
+    pub fn get_feature_metadata_as_value(
+        &self,
+    ) -> common_utils::errors::CustomResult<
+        Option<serde_json::Value>,
+        common_utils::errors::ParsingError,
+    > {
+        self.feature_metadata
+            .as_ref()
+            .map(Encode::<FeatureMetadata>::encode_to_value)
+            .transpose()
+    }
+
+    pub fn get_connector_metadata_as_value(
+        &self,
+    ) -> common_utils::errors::CustomResult<
+        Option<serde_json::Value>,
+        common_utils::errors::ParsingError,
+    > {
+        self.connector_metadata
+            .as_ref()
+            .map(Encode::<ConnectorMetadata>::encode_to_value)
+            .transpose()
+    }
+
+    pub fn get_allowed_payment_method_types_as_value(
+        &self,
+    ) -> common_utils::errors::CustomResult<
+        Option<serde_json::Value>,
+        common_utils::errors::ParsingError,
+    > {
+        self.allowed_payment_method_types
+            .as_ref()
+            .map(Encode::<Vec<api_enums::PaymentMethodType>>::encode_to_value)
+            .transpose()
+    }
+
+    pub fn get_order_details_as_value(
+        &self,
+    ) -> common_utils::errors::CustomResult<
+        Option<Vec<pii::SecretSerdeValue>>,
+        common_utils::errors::ParsingError,
+    > {
+        self.order_details
+            .as_ref()
+            .map(|od| {
+                od.iter()
+                    .map(|order| {
+                        Encode::<OrderDetailsWithAmount>::encode_to_value(order)
+                            .map(masking::Secret::new)
+                    })
+                    .collect::<Result<Vec<_>, _>>()
+            })
+            .transpose()
+    }
 }
 
 #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)]
@@ -1354,10 +1415,6 @@ pub struct PaymentsResponse {
     /// The billing address for the payment
     pub billing: Option<Address>,
 
-    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
-    #[schema(value_type = Option<Object>)]
-    pub metadata: Option<pii::SecretSerdeValue>,
-
     /// Information about the product , quantity and amount for connectors. (e.g. Klarna)
     #[schema(value_type = Option<Vec<OrderDetailsWithAmount>>, example = r#"[{
         "product_name": "gillete creme",
@@ -1432,7 +1489,7 @@ pub struct PaymentsResponse {
 
     /// Allowed Payment Method Types for a given PaymentIntent
     #[schema(value_type = Option<Vec<PaymentMethodType>>)]
-    pub allowed_payment_method_types: Option<Vec<api_enums::PaymentMethodType>>,
+    pub allowed_payment_method_types: Option<serde_json::Value>,
 
     /// ephemeral_key for the customer_id mentioned
     pub ephemeral_key: Option<EphemeralKeyCreateResponse>,
@@ -1440,13 +1497,21 @@ pub struct PaymentsResponse {
     /// If true the payment can be retried with same or different payment method which means the confirm call can be made again.
     pub manual_retry_allowed: Option<bool>,
 
-    /// Any user defined fields can be passed here.
-    #[schema(value_type = Option<Object>, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)]
-    pub udf: Option<pii::SecretSerdeValue>,
-
     /// A unique identifier for a payment provided by the connector
     #[schema(value_type = Option<String>, example = "993672945374576J")]
     pub connector_transaction_id: Option<String>,
+
+    /// You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.
+    #[schema(value_type = Option<Object>, example = r#"{ "udf1": "some-value", "udf2": "some-value" }"#)]
+    pub metadata: Option<pii::SecretSerdeValue>,
+
+    /// additional data related to some connectors
+    #[schema(value_type = Option<ConnectorMetadata>)]
+    pub connector_metadata: Option<serde_json::Value>, // This is Value because it is fetched from DB and before putting in DB the type is validated
+
+    /// additional data that might be required by hyperswitch
+    #[schema(value_type = Option<FeatureMetadata>)]
+    pub feature_metadata: Option<serde_json::Value>, // This is Value because it is fetched from DB and before putting in DB the type is validated
 }
 
 #[derive(Clone, Debug, serde::Deserialize, ToSchema)]
@@ -1704,23 +1769,6 @@ pub struct OrderDetails {
     pub quantity: u16,
 }
 
-#[derive(Default, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
-pub struct Metadata {
-    /// Information about the product and quantity for specific connectors. (e.g. Klarna)
-    pub order_details: Option<OrderDetails>,
-
-    /// Information about the order category that merchant wants to specify at connector level. (e.g. In Noon Payments it can take values like "pay", "food", or any other custom string set by the merchant in Noon's Dashboard)
-    pub order_category: Option<String>,
-
-    /// Redirection response coming in request as metadata field only for redirection scenarios
-    #[schema(value_type = Option<RedirectResponse>)]
-    pub redirect_response: Option<RedirectResponse>,
-
-    /// Allowed payment method types for a payment intent
-    #[schema(value_type = Option<Vec<PaymentMethodType>>)]
-    pub allowed_payment_method_types: Option<Vec<api_enums::PaymentMethodType>>,
-}
-
 #[derive(Default, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, Clone, ToSchema)]
 pub struct RedirectResponse {
     #[schema(value_type = Option<String>)]
@@ -1828,12 +1876,26 @@ pub struct ApplepaySessionRequest {
     pub initiative_context: String,
 }
 
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 pub struct ConnectorMetadata {
     pub apple_pay: Option<ApplepayConnectorMetadataRequest>,
+    pub airwallex: Option<AirwallexData>,
+    pub noon: Option<NoonData>,
 }
 
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
+pub struct AirwallexData {
+    /// payload required by airwallex
+    payload: Option<String>,
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
+pub struct NoonData {
+    /// Information about the order category that merchant wants to specify at connector level. (e.g. In Noon Payments it can take values like "pay", "food", or any other custom string set by the merchant in Noon's Dashboard)
+    pub order_category: Option<String>,
+}
+
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 pub struct ApplepayConnectorMetadataRequest {
     pub session_token_data: Option<SessionTokenInfo>,
 }
@@ -1857,7 +1919,7 @@ pub struct PaymentRequestMetadata {
     pub label: String,
 }
 
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 pub struct SessionTokenInfo {
     pub certificate: String,
     pub certificate_keys: String,
@@ -2111,6 +2173,13 @@ pub struct PaymentsStartRequest {
     pub attempt_id: String,
 }
 
+#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
+pub struct FeatureMetadata {
+    /// Redirection response coming in request as metadata field only for redirection scenarios
+    #[schema(value_type = Option<RedirectResponse>)]
+    pub redirect_response: Option<RedirectResponse>,
+}
+
 mod payment_id_type {
     use std::fmt;
 
diff --git a/crates/router/src/compatibility/stripe/payment_intents/types.rs b/crates/router/src/compatibility/stripe/payment_intents/types.rs
index 6cfa910e7fa..ff42e15034f 100644
--- a/crates/router/src/compatibility/stripe/payment_intents/types.rs
+++ b/crates/router/src/compatibility/stripe/payment_intents/types.rs
@@ -14,7 +14,6 @@ use crate::{
         api::{admin, enums as api_enums},
         transformers::{ForeignFrom, ForeignTryFrom},
     },
-    utils::OptionExt,
 };
 
 #[derive(Default, Serialize, PartialEq, Eq, Deserialize, Clone)]
@@ -220,13 +219,7 @@ impl TryFrom<StripePaymentIntentRequest> for payments::PaymentsRequest {
                 field_name: "receipt_ipaddress".to_string(),
                 expected_format: "127.0.0.1".to_string(),
             })?;
-        let metadata_object = item
-            .metadata
-            .clone()
-            .parse_value("metadata")
-            .change_context(errors::ApiErrorResponse::InvalidDataValue {
-                field_name: "metadata mapping failed",
-            })?;
+
         let request = Ok(Self {
             payment_id: item.id.map(payments::PaymentIdType::PaymentIntentId),
             amount: item.amount.map(|amount| amount.into()),
@@ -264,8 +257,7 @@ impl TryFrom<StripePaymentIntentRequest> for payments::PaymentsRequest {
                 .and_then(|pmd| pmd.billing_details.map(payments::Address::from)),
             statement_descriptor_name: item.statement_descriptor,
             statement_descriptor_suffix: item.statement_descriptor_suffix,
-            metadata: metadata_object,
-            udf: item.metadata,
+            metadata: item.metadata,
             client_secret: item.client_secret.map(|s| s.peek().clone()),
             authentication_type,
             mandate_data: mandate_options,
@@ -447,7 +439,7 @@ impl From<payments::PaymentsResponse> for StripePaymentIntentResponse {
             statement_descriptor_suffix: resp.statement_descriptor_suffix,
             next_action: into_stripe_next_action(resp.next_action, resp.return_url),
             cancellation_reason: resp.cancellation_reason,
-            metadata: resp.udf,
+            metadata: resp.metadata,
             charges: Charges::new(),
             last_payment_error: resp.error_code.map(|code| LastPaymentError {
                 charge: None,
diff --git a/crates/router/src/compatibility/stripe/setup_intents/types.rs b/crates/router/src/compatibility/stripe/setup_intents/types.rs
index df6f741f93f..294dd92b29b 100644
--- a/crates/router/src/compatibility/stripe/setup_intents/types.rs
+++ b/crates/router/src/compatibility/stripe/setup_intents/types.rs
@@ -237,7 +237,6 @@ impl TryFrom<StripeSetupIntentRequest> for payments::PaymentsRequest {
             statement_descriptor_name: item.statement_descriptor,
             statement_descriptor_suffix: item.statement_descriptor_suffix,
             metadata: metadata_object,
-            udf: item.metadata,
             client_secret: item.client_secret.map(|s| s.peek().clone()),
             setup_future_usage: item.setup_future_usage,
             merchant_connector_details: item.merchant_connector_details,
@@ -419,7 +418,7 @@ impl From<payments::PaymentsResponse> for StripeSetupIntentResponse {
             charges: payment_intent::Charges::new(),
             created: resp.created,
             customer: resp.customer_id,
-            metadata: resp.udf,
+            metadata: resp.metadata,
             id: resp.payment_id,
             refunds: resp
                 .refunds
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 9febf63c1eb..5020c877bae 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -1206,26 +1206,17 @@ pub async fn filter_payment_methods(
         let parse_result = serde_json::from_value::<PaymentMethodsEnabled>(payment_method);
         if let Ok(payment_methods_enabled) = parse_result {
             let payment_method = payment_methods_enabled.payment_method;
+
             let allowed_payment_method_types = payment_intent
-                .map(|payment_intent|
+                .and_then(|payment_intent| {
                     payment_intent
-                        .metadata
-                        .as_ref()
-                        .and_then(|masked_metadata| {
-                            let metadata = masked_metadata.peek().clone();
-                            let parsed_metadata: Option<api_models::payments::Metadata> =
-                                serde_json::from_value(metadata)
-                                    .map_err(|error| logger::error!(%error, "Failed to deserialize PaymentIntent metadata"))
-                                    .ok();
-                            parsed_metadata.and_then(|pm| {
-                                logger::info!(
-                                    "Only given PaymentMethodTypes will be allowed {:?}",
-                                    pm.allowed_payment_method_types
-                                );
-                                pm.allowed_payment_method_types
-                            })
-                }))
-                .and_then(|a| a);
+                        .allowed_payment_method_types
+                        .clone()
+                        .parse_value("Vec<PaymentMethodType>")
+                        .map_err(|error| logger::error!(%error, "Failed to deserialize PaymentIntent allowed_payment_method_types"))
+                        .ok()
+                });
+
             for payment_method_type_info in payment_methods_enabled
                 .payment_method_types
                 .unwrap_or_default()
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index 37f11e93ba7..76c9c4321bf 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -8,7 +8,6 @@ pub mod transformers;
 
 use std::{fmt::Debug, marker::PhantomData, ops::Deref, time::Instant};
 
-use api_models::payments::Metadata;
 use common_utils::pii;
 use error_stack::{IntoReport, ResultExt};
 use futures::future::join_all;
@@ -382,14 +381,11 @@ impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize {
         let payment_confirm_req = api::PaymentsRequest {
             payment_id: Some(req.resource_id.clone()),
             merchant_id: req.merchant_id.clone(),
-            metadata: Some(Metadata {
-                order_details: None,
+            feature_metadata: Some(api_models::payments::FeatureMetadata {
                 redirect_response: Some(api_models::payments::RedirectResponse {
                     param: req.param.map(Secret::new),
                     json_payload: Some(req.json_payload.unwrap_or(serde_json::json!({})).into()),
                 }),
-                allowed_payment_method_types: None,
-                order_category: None,
             }),
             ..Default::default()
         };
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index f47f67707a9..c37354f9c59 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -2,7 +2,7 @@ use std::borrow::Cow;
 
 use base64::Engine;
 use common_utils::{
-    ext_traits::{AsyncExt, ByteSliceExt, Encode, ValueExt},
+    ext_traits::{AsyncExt, ByteSliceExt, ValueExt},
     fp_utils, generate_id, pii,
 };
 // TODO : Evaluate all the helper functions ()
@@ -1906,7 +1906,9 @@ mod tests {
             business_country: storage_enums::CountryAlpha2::AG,
             business_label: "no".to_string(),
             order_details: None,
-            udf: None,
+            allowed_payment_method_types: None,
+            connector_metadata: None,
+            feature_metadata: None,
             attempt_count: 1,
         };
         let req_cs = Some("1".to_string());
@@ -1948,7 +1950,9 @@ mod tests {
             business_country: storage_enums::CountryAlpha2::AG,
             business_label: "no".to_string(),
             order_details: None,
-            udf: None,
+            allowed_payment_method_types: None,
+            connector_metadata: None,
+            feature_metadata: None,
             attempt_count: 1,
         };
         let req_cs = Some("1".to_string());
@@ -1990,7 +1994,9 @@ mod tests {
             business_country: storage_enums::CountryAlpha2::AG,
             business_label: "no".to_string(),
             order_details: None,
-            udf: None,
+            allowed_payment_method_types: None,
+            connector_metadata: None,
+            feature_metadata: None,
             attempt_count: 1,
         };
         let req_cs = Some("1".to_string());
@@ -2434,108 +2440,6 @@ pub fn is_manual_retry_allowed(
     }
 }
 
-pub fn validate_and_add_order_details_to_payment_intent(
-    payment_intent: &mut storage::payment_intent::PaymentIntent,
-    request: &api::PaymentsRequest,
-) -> RouterResult<()> {
-    let parsed_metadata_db: Option<api_models::payments::Metadata> = payment_intent
-        .metadata
-        .as_ref()
-        .map(|metadata_value| {
-            metadata_value
-                .peek()
-                .clone()
-                .parse_value("metadata")
-                .change_context(errors::ApiErrorResponse::InvalidDataValue {
-                    field_name: "metadata",
-                })
-                .attach_printable("unable to parse metadata")
-        })
-        .transpose()?;
-    let order_details_metadata_db = parsed_metadata_db
-        .as_ref()
-        .and_then(|meta| meta.order_details.to_owned());
-    let order_details_outside_metadata_db = payment_intent.order_details.as_ref();
-    let order_details_outside_metadata_req = request.order_details.as_ref();
-    let order_details_metadata_req = request
-        .metadata
-        .as_ref()
-        .and_then(|meta| meta.order_details.to_owned());
-
-    if order_details_metadata_db
-        .as_ref()
-        .zip(order_details_outside_metadata_db.as_ref())
-        .is_some()
-    {
-        Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payment intent in db".to_string() })?
-    }
-    let order_details_outside = match order_details_outside_metadata_req {
-        Some(order) => match order_details_metadata_db {
-            Some(_) => Err(errors::ApiErrorResponse::NotSupported {
-                message: "order_details previously present inside of metadata".to_string(),
-            })?,
-            None => Some(order),
-        },
-        None => match order_details_metadata_req {
-            Some(_order) => match order_details_outside_metadata_db {
-                Some(_) => Err(errors::ApiErrorResponse::NotSupported {
-                    message: "order_details previously present outside of metadata".to_string(),
-                })?,
-                None => None,
-            },
-            None => None,
-        },
-    };
-    add_order_details_and_metadata_to_payment_intent(
-        payment_intent,
-        request,
-        parsed_metadata_db,
-        &order_details_outside.map(|data| data.to_owned()),
-    )
-}
-
-pub fn add_order_details_and_metadata_to_payment_intent(
-    mut payment_intent: &mut storage::payment_intent::PaymentIntent,
-    request: &api::PaymentsRequest,
-    parsed_metadata_db: Option<api_models::payments::Metadata>,
-    order_details_outside: &Option<Vec<api_models::payments::OrderDetailsWithAmount>>,
-) -> RouterResult<()> {
-    let metadata_with_order_details = match request.metadata.as_ref() {
-        Some(meta) => {
-            let transformed_metadata = match parsed_metadata_db {
-                Some(meta_db) => api_models::payments::Metadata {
-                    order_details: meta.order_details.to_owned(),
-                    ..meta_db
-                },
-                None => meta.to_owned(),
-            };
-            let transformed_metadata_value =
-                Encode::<api_models::payments::Metadata>::encode_to_value(&transformed_metadata)
-                    .change_context(errors::ApiErrorResponse::InternalServerError)
-                    .attach_printable("Encoding Metadata to value failed")?;
-            Some(masking::Secret::new(transformed_metadata_value))
-        }
-        None => None,
-    };
-    if let Some(order_details_outside_struct) = order_details_outside {
-        let order_details_outside_value = order_details_outside_struct
-            .iter()
-            .map(|order| {
-                Encode::<api_models::payments::OrderDetailsWithAmount>::encode_to_value(order)
-                    .change_context(errors::ApiErrorResponse::InternalServerError)
-                    .map(masking::Secret::new)
-            })
-            .collect::<Result<Vec<_>, _>>()?;
-        payment_intent.order_details = Some(order_details_outside_value);
-    };
-
-    if metadata_with_order_details.is_some() {
-        payment_intent.metadata = metadata_with_order_details;
-    }
-
-    Ok(())
-}
-
 #[cfg(test)]
 mod test {
     #![allow(clippy::unwrap_used)]
diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
index 1d71f4ba31b..47803dc79de 100644
--- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs
+++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs
@@ -159,14 +159,34 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Co
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
         let redirect_response = request
-            .metadata
+            .feature_metadata
             .as_ref()
-            .and_then(|secret_metadata| secret_metadata.redirect_response.to_owned());
+            .and_then(|fm| fm.redirect_response.clone());
 
         payment_intent.shipping_address_id = shipping_address.clone().map(|i| i.address_id);
         payment_intent.billing_address_id = billing_address.clone().map(|i| i.address_id);
         payment_intent.return_url = request.return_url.as_ref().map(|a| a.to_string());
 
+        payment_intent.allowed_payment_method_types = request
+            .get_allowed_payment_method_types_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting allowed_payment_types to Value")?
+            .or(payment_intent.allowed_payment_method_types);
+
+        payment_intent.connector_metadata = request
+            .get_connector_metadata_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting connector_metadata to Value")?
+            .or(payment_intent.connector_metadata);
+
+        payment_intent.feature_metadata = request
+            .get_feature_metadata_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting feature_metadata to Value")?
+            .or(payment_intent.feature_metadata);
+
+        payment_intent.metadata = request.metadata.clone().or(payment_intent.metadata);
+
         // The operation merges mandate data from both request and payment_attempt
         let setup_mandate = setup_mandate.map(|mandate_data| api_models::payments::MandateData {
             customer_acceptance: mandate_data.customer_acceptance,
diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs
index 01800b70177..6307e4639e2 100644
--- a/crates/router/src/core/payments/operations/payment_confirm.rs
+++ b/crates/router/src/core/payments/operations/payment_confirm.rs
@@ -72,11 +72,6 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             "confirm",
         )?;
 
-        let _ = helpers::validate_and_add_order_details_to_payment_intent(
-            &mut payment_intent,
-            request,
-        )?;
-
         payment_attempt = db
             .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
                 payment_intent.payment_id.as_str(),
@@ -87,6 +82,12 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
+        payment_intent.order_details = request
+            .get_order_details_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to convert order details to value")?
+            .or(payment_intent.order_details);
+
         let attempt_type =
             helpers::get_attempt_type(&payment_intent, &payment_attempt, request, "confirm")?;
 
@@ -202,8 +203,25 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             .as_ref()
             .map(|a| a.to_string())
             .or(payment_intent.return_url);
-        payment_intent.udf = request.udf.clone().or(payment_intent.udf);
 
+        payment_intent.allowed_payment_method_types = request
+            .get_allowed_payment_method_types_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting allowed_payment_types to Value")?
+            .or(payment_intent.allowed_payment_method_types);
+
+        payment_intent.connector_metadata = request
+            .get_connector_metadata_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting connector_metadata to Value")?
+            .or(payment_intent.connector_metadata);
+
+        payment_intent.feature_metadata = request
+            .get_feature_metadata_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting feature_metadata to Value")?
+            .or(payment_intent.feature_metadata);
+        payment_intent.metadata = request.metadata.clone().or(payment_intent.metadata);
         payment_attempt.business_sub_label = request
             .business_sub_label
             .clone()
@@ -429,7 +447,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
             .take();
         let order_details = payment_data.payment_intent.order_details.clone();
         let metadata = payment_data.payment_intent.metadata.clone();
-        let udf = payment_data.payment_intent.udf.clone();
+
         payment_data.payment_intent = db
             .update_payment_intent(
                 payment_data.payment_intent,
@@ -449,7 +467,6 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
                     statement_descriptor_suffix,
                     order_details,
                     metadata,
-                    udf,
                 },
                 storage_scheme,
             )
@@ -482,19 +499,6 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentConfir
         BoxedOperation<'b, F, api::PaymentsRequest>,
         operations::ValidateResult<'a>,
     )> {
-        let order_details_inside_metadata = request
-            .metadata
-            .as_ref()
-            .and_then(|meta| meta.order_details.to_owned());
-        if request
-            .order_details
-            .as_ref()
-            .zip(order_details_inside_metadata)
-            .is_some()
-        {
-            Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
-        }
-
         helpers::validate_customer_details_in_request(request)?;
 
         let given_payment_id = match &request.payment_id {
diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs
index a8ae302558e..24b867003a3 100644
--- a/crates/router/src/core/payments/operations/payment_create.rs
+++ b/crates/router/src/core/payments/operations/payment_create.rs
@@ -1,6 +1,5 @@
 use std::marker::PhantomData;
 
-use api_models::payments::OrderDetailsWithAmount;
 use async_trait::async_trait;
 use common_utils::ext_traits::{AsyncExt, Encode, ValueExt};
 use error_stack::{self, ResultExt};
@@ -414,19 +413,6 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentCreate
         BoxedOperation<'b, F, api::PaymentsRequest>,
         operations::ValidateResult<'a>,
     )> {
-        let order_details_inside_metadata = request
-            .metadata
-            .as_ref()
-            .and_then(|meta| meta.order_details.to_owned());
-        if request
-            .order_details
-            .as_ref()
-            .zip(order_details_inside_metadata)
-            .is_some()
-        {
-            Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
-        }
-
         helpers::validate_customer_details_in_request(request)?;
 
         let given_payment_id = match &request.payment_id {
@@ -570,45 +556,11 @@ impl PaymentCreate {
         let client_secret =
             crate::utils::generate_id(consts::ID_LENGTH, format!("{payment_id}_secret").as_str());
         let (amount, currency) = (money.0, Some(money.1));
-        let metadata = request
-            .metadata
-            .as_ref()
-            .map(|metadata| {
-                let transformed_metadata = api_models::payments::Metadata {
-                    allowed_payment_method_types: request.allowed_payment_method_types.clone(),
-                    ..metadata.clone()
-                };
-                Encode::<api_models::payments::Metadata>::encode_to_value(&transformed_metadata)
-            })
-            .transpose()
+
+        let order_details = request
+            .get_order_details_as_value()
             .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Encoding Metadata to value failed")?;
-        let order_details_metadata_req = request
-            .metadata
-            .as_ref()
-            .and_then(|meta| meta.order_details.to_owned());
-        if request
-            .order_details
-            .as_ref()
-            .zip(order_details_metadata_req)
-            .is_some()
-        {
-            Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
-        }
-        let order_details_outside_value = match request.order_details.as_ref() {
-            Some(od_value) => {
-                let order_details_outside_value_secret = od_value
-                    .iter()
-                    .map(|order| {
-                        Encode::<OrderDetailsWithAmount>::encode_to_value(order)
-                            .change_context(errors::ApiErrorResponse::InternalServerError)
-                            .map(masking::Secret::new)
-                    })
-                    .collect::<Result<Vec<_>, _>>()?;
-                Some(order_details_outside_value_secret)
-            }
-            None => None,
-        };
+            .attach_printable("Failed to convert order details to value")?;
 
         let (business_country, business_label) = helpers::get_business_details(
             request.business_country,
@@ -616,6 +568,21 @@ impl PaymentCreate {
             merchant_account,
         )?;
 
+        let allowed_payment_method_types = request
+            .get_allowed_payment_method_types_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting allowed_payment_types to Value")?;
+
+        let connector_metadata = request
+            .get_connector_metadata_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting connector_metadata to Value")?;
+
+        let feature_metadata = request
+            .get_feature_metadata_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting feature_metadata to Value")?;
+
         Ok(storage::PaymentIntentNew {
             payment_id: payment_id.to_string(),
             merchant_id: merchant_account.merchant_id.to_string(),
@@ -634,14 +601,18 @@ impl PaymentCreate {
             billing_address_id,
             statement_descriptor_name: request.statement_descriptor_name.clone(),
             statement_descriptor_suffix: request.statement_descriptor_suffix.clone(),
-            metadata: metadata.map(masking::Secret::new),
+            metadata: request.metadata.clone(),
             business_country,
             business_label,
             active_attempt_id,
-            order_details: order_details_outside_value,
-            udf: request.udf.clone(),
+            order_details,
+            amount_captured: None,
+            customer_id: None,
+            connector_id: None,
+            allowed_payment_method_types,
+            connector_metadata,
+            feature_metadata,
             attempt_count: 1,
-            ..storage::PaymentIntentNew::default()
         })
     }
 
diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs
index f2868a2ede4..9770a86d72a 100644
--- a/crates/router/src/core/payments/operations/payment_update.rs
+++ b/crates/router/src/core/payments/operations/payment_update.rs
@@ -90,10 +90,12 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
             .await
             .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?;
 
-        let _ = helpers::validate_and_add_order_details_to_payment_intent(
-            &mut payment_intent,
-            request,
-        )?;
+        payment_intent.order_details = request
+            .get_order_details_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to convert order details to value")?
+            .or(payment_intent.order_details);
+
         payment_attempt = db
             .find_payment_attempt_by_payment_id_merchant_id_attempt_id(
                 payment_intent.payment_id.as_str(),
@@ -158,6 +160,24 @@ impl<F: Send + Clone> GetTracker<F, PaymentData<F>, api::PaymentsRequest> for Pa
         payment_intent.shipping_address_id = shipping_address.clone().map(|x| x.address_id);
         payment_intent.billing_address_id = billing_address.clone().map(|x| x.address_id);
 
+        payment_intent.allowed_payment_method_types = request
+            .get_allowed_payment_method_types_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting allowed_payment_types to Value")?
+            .or(payment_intent.allowed_payment_method_types);
+
+        payment_intent.connector_metadata = request
+            .get_connector_metadata_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting connector_metadata to Value")?
+            .or(payment_intent.connector_metadata);
+
+        payment_intent.feature_metadata = request
+            .get_feature_metadata_as_value()
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Error converting feature_metadata to Value")?
+            .or(payment_intent.feature_metadata);
+        payment_intent.metadata = request.metadata.clone().or(payment_intent.metadata);
         Self::populate_payment_intent_with_request(&mut payment_intent, request);
 
         let token = token.or_else(|| payment_attempt.payment_token.clone());
@@ -478,7 +498,7 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
             .clone();
         let order_details = payment_data.payment_intent.order_details.clone();
         let metadata = payment_data.payment_intent.metadata.clone();
-        let udf = payment_data.payment_intent.udf.clone();
+
         payment_data.payment_intent = db
             .update_payment_intent(
                 payment_data.payment_intent,
@@ -498,7 +518,6 @@ impl<F: Clone> UpdateTracker<F, PaymentData<F>, api::PaymentsRequest> for Paymen
                     statement_descriptor_suffix,
                     order_details,
                     metadata,
-                    udf,
                 },
                 storage_scheme,
             )
@@ -524,19 +543,6 @@ impl<F: Send + Clone> ValidateRequest<F, api::PaymentsRequest> for PaymentUpdate
         BoxedOperation<'b, F, api::PaymentsRequest>,
         operations::ValidateResult<'a>,
     )> {
-        let order_details_inside_metadata = request
-            .metadata
-            .as_ref()
-            .and_then(|meta| meta.order_details.to_owned());
-        if request
-            .order_details
-            .as_ref()
-            .zip(order_details_inside_metadata)
-            .is_some()
-        {
-            Err(errors::ApiErrorResponse::NotSupported { message: "order_details cannot be present both inside and outside metadata in payments request".to_string() })?
-        }
-
         helpers::validate_customer_details_in_request(request)?;
 
         let given_payment_id = match &request.payment_id {
@@ -646,10 +652,5 @@ impl PaymentUpdate {
             .client_secret
             .clone()
             .map(|i| payment_intent.client_secret.replace(i));
-
-        request
-            .udf
-            .clone()
-            .map(|udf| payment_intent.udf.replace(udf));
     }
 }
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index a9ad00b969f..a3ead3fb17a 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -3,7 +3,6 @@ use std::{fmt::Debug, marker::PhantomData};
 use api_models::payments::OrderDetailsWithAmount;
 use common_utils::fp_utils;
 use error_stack::ResultExt;
-use masking::PeekInterface;
 use router_env::{instrument, tracing};
 use storage_models::ephemeral_key;
 
@@ -361,19 +360,7 @@ where
                         connector_name,
                     )
                 });
-                let parsed_metadata: Option<api_models::payments::Metadata> = payment_intent
-                    .metadata
-                    .clone()
-                    .map(|metadata_value| {
-                        metadata_value
-                            .parse_value("metadata")
-                            .change_context(errors::ApiErrorResponse::InvalidDataValue {
-                                field_name: "metadata",
-                            })
-                            .attach_printable("unable to parse metadata")
-                    })
-                    .transpose()
-                    .unwrap_or_default();
+
                 let amount_captured = payment_intent.amount_captured.unwrap_or_default();
                 let amount_capturable = Some(payment_attempt.amount - amount_captured);
                 services::ApplicationResponse::Json(
@@ -460,16 +447,16 @@ where
                         .set_business_label(payment_intent.business_label)
                         .set_business_sub_label(payment_attempt.business_sub_label)
                         .set_allowed_payment_method_types(
-                            parsed_metadata
-                                .and_then(|metadata| metadata.allowed_payment_method_types),
+                            payment_intent.allowed_payment_method_types,
                         )
                         .set_ephemeral_key(ephemeral_key_option.map(ForeignFrom::foreign_from))
                         .set_manual_retry_allowed(helpers::is_manual_retry_allowed(
                             &payment_intent.status,
                             &payment_attempt.status,
                         ))
-                        .set_udf(payment_intent.udf)
                         .set_connector_transaction_id(payment_attempt.connector_transaction_id)
+                        .set_feature_metadata(payment_intent.feature_metadata)
+                        .set_connector_metadata(payment_intent.connector_metadata)
                         .to_owned(),
                 )
             }
@@ -517,8 +504,10 @@ where
                 &payment_attempt.status,
             ),
             order_details: payment_intent.order_details,
-            udf: payment_intent.udf,
             connector_transaction_id: payment_attempt.connector_transaction_id,
+            feature_metadata: payment_intent.feature_metadata,
+            connector_metadata: payment_intent.connector_metadata,
+            allowed_payment_method_types: payment_intent.allowed_payment_method_types,
             ..Default::default()
         }),
     });
@@ -662,31 +651,43 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsAuthoriz
                 field_name: "browser_info",
             })?;
 
-        let parsed_metadata: Option<api_models::payments::Metadata> = payment_data
+        let order_category = additional_data
+            .payment_data
             .payment_intent
-            .metadata
-            .as_ref()
-            .map(|metadata_value| {
-                metadata_value
-                    .clone()
-                    .parse_value("metadata")
-                    .change_context(errors::ApiErrorResponse::InvalidDataValue {
-                        field_name: "metadata",
+            .connector_metadata
+            .map(|cm| {
+                cm.parse_value::<api_models::payments::ConnectorMetadata>("ConnectorMetadata")
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed parsing ConnectorMetadata")
+            })
+            .transpose()?
+            .and_then(|cm| cm.noon.and_then(|noon| noon.order_category));
+
+        let order_details = additional_data
+            .payment_data
+            .payment_intent
+            .order_details
+            .map(|order_details| {
+                order_details
+                    .iter()
+                    .map(|data| {
+                        data.to_owned()
+                            .parse_value("OrderDetailsWithAmount")
+                            .change_context(errors::ApiErrorResponse::InvalidDataValue {
+                                field_name: "OrderDetailsWithAmount",
+                            })
+                            .attach_printable("Unable to parse OrderDetailsWithAmount")
                     })
-                    .attach_printable("unable to parse metadata")
+                    .collect::<Result<Vec<_>, _>>()
             })
-            .transpose()
-            .unwrap_or_default();
-        let order_category = parsed_metadata
-            .as_ref()
-            .and_then(|data| data.order_category.clone());
-        let order_details =
-            fetch_order_details(additional_data.clone(), parsed_metadata, &payment_data)?;
+            .transpose()?;
+
         let complete_authorize_url = Some(helpers::create_complete_authorize_url(
             router_base_url,
             attempt,
             connector_name,
         ));
+
         let webhook_url = Some(helpers::create_webhook_url(
             router_base_url,
             &attempt.merchant_id,
@@ -839,24 +840,25 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsSessionD
 
     fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result<Self, Self::Error> {
         let payment_data = additional_data.payment_data.clone();
-        let parsed_metadata: Option<api_models::payments::Metadata> = payment_data
+
+        let order_details = additional_data
+            .payment_data
             .payment_intent
-            .metadata
-            .as_ref()
-            .map(|metadata_value| {
-                metadata_value
-                    .clone()
-                    .parse_value("metadata")
-                    .change_context(errors::ApiErrorResponse::InvalidDataValue {
-                        field_name: "metadata",
+            .order_details
+            .map(|order_details| {
+                order_details
+                    .iter()
+                    .map(|data| {
+                        data.to_owned()
+                            .parse_value("OrderDetailsWithAmount")
+                            .change_context(errors::ApiErrorResponse::InvalidDataValue {
+                                field_name: "OrderDetailsWithAmount",
+                            })
+                            .attach_printable("Unable to parse OrderDetailsWithAmount")
                     })
-                    .attach_printable("unable to parse metadata")
+                    .collect::<Result<Vec<_>, _>>()
             })
-            .transpose()
-            .unwrap_or_default();
-
-        let order_details =
-            fetch_order_details(additional_data.clone(), parsed_metadata, &payment_data)?;
+            .transpose()?;
 
         Ok(Self {
             amount: payment_data.amount.into(),
@@ -957,38 +959,3 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsPreProce
         })
     }
 }
-
-pub fn fetch_order_details<F: Clone>(
-    additional_data: PaymentAdditionalData<'_, F>,
-    parsed_metadata: Option<api_models::payments::Metadata>,
-    payment_data: &PaymentData<F>,
-) -> RouterResult<Option<Vec<OrderDetailsWithAmount>>> {
-    let order_details_metadata_parsed = parsed_metadata.and_then(|data| data.order_details);
-    let order_details_outside_metadata_parsed =
-        match payment_data.payment_intent.order_details.clone() {
-            Some(order_details_outside_metadata_value) => {
-                let parsed_value = order_details_outside_metadata_value
-                    .iter()
-                    .map(|data| {
-                        data.peek()
-                            .to_owned()
-                            .parse_value("OrderDetailsWithAmount")
-                            .change_context(errors::ApiErrorResponse::InvalidDataValue {
-                                field_name: "OrderDetailsWithAmount",
-                            })
-                            .attach_printable("unable to parse OrderDetailsWithAmount")
-                    })
-                    .collect::<Result<Vec<_>, _>>()?;
-                Some(parsed_value)
-            }
-            None => None,
-        };
-    let order_details = match order_details_metadata_parsed {
-        Some(odm) => change_order_details_to_new_type(
-            additional_data.clone().payment_data.payment_intent.amount,
-            odm,
-        ),
-        None => order_details_outside_metadata_parsed,
-    };
-    Ok(order_details)
-}
diff --git a/crates/router/src/db/payment_intent.rs b/crates/router/src/db/payment_intent.rs
index 4fa6c9fb5a1..4ff605d1f5b 100644
--- a/crates/router/src/db/payment_intent.rs
+++ b/crates/router/src/db/payment_intent.rs
@@ -96,7 +96,9 @@ mod storage {
                         business_label: new.business_label.clone(),
                         active_attempt_id: new.active_attempt_id.to_owned(),
                         order_details: new.order_details.clone(),
-                        udf: new.udf.clone(),
+                        allowed_payment_method_types: new.allowed_payment_method_types.clone(),
+                        connector_metadata: new.connector_metadata.clone(),
+                        feature_metadata: new.feature_metadata.clone(),
                         attempt_count: new.attempt_count,
                     };
 
@@ -357,7 +359,9 @@ impl PaymentIntentInterface for MockDb {
             business_label: new.business_label,
             active_attempt_id: new.active_attempt_id.to_owned(),
             order_details: new.order_details,
-            udf: new.udf,
+            allowed_payment_method_types: new.allowed_payment_method_types,
+            connector_metadata: new.connector_metadata,
+            feature_metadata: new.feature_metadata,
             attempt_count: new.attempt_count,
         };
         payment_intents.push(payment_intent.clone());
diff --git a/crates/router/src/openapi.rs b/crates/router/src/openapi.rs
index 2c0643d3fe3..3c7c1777076 100644
--- a/crates/router/src/openapi.rs
+++ b/crates/router/src/openapi.rs
@@ -178,10 +178,15 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::BankRedirectData,
         api_models::payments::BankRedirectBilling,
         api_models::payments::BankRedirectBilling,
+        api_models::payments::ConnectorMetadata,
+        api_models::payments::FeatureMetadata,
+        api_models::payments::ApplepayConnectorMetadataRequest,
+        api_models::payments::SessionTokenInfo,
+        api_models::payments::AirwallexData,
+        api_models::payments::NoonData,
         api_models::payments::OrderDetails,
         api_models::payments::OrderDetailsWithAmount,
         api_models::payments::NextActionType,
-        api_models::payments::Metadata,
         api_models::payments::WalletData,
         api_models::payments::NextActionData,
         api_models::payments::PayLaterData,
diff --git a/crates/storage_models/src/payment_intent.rs b/crates/storage_models/src/payment_intent.rs
index 14173879bae..cd16f34742e 100644
--- a/crates/storage_models/src/payment_intent.rs
+++ b/crates/storage_models/src/payment_intent.rs
@@ -38,7 +38,9 @@ pub struct PaymentIntent {
     pub business_label: String,
     #[diesel(deserialize_as = super::OptionalDieselArray<pii::SecretSerdeValue>)]
     pub order_details: Option<Vec<pii::SecretSerdeValue>>,
-    pub udf: Option<pii::SecretSerdeValue>,
+    pub allowed_payment_method_types: Option<serde_json::Value>,
+    pub connector_metadata: Option<serde_json::Value>,
+    pub feature_metadata: Option<serde_json::Value>,
     pub attempt_count: i16,
 }
 
@@ -84,7 +86,9 @@ pub struct PaymentIntentNew {
     pub business_label: String,
     #[diesel(deserialize_as = super::OptionalDieselArray<pii::SecretSerdeValue>)]
     pub order_details: Option<Vec<pii::SecretSerdeValue>>,
-    pub udf: Option<pii::SecretSerdeValue>,
+    pub allowed_payment_method_types: Option<serde_json::Value>,
+    pub connector_metadata: Option<serde_json::Value>,
+    pub feature_metadata: Option<serde_json::Value>,
     pub attempt_count: i16,
 }
 
@@ -129,7 +133,6 @@ pub enum PaymentIntentUpdate {
         statement_descriptor_suffix: Option<String>,
         order_details: Option<Vec<pii::SecretSerdeValue>>,
         metadata: Option<pii::SecretSerdeValue>,
-        udf: Option<pii::SecretSerdeValue>,
     },
     PaymentAttemptUpdate {
         active_attempt_id: String,
@@ -166,7 +169,6 @@ pub struct PaymentIntentUpdateInternal {
     pub statement_descriptor_suffix: Option<String>,
     #[diesel(deserialize_as = super::OptionalDieselArray<pii::SecretSerdeValue>)]
     pub order_details: Option<Vec<pii::SecretSerdeValue>>,
-    pub udf: Option<pii::SecretSerdeValue>,
     pub attempt_count: Option<i16>,
 }
 
@@ -220,7 +222,6 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 statement_descriptor_suffix,
                 order_details,
                 metadata,
-                udf,
             } => Self {
                 amount: Some(amount),
                 currency: Some(currency),
@@ -239,7 +240,6 @@ impl From<PaymentIntentUpdate> for PaymentIntentUpdateInternal {
                 statement_descriptor_suffix,
                 order_details,
                 metadata,
-                udf,
                 ..Default::default()
             },
             PaymentIntentUpdate::MetadataUpdate { metadata } => Self {
diff --git a/crates/storage_models/src/schema.rs b/crates/storage_models/src/schema.rs
index 1e1ce1d7332..2177eb286aa 100644
--- a/crates/storage_models/src/schema.rs
+++ b/crates/storage_models/src/schema.rs
@@ -477,7 +477,9 @@ diesel::table! {
         #[max_length = 64]
         business_label -> Varchar,
         order_details -> Nullable<Array<Nullable<Jsonb>>>,
-        udf -> Nullable<Jsonb>,
+        allowed_payment_method_types -> Nullable<Json>,
+        connector_metadata -> Nullable<Json>,
+        feature_metadata -> Nullable<Json>,
         attempt_count -> Int2,
     }
 }
diff --git a/migrations/2023-06-29-094858_payment-intent-remove-udf-field/down.sql b/migrations/2023-06-29-094858_payment-intent-remove-udf-field/down.sql
new file mode 100644
index 00000000000..b13ae2326e0
--- /dev/null
+++ b/migrations/2023-06-29-094858_payment-intent-remove-udf-field/down.sql
@@ -0,0 +1,2 @@
+-- This file should undo anything in `up.sql`
+ALTER TABLE payment_intent ADD COLUMN udf JSONB;
diff --git a/migrations/2023-06-29-094858_payment-intent-remove-udf-field/up.sql b/migrations/2023-06-29-094858_payment-intent-remove-udf-field/up.sql
new file mode 100644
index 00000000000..1c0a29b53e6
--- /dev/null
+++ b/migrations/2023-06-29-094858_payment-intent-remove-udf-field/up.sql
@@ -0,0 +1,2 @@
+-- Your SQL goes here
+ALTER TABLE payment_intent DROP COLUMN udf;
diff --git a/migrations/2023-07-01-184850_payment-intent-add-metadata-fields/down.sql b/migrations/2023-07-01-184850_payment-intent-add-metadata-fields/down.sql
new file mode 100644
index 00000000000..d3babf9b094
--- /dev/null
+++ b/migrations/2023-07-01-184850_payment-intent-add-metadata-fields/down.sql
@@ -0,0 +1,5 @@
+-- This file should undo anything in `up.sql`
+ALTER TABLE payment_intent 
+DROP COLUMN allowed_payment_method_types,
+DROP COLUMN connector_metadata,
+DROP COLUMN feature_metadata;
diff --git a/migrations/2023-07-01-184850_payment-intent-add-metadata-fields/up.sql b/migrations/2023-07-01-184850_payment-intent-add-metadata-fields/up.sql
new file mode 100644
index 00000000000..d3be339d840
--- /dev/null
+++ b/migrations/2023-07-01-184850_payment-intent-add-metadata-fields/up.sql
@@ -0,0 +1,5 @@
+-- Your SQL goes here
+ALTER TABLE payment_intent
+ADD COLUMN allowed_payment_method_types JSON,
+ADD COLUMN connector_metadata JSON,
+ADD COLUMN feature_metadata JSON;
diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json
index 240cf9698c1..d9cc619b9d0 100644
--- a/openapi/openapi_spec.json
+++ b/openapi/openapi_spec.json
@@ -1729,6 +1729,16 @@
           }
         }
       },
+      "AirwallexData": {
+        "type": "object",
+        "properties": {
+          "payload": {
+            "type": "string",
+            "description": "payload required by airwallex",
+            "nullable": true
+          }
+        }
+      },
       "AliPayHkRedirection": {
         "type": "object"
       },
@@ -1852,6 +1862,19 @@
           }
         }
       },
+      "ApplepayConnectorMetadataRequest": {
+        "type": "object",
+        "properties": {
+          "session_token_data": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/SessionTokenInfo"
+              }
+            ],
+            "nullable": true
+          }
+        }
+      },
       "ApplepayPaymentMethod": {
         "type": "object",
         "required": [
@@ -2886,6 +2909,35 @@
           "zen"
         ]
       },
+      "ConnectorMetadata": {
+        "type": "object",
+        "properties": {
+          "apple_pay": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/ApplepayConnectorMetadataRequest"
+              }
+            ],
+            "nullable": true
+          },
+          "airwallex": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/AirwallexData"
+              }
+            ],
+            "nullable": true
+          },
+          "noon": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/NoonData"
+              }
+            ],
+            "nullable": true
+          }
+        }
+      },
       "ConnectorType": {
         "type": "string",
         "enum": [
@@ -3877,6 +3929,19 @@
           }
         }
       },
+      "FeatureMetadata": {
+        "type": "object",
+        "properties": {
+          "redirect_response": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/RedirectResponse"
+              }
+            ],
+            "nullable": true
+          }
+        }
+      },
       "FieldType": {
         "oneOf": [
           {
@@ -5335,40 +5400,6 @@
           }
         }
       },
-      "Metadata": {
-        "type": "object",
-        "properties": {
-          "order_details": {
-            "allOf": [
-              {
-                "$ref": "#/components/schemas/OrderDetails"
-              }
-            ],
-            "nullable": true
-          },
-          "order_category": {
-            "type": "string",
-            "description": "Information about the order category that merchant wants to specify at connector level. (e.g. In Noon Payments it can take values like \"pay\", \"food\", or any other custom string set by the merchant in Noon's Dashboard)",
-            "nullable": true
-          },
-          "redirect_response": {
-            "allOf": [
-              {
-                "$ref": "#/components/schemas/RedirectResponse"
-              }
-            ],
-            "nullable": true
-          },
-          "allowed_payment_method_types": {
-            "type": "array",
-            "items": {
-              "$ref": "#/components/schemas/PaymentMethodType"
-            },
-            "description": "Allowed payment method types for a payment intent",
-            "nullable": true
-          }
-        }
-      },
       "MobilePayRedirection": {
         "type": "object"
       },
@@ -5525,6 +5556,16 @@
           }
         }
       },
+      "NoonData": {
+        "type": "object",
+        "properties": {
+          "order_category": {
+            "type": "string",
+            "description": "Information about the order category that merchant wants to specify at connector level. (e.g. In Noon Payments it can take values like \"pay\", \"food\", or any other custom string set by the merchant in Noon's Dashboard)",
+            "nullable": true
+          }
+        }
+      },
       "OnlineMandate": {
         "type": "object",
         "required": [
@@ -6606,14 +6647,6 @@
             "nullable": true,
             "maxLength": 255
           },
-          "metadata": {
-            "allOf": [
-              {
-                "$ref": "#/components/schemas/Metadata"
-              }
-            ],
-            "nullable": true
-          },
           "order_details": {
             "type": "array",
             "items": {
@@ -6708,9 +6741,25 @@
             ],
             "nullable": true
           },
-          "udf": {
+          "metadata": {
             "type": "object",
-            "description": "Any user defined fields can be passed here.",
+            "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
+            "nullable": true
+          },
+          "connector_metadata": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/ConnectorMetadata"
+              }
+            ],
+            "nullable": true
+          },
+          "feature_metadata": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/FeatureMetadata"
+              }
+            ],
             "nullable": true
           }
         }
@@ -6932,14 +6981,6 @@
             "nullable": true,
             "maxLength": 255
           },
-          "metadata": {
-            "allOf": [
-              {
-                "$ref": "#/components/schemas/Metadata"
-              }
-            ],
-            "nullable": true
-          },
           "order_details": {
             "type": "array",
             "items": {
@@ -7034,9 +7075,25 @@
             ],
             "nullable": true
           },
-          "udf": {
+          "metadata": {
             "type": "object",
-            "description": "Any user defined fields can be passed here.",
+            "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
+            "nullable": true
+          },
+          "connector_metadata": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/ConnectorMetadata"
+              }
+            ],
+            "nullable": true
+          },
+          "feature_metadata": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/FeatureMetadata"
+              }
+            ],
             "nullable": true
           }
         }
@@ -7220,11 +7277,6 @@
             ],
             "nullable": true
           },
-          "metadata": {
-            "type": "object",
-            "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
-            "nullable": true
-          },
           "order_details": {
             "type": "array",
             "items": {
@@ -7363,16 +7415,32 @@
             "description": "If true the payment can be retried with same or different payment method which means the confirm call can be made again.",
             "nullable": true
           },
-          "udf": {
-            "type": "object",
-            "description": "Any user defined fields can be passed here.",
-            "nullable": true
-          },
           "connector_transaction_id": {
             "type": "string",
             "description": "A unique identifier for a payment provided by the connector",
             "example": "993672945374576J",
             "nullable": true
+          },
+          "metadata": {
+            "type": "object",
+            "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.",
+            "nullable": true
+          },
+          "connector_metadata": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/ConnectorMetadata"
+              }
+            ],
+            "nullable": true
+          },
+          "feature_metadata": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/FeatureMetadata"
+              }
+            ],
+            "nullable": true
           }
         }
       },
@@ -8147,6 +8215,37 @@
           "propertyName": "wallet_name"
         }
       },
+      "SessionTokenInfo": {
+        "type": "object",
+        "required": [
+          "certificate",
+          "certificate_keys",
+          "merchant_identifier",
+          "display_name",
+          "initiative",
+          "initiative_context"
+        ],
+        "properties": {
+          "certificate": {
+            "type": "string"
+          },
+          "certificate_keys": {
+            "type": "string"
+          },
+          "merchant_identifier": {
+            "type": "string"
+          },
+          "display_name": {
+            "type": "string"
+          },
+          "initiative": {
+            "type": "string"
+          },
+          "initiative_context": {
+            "type": "string"
+          }
+        }
+      },
       "ThirdPartySdkSessionResponse": {
         "type": "object",
         "required": [