Bug: Add support to pass apple pay recurring details in the payment request



Whenever a customer makes an Applepay payment a unique network token called a DPAN (Device Primary Account Number) is created and stored securely on the customer’s Apple device. This token acts as the payment information for all purchases and keeps the raw card number safe from bad actors.

However, Apple Pay’s DPAN (Device Primary Account Number) may not be ideal for all subscription businesses, because it can result in involuntary churn.

Visa is making enhancements to network tokens to ensure their continued compatibility with follow-on transactions. Due to these changes, there is impact to a few use cases for Apple Pay recurring transactions. [Beginning July 30th, 2025, the current device generated Apple Pay network tokens will no longer be applicable for Standing Instruction transactions](https://support.visaacceptance.com/knowledgebase/knowledgearticle/?code=KA-04318).  Standing Instruction use cases constitute recurring, installments, or unscheduled credential on file token usages.

In order to add support apple pay MPAN recurring object needs to be passed to apple pay in the /sessions call.
diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json
index ee5654cfb6b..17849948516 100644
--- a/api-reference-v2/openapi_spec.json
+++ b/api-reference-v2/openapi_spec.json
@@ -3288,12 +3288,169 @@
               }
             ],
             "nullable": true
+          },
+          "recurring_payment_request": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/ApplePayRecurringPaymentRequest"
+              }
+            ],
+            "nullable": true
+          }
+        }
+      },
+      "ApplePayPaymentTiming": {
+        "type": "string",
+        "enum": [
+          "immediate",
+          "recurring"
+        ]
+      },
+      "ApplePayRecurringDetails": {
+        "type": "object",
+        "required": [
+          "payment_description",
+          "regular_billing",
+          "management_url"
+        ],
+        "properties": {
+          "payment_description": {
+            "type": "string",
+            "description": "A description of the recurring payment that Apple Pay displays to the user in the payment sheet"
+          },
+          "regular_billing": {
+            "$ref": "#/components/schemas/ApplePayRegularBillingDetails"
+          },
+          "billing_agreement": {
+            "type": "string",
+            "description": "A localized billing agreement that the payment sheet displays to the user before the user authorizes the payment",
+            "nullable": true
+          },
+          "management_url": {
+            "type": "string",
+            "description": "A URL to a web page where the user can update or delete the payment method for the recurring payment",
+            "example": "https://hyperswitch.io"
+          }
+        }
+      },
+      "ApplePayRecurringPaymentRequest": {
+        "type": "object",
+        "required": [
+          "payment_description",
+          "regular_billing",
+          "management_url"
+        ],
+        "properties": {
+          "payment_description": {
+            "type": "string",
+            "description": "A description of the recurring payment that Apple Pay displays to the user in the payment sheet"
+          },
+          "regular_billing": {
+            "$ref": "#/components/schemas/ApplePayRegularBillingRequest"
+          },
+          "billing_agreement": {
+            "type": "string",
+            "description": "A localized billing agreement that the payment sheet displays to the user before the user authorizes the payment",
+            "nullable": true
+          },
+          "management_url": {
+            "type": "string",
+            "description": "A URL to a web page where the user can update or delete the payment method for the recurring payment",
+            "example": "https://hyperswitch.io"
           }
         }
       },
       "ApplePayRedirectData": {
         "type": "object"
       },
+      "ApplePayRegularBillingDetails": {
+        "type": "object",
+        "required": [
+          "label"
+        ],
+        "properties": {
+          "label": {
+            "type": "string",
+            "description": "The label that Apple Pay displays to the user in the payment sheet with the recurring details"
+          },
+          "recurring_payment_start_date": {
+            "type": "string",
+            "format": "date-time",
+            "description": "The date of the first payment",
+            "example": "2023-09-10T23:59:59Z",
+            "nullable": true
+          },
+          "recurring_payment_end_date": {
+            "type": "string",
+            "format": "date-time",
+            "description": "The date of the final payment",
+            "example": "2023-09-10T23:59:59Z",
+            "nullable": true
+          },
+          "recurring_payment_interval_unit": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/RecurringPaymentIntervalUnit"
+              }
+            ],
+            "nullable": true
+          },
+          "recurring_payment_interval_count": {
+            "type": "integer",
+            "format": "int32",
+            "description": "The number of interval units that make up the total payment interval",
+            "nullable": true
+          }
+        }
+      },
+      "ApplePayRegularBillingRequest": {
+        "type": "object",
+        "required": [
+          "amount",
+          "label",
+          "payment_timing"
+        ],
+        "properties": {
+          "amount": {
+            "type": "string",
+            "description": "The amount of the recurring payment",
+            "example": "38.02"
+          },
+          "label": {
+            "type": "string",
+            "description": "The label that Apple Pay displays to the user in the payment sheet with the recurring details"
+          },
+          "payment_timing": {
+            "$ref": "#/components/schemas/ApplePayPaymentTiming"
+          },
+          "recurring_payment_start_date": {
+            "type": "string",
+            "format": "date-time",
+            "description": "The date of the first payment",
+            "nullable": true
+          },
+          "recurring_payment_end_date": {
+            "type": "string",
+            "format": "date-time",
+            "description": "The date of the final payment",
+            "nullable": true
+          },
+          "recurring_payment_interval_unit": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/RecurringPaymentIntervalUnit"
+              }
+            ],
+            "nullable": true
+          },
+          "recurring_payment_interval_count": {
+            "type": "integer",
+            "format": "int32",
+            "description": "The number of interval units that make up the total payment interval",
+            "nullable": true
+          }
+        }
+      },
       "ApplePaySessionResponse": {
         "oneOf": [
           {
@@ -8396,6 +8553,14 @@
             },
             "description": "Additional tags to be used for global search",
             "nullable": true
+          },
+          "apple_pay_recurring_details": {
+            "allOf": [
+              {
+                "$ref": "#/components/schemas/ApplePayRecurringDetails"
+              }
+            ],
+            "nullable": true
           }
         }
       },
@@ -18323,6 +18488,16 @@
           "propertyName": "type"
         }
       },
+      "RecurringPaymentIntervalUnit": {
+        "type": "string",
+        "enum": [
+          "year",
+          "month",
+          "day",
+          "hour",
+          "minute"
+        ]
+      },
       "RedirectResponse": {
         "type": "object",
         "properties": {
diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs
index 2464cdf62db..f0b59dfe375 100644
--- a/crates/api_models/src/payments.rs
+++ b/crates/api_models/src/payments.rs
@@ -6227,6 +6227,57 @@ pub struct ApplePayPaymentRequest {
     #[serde(skip_serializing_if = "Option::is_none")]
     /// The required shipping contacht fields for connector
     pub required_shipping_contact_fields: Option<ApplePayShippingContactFields>,
+    /// Recurring payment request for apple pay Merchant Token
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub recurring_payment_request: Option<ApplePayRecurringPaymentRequest>,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)]
+pub struct ApplePayRecurringPaymentRequest {
+    /// A description of the recurring payment that Apple Pay displays to the user in the payment sheet
+    pub payment_description: String,
+    /// The regular billing cycle for the recurring payment, including start and end dates, an interval, and an interval count
+    pub regular_billing: ApplePayRegularBillingRequest,
+    /// A localized billing agreement that the payment sheet displays to the user before the user authorizes the payment
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub billing_agreement: Option<String>,
+    /// A URL to a web page where the user can update or delete the payment method for the recurring payment
+    #[schema(value_type = String, example = "https://hyperswitch.io")]
+    pub management_url: common_utils::types::Url,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)]
+pub struct ApplePayRegularBillingRequest {
+    /// The amount of the recurring payment
+    #[schema(value_type = String, example = "38.02")]
+    pub amount: StringMajorUnit,
+    /// The label that Apple Pay displays to the user in the payment sheet with the recurring details
+    pub label: String,
+    /// The time that the payment occurs as part of a successful transaction
+    pub payment_timing: ApplePayPaymentTiming,
+    /// The date of the first payment
+    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(with = "common_utils::custom_serde::iso8601::option")]
+    pub recurring_payment_start_date: Option<PrimitiveDateTime>,
+    /// The date of the final payment
+    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(with = "common_utils::custom_serde::iso8601::option")]
+    pub recurring_payment_end_date: Option<PrimitiveDateTime>,
+    /// The amount of time — in calendar units, such as day, month, or year — that represents a fraction of the total payment interval
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub recurring_payment_interval_unit: Option<RecurringPaymentIntervalUnit>,
+    /// The number of interval units that make up the total payment interval
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub recurring_payment_interval_count: Option<i32>,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum ApplePayPaymentTiming {
+    /// A value that specifies that the payment occurs when the transaction is complete
+    Immediate,
+    /// A value that specifies that the payment occurs on a regular basis
+    Recurring,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema, serde::Deserialize)]
@@ -6504,6 +6555,49 @@ pub struct FeatureMetadata {
     /// Additional tags to be used for global search
     #[schema(value_type = Option<Vec<String>>)]
     pub search_tags: Option<Vec<HashedString<WithType>>>,
+    /// Recurring payment details required for apple pay Merchant Token
+    pub apple_pay_recurring_details: Option<ApplePayRecurringDetails>,
+}
+
+#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
+pub struct ApplePayRecurringDetails {
+    /// A description of the recurring payment that Apple Pay displays to the user in the payment sheet
+    pub payment_description: String,
+    /// The regular billing cycle for the recurring payment, including start and end dates, an interval, and an interval count
+    pub regular_billing: ApplePayRegularBillingDetails,
+    /// A localized billing agreement that the payment sheet displays to the user before the user authorizes the payment
+    pub billing_agreement: Option<String>,
+    /// A URL to a web page where the user can update or delete the payment method for the recurring payment
+    #[schema(value_type = String, example = "https://hyperswitch.io")]
+    pub management_url: common_utils::types::Url,
+}
+
+#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
+pub struct ApplePayRegularBillingDetails {
+    /// The label that Apple Pay displays to the user in the payment sheet with the recurring details
+    pub label: String,
+    /// The date of the first payment
+    #[schema(example = "2023-09-10T23:59:59Z")]
+    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
+    pub recurring_payment_start_date: Option<PrimitiveDateTime>,
+    /// The date of the final payment
+    #[schema(example = "2023-09-10T23:59:59Z")]
+    #[serde(default, with = "common_utils::custom_serde::iso8601::option")]
+    pub recurring_payment_end_date: Option<PrimitiveDateTime>,
+    /// The amount of time — in calendar units, such as day, month, or year — that represents a fraction of the total payment interval
+    pub recurring_payment_interval_unit: Option<RecurringPaymentIntervalUnit>,
+    /// The number of interval units that make up the total payment interval
+    pub recurring_payment_interval_count: Option<i32>,
+}
+
+#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum RecurringPaymentIntervalUnit {
+    Year,
+    Month,
+    Day,
+    Hour,
+    Minute,
 }
 
 ///frm message is an object sent inside the payments response...when frm is invoked, its value is Some(...), else its None
diff --git a/crates/diesel_models/src/types.rs b/crates/diesel_models/src/types.rs
index 94f1fa8d266..31a9672b910 100644
--- a/crates/diesel_models/src/types.rs
+++ b/crates/diesel_models/src/types.rs
@@ -44,8 +44,55 @@ pub struct FeatureMetadata {
     // TODO: Convert this to hashedstrings to avoid PII sensitive data
     /// Additional tags to be used for global search
     pub search_tags: Option<Vec<HashedString<WithType>>>,
+    /// Recurring payment details required for apple pay Merchant Token
+    pub apple_pay_recurring_details: Option<ApplePayRecurringDetails>,
 }
-impl masking::SerializableSecret for FeatureMetadata {}
+
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, FromSqlRow, AsExpression)]
+#[diesel(sql_type = Json)]
+pub struct ApplePayRecurringDetails {
+    /// A description of the recurring payment that Apple Pay displays to the user in the payment sheet
+    pub payment_description: String,
+    /// The regular billing cycle for the recurring payment, including start and end dates, an interval, and an interval count
+    pub regular_billing: ApplePayRegularBillingDetails,
+    /// A localized billing agreement that the payment sheet displays to the user before the user authorizes the payment
+    pub billing_agreement: Option<String>,
+    /// A URL to a web page where the user can update or delete the payment method for the recurring payment
+    pub management_url: common_utils::types::Url,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, FromSqlRow, AsExpression)]
+#[diesel(sql_type = Json)]
+pub struct ApplePayRegularBillingDetails {
+    /// The label that Apple Pay displays to the user in the payment sheet with the recurring details
+    pub label: String,
+    /// The date of the first payment
+    #[serde(with = "common_utils::custom_serde::iso8601::option")]
+    pub recurring_payment_start_date: Option<time::PrimitiveDateTime>,
+    /// The date of the final payment
+    #[serde(with = "common_utils::custom_serde::iso8601::option")]
+    pub recurring_payment_end_date: Option<time::PrimitiveDateTime>,
+    /// The amount of time — in calendar units, such as day, month, or year — that represents a fraction of the total payment interval
+    pub recurring_payment_interval_unit: Option<RecurringPaymentIntervalUnit>,
+    /// The number of interval units that make up the total payment interval
+    pub recurring_payment_interval_count: Option<i32>,
+}
+
+#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, FromSqlRow, AsExpression)]
+#[diesel(sql_type = Json)]
+#[serde(rename_all = "snake_case")]
+pub enum RecurringPaymentIntervalUnit {
+    Year,
+    Month,
+    Day,
+    Hour,
+    Minute,
+}
+
+common_utils::impl_to_sql_from_sql_json!(ApplePayRecurringDetails);
+common_utils::impl_to_sql_from_sql_json!(ApplePayRegularBillingDetails);
+common_utils::impl_to_sql_from_sql_json!(RecurringPaymentIntervalUnit);
+
 common_utils::impl_to_sql_from_sql_json!(FeatureMetadata);
 
 #[derive(Default, Debug, Eq, PartialEq, Deserialize, Serialize, Clone)]
diff --git a/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs b/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs
index 2e4503c3469..7970b1b1d42 100644
--- a/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs
@@ -555,6 +555,7 @@ impl
                         merchant_identifier: Some(session_token_data.merchant_identifier),
                         required_billing_contact_fields: None,
                         required_shipping_contact_fields: None,
+                        recurring_payment_request: None,
                     }),
                     connector: "bluesnap".to_string(),
                     delayed_session_token: false,
diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs
index 0e8722644bd..4b78fd3c788 100644
--- a/crates/hyperswitch_domain_models/src/lib.rs
+++ b/crates/hyperswitch_domain_models/src/lib.rs
@@ -32,10 +32,16 @@ pub trait PayoutAttemptInterface {}
 pub trait PayoutsInterface {}
 
 use api_models::payments::{
+    ApplePayRecurringDetails as ApiApplePayRecurringDetails,
+    ApplePayRegularBillingDetails as ApiApplePayRegularBillingDetails,
     FeatureMetadata as ApiFeatureMetadata, OrderDetailsWithAmount as ApiOrderDetailsWithAmount,
+    RecurringPaymentIntervalUnit as ApiRecurringPaymentIntervalUnit,
     RedirectResponse as ApiRedirectResponse,
 };
-use diesel_models::types::{FeatureMetadata, OrderDetailsWithAmount, RedirectResponse};
+use diesel_models::types::{
+    ApplePayRecurringDetails, ApplePayRegularBillingDetails, FeatureMetadata,
+    OrderDetailsWithAmount, RecurringPaymentIntervalUnit, RedirectResponse,
+};
 
 #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
 pub enum RemoteStorageObject<T: ForeignIDRef> {
@@ -75,10 +81,13 @@ impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
         let ApiFeatureMetadata {
             redirect_response,
             search_tags,
+            apple_pay_recurring_details,
         } = from;
         Self {
             redirect_response: redirect_response.map(RedirectResponse::convert_from),
             search_tags,
+            apple_pay_recurring_details: apple_pay_recurring_details
+                .map(ApplePayRecurringDetails::convert_from),
         }
     }
 
@@ -86,11 +95,14 @@ impl ApiModelToDieselModelConvertor<ApiFeatureMetadata> for FeatureMetadata {
         let Self {
             redirect_response,
             search_tags,
+            apple_pay_recurring_details,
         } = self;
         ApiFeatureMetadata {
             redirect_response: redirect_response
                 .map(|redirect_response| redirect_response.convert_back()),
             search_tags,
+            apple_pay_recurring_details: apple_pay_recurring_details
+                .map(|value| value.convert_back()),
         }
     }
 }
@@ -119,6 +131,77 @@ impl ApiModelToDieselModelConvertor<ApiRedirectResponse> for RedirectResponse {
     }
 }
 
+impl ApiModelToDieselModelConvertor<ApiRecurringPaymentIntervalUnit>
+    for RecurringPaymentIntervalUnit
+{
+    fn convert_from(from: ApiRecurringPaymentIntervalUnit) -> Self {
+        match from {
+            ApiRecurringPaymentIntervalUnit::Year => Self::Year,
+            ApiRecurringPaymentIntervalUnit::Month => Self::Month,
+            ApiRecurringPaymentIntervalUnit::Day => Self::Day,
+            ApiRecurringPaymentIntervalUnit::Hour => Self::Hour,
+            ApiRecurringPaymentIntervalUnit::Minute => Self::Minute,
+        }
+    }
+    fn convert_back(self) -> ApiRecurringPaymentIntervalUnit {
+        match self {
+            Self::Year => ApiRecurringPaymentIntervalUnit::Year,
+            Self::Month => ApiRecurringPaymentIntervalUnit::Month,
+            Self::Day => ApiRecurringPaymentIntervalUnit::Day,
+            Self::Hour => ApiRecurringPaymentIntervalUnit::Hour,
+            Self::Minute => ApiRecurringPaymentIntervalUnit::Minute,
+        }
+    }
+}
+
+impl ApiModelToDieselModelConvertor<ApiApplePayRegularBillingDetails>
+    for ApplePayRegularBillingDetails
+{
+    fn convert_from(from: ApiApplePayRegularBillingDetails) -> Self {
+        Self {
+            label: from.label,
+            recurring_payment_start_date: from.recurring_payment_start_date,
+            recurring_payment_end_date: from.recurring_payment_end_date,
+            recurring_payment_interval_unit: from
+                .recurring_payment_interval_unit
+                .map(RecurringPaymentIntervalUnit::convert_from),
+            recurring_payment_interval_count: from.recurring_payment_interval_count,
+        }
+    }
+
+    fn convert_back(self) -> ApiApplePayRegularBillingDetails {
+        ApiApplePayRegularBillingDetails {
+            label: self.label,
+            recurring_payment_start_date: self.recurring_payment_start_date,
+            recurring_payment_end_date: self.recurring_payment_end_date,
+            recurring_payment_interval_unit: self
+                .recurring_payment_interval_unit
+                .map(|value| value.convert_back()),
+            recurring_payment_interval_count: self.recurring_payment_interval_count,
+        }
+    }
+}
+
+impl ApiModelToDieselModelConvertor<ApiApplePayRecurringDetails> for ApplePayRecurringDetails {
+    fn convert_from(from: ApiApplePayRecurringDetails) -> Self {
+        Self {
+            payment_description: from.payment_description,
+            regular_billing: ApplePayRegularBillingDetails::convert_from(from.regular_billing),
+            billing_agreement: from.billing_agreement,
+            management_url: from.management_url,
+        }
+    }
+
+    fn convert_back(self) -> ApiApplePayRecurringDetails {
+        ApiApplePayRecurringDetails {
+            payment_description: self.payment_description,
+            regular_billing: self.regular_billing.convert_back(),
+            billing_agreement: self.billing_agreement,
+            management_url: self.management_url,
+        }
+    }
+}
+
 impl ApiModelToDieselModelConvertor<ApiOrderDetailsWithAmount> for OrderDetailsWithAmount {
     fn convert_from(from: ApiOrderDetailsWithAmount) -> Self {
         let ApiOrderDetailsWithAmount {
diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs
index 2f68b481d88..210047f8e1f 100644
--- a/crates/hyperswitch_domain_models/src/router_request_types.rs
+++ b/crates/hyperswitch_domain_models/src/router_request_types.rs
@@ -830,6 +830,7 @@ pub struct PaymentsSessionData {
     pub email: Option<pii::Email>,
     // Minor Unit amount for amount frame work
     pub minor_amount: MinorUnit,
+    pub apple_pay_recurring_details: Option<api_models::payments::ApplePayRecurringPaymentRequest>,
 }
 
 #[derive(Debug, Clone, Default)]
diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs
index 7ad5645e75a..5a3fb3ac649 100644
--- a/crates/openapi/src/openapi.rs
+++ b/crates/openapi/src/openapi.rs
@@ -416,6 +416,12 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::ApplePayPaymentRequest,
         api_models::payments::ApplePayBillingContactFields,
         api_models::payments::ApplePayShippingContactFields,
+        api_models::payments::ApplePayRecurringPaymentRequest,
+        api_models::payments::ApplePayRegularBillingRequest,
+        api_models::payments::ApplePayPaymentTiming,
+        api_models::payments::RecurringPaymentIntervalUnit,
+        api_models::payments::ApplePayRecurringDetails,
+        api_models::payments::ApplePayRegularBillingDetails,
         api_models::payments::ApplePayAddressParameters,
         api_models::payments::AmountInfo,
         api_models::payments::ClickToPaySessionResponse,
diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs
index 5a5454e2505..f197f843afb 100644
--- a/crates/openapi/src/openapi_v2.rs
+++ b/crates/openapi/src/openapi_v2.rs
@@ -380,6 +380,12 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::ApplePayBillingContactFields,
         api_models::payments::ApplePayShippingContactFields,
         api_models::payments::ApplePayAddressParameters,
+        api_models::payments::ApplePayRecurringPaymentRequest,
+        api_models::payments::ApplePayRegularBillingRequest,
+        api_models::payments::ApplePayPaymentTiming,
+        api_models::payments::RecurringPaymentIntervalUnit,
+        api_models::payments::ApplePayRecurringDetails,
+        api_models::payments::ApplePayRegularBillingDetails,
         api_models::payments::AmountInfo,
         api_models::payments::GooglePayWalletData,
         api_models::payments::PayPalWalletData,
diff --git a/crates/router/src/connector/payme/transformers.rs b/crates/router/src/connector/payme/transformers.rs
index 7b6b67c8408..0e88ae23665 100644
--- a/crates/router/src/connector/payme/transformers.rs
+++ b/crates/router/src/connector/payme/transformers.rs
@@ -579,6 +579,7 @@ impl<F>
                                     merchant_identifier: None,
                                     required_billing_contact_fields: None,
                                     required_shipping_contact_fields: None,
+                                    recurring_payment_request: None,
                                 },
                             ),
                             connector: "payme".to_string(),
diff --git a/crates/router/src/connector/trustpay/transformers.rs b/crates/router/src/connector/trustpay/transformers.rs
index dafca256529..c20cc1aeb3a 100644
--- a/crates/router/src/connector/trustpay/transformers.rs
+++ b/crates/router/src/connector/trustpay/transformers.rs
@@ -1231,6 +1231,7 @@ pub fn get_apple_pay_session<F, T>(
                         merchant_identifier: None,
                         required_billing_contact_fields: None,
                         required_shipping_contact_fields: None,
+                        recurring_payment_request: None,
                     }),
                     connector: "trustpay".to_string(),
                     delayed_session_token: true,
diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs
index e8a591437de..7466b638922 100644
--- a/crates/router/src/core/payments.rs
+++ b/crates/router/src/core/payments.rs
@@ -1769,6 +1769,7 @@ impl PaymentRedirectFlow for PaymentRedirectCompleteAuthorize {
                     json_payload: Some(req.json_payload.unwrap_or(serde_json::json!({})).into()),
                 }),
                 search_tags: None,
+                apple_pay_recurring_details: None,
             }),
             ..Default::default()
         };
@@ -2230,6 +2231,7 @@ impl PaymentRedirectFlow for PaymentAuthenticateCompleteAuthorize {
                         ),
                     }),
                     search_tags: None,
+                    apple_pay_recurring_details: None,
                 }),
                 ..Default::default()
             };
diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs
index 464781f3d7c..1e3432220ac 100644
--- a/crates/router/src/core/payments/flows/session_flow.rs
+++ b/crates/router/src/core/payments/flows/session_flow.rs
@@ -715,6 +715,7 @@ fn get_apple_pay_payment_request(
         merchant_identifier: Some(merchant_identifier.to_string()),
         required_billing_contact_fields,
         required_shipping_contact_fields,
+        recurring_payment_request: session_data.apple_pay_recurring_details,
     };
     Ok(applepay_payment_request)
 }
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index 92486320cde..f48dd6915c9 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -8,7 +8,10 @@ use common_enums::{Currency, RequestIncrementalAuthorization};
 use common_utils::{
     consts::X_HS_LATENCY,
     fp_utils, pii,
-    types::{self as common_utils_type, AmountConvertor, MinorUnit, StringMajorUnitForConnector},
+    types::{
+        self as common_utils_type, AmountConvertor, MinorUnit, StringMajorUnit,
+        StringMajorUnitForConnector,
+    },
 };
 use diesel_models::{
     ephemeral_key,
@@ -562,6 +565,25 @@ pub async fn construct_payment_router_data_for_sdk_session<'a>(
                 .map(|order_detail| order_detail.expose())
                 .collect()
         });
+    let required_amount_type = StringMajorUnitForConnector;
+
+    let apple_pay_amount = required_amount_type
+        .convert(
+            payment_data.payment_intent.amount_details.order_amount,
+            payment_data.payment_intent.amount_details.currency,
+        )
+        .change_context(errors::ApiErrorResponse::PreconditionFailed {
+            message: "Failed to convert amount to string major unit for applePay".to_string(),
+        })?;
+
+    let apple_pay_recurring_details = payment_data
+        .payment_intent
+        .feature_metadata
+        .and_then(|feature_metadata| feature_metadata.apple_pay_recurring_details)
+        .map(|apple_pay_recurring_details| {
+            ForeignInto::foreign_into((apple_pay_recurring_details, apple_pay_amount))
+        });
+
     // TODO: few fields are repeated in both routerdata and request
     let request = types::PaymentsSessionData {
         amount: payment_data
@@ -585,6 +607,7 @@ pub async fn construct_payment_router_data_for_sdk_session<'a>(
         order_details,
         email,
         minor_amount: payment_data.payment_intent.amount_details.order_amount,
+        apple_pay_recurring_details,
     };
 
     // TODO: evaluate the fields in router data, if they are required or not
@@ -3097,6 +3120,22 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsSessionD
         // net_amount here would include amount, surcharge_amount and shipping_cost
         let net_amount = amount + surcharge_amount + shipping_cost;
 
+        let required_amount_type = StringMajorUnitForConnector;
+
+        let apple_pay_amount = required_amount_type
+            .convert(net_amount, payment_data.currency)
+            .change_context(errors::ApiErrorResponse::PreconditionFailed {
+                message: "Failed to convert amount to string major unit for applePay".to_string(),
+            })?;
+
+        let apple_pay_recurring_details = payment_data
+            .payment_intent
+            .feature_metadata
+            .and_then(|feature_metadata| feature_metadata.apple_pay_recurring_details)
+            .map(|apple_pay_recurring_details| {
+                ForeignInto::foreign_into((apple_pay_recurring_details, apple_pay_amount))
+            });
+
         Ok(Self {
             amount: amount.get_amount_as_i64(), //need to change once we move to connector module
             minor_amount: amount,
@@ -3112,6 +3151,7 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsSessionD
             order_details,
             surcharge_details: payment_data.surcharge_details,
             email: payment_data.email,
+            apple_pay_recurring_details,
         })
     }
 }
@@ -3158,6 +3198,29 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsSessionD
         // net_amount here would include amount, surcharge_amount and shipping_cost
         let net_amount = amount + surcharge_amount + shipping_cost;
 
+        let required_amount_type = StringMajorUnitForConnector;
+
+        let apple_pay_amount = required_amount_type
+            .convert(net_amount, payment_data.currency)
+            .change_context(errors::ApiErrorResponse::PreconditionFailed {
+                message: "Failed to convert amount to string major unit for applePay".to_string(),
+            })?;
+
+        let apple_pay_recurring_details = payment_data
+            .payment_intent
+            .feature_metadata
+            .map(|feature_metadata| {
+                feature_metadata
+                    .parse_value::<diesel_models::types::FeatureMetadata>("FeatureMetadata")
+                    .change_context(errors::ApiErrorResponse::InternalServerError)
+                    .attach_printable("Failed parsing FeatureMetadata")
+            })
+            .transpose()?
+            .and_then(|feature_metadata| feature_metadata.apple_pay_recurring_details)
+            .map(|apple_pay_recurring_details| {
+                ForeignFrom::foreign_from((apple_pay_recurring_details, apple_pay_amount))
+            });
+
         Ok(Self {
             amount: net_amount.get_amount_as_i64(), //need to change once we move to connector module
             minor_amount: amount,
@@ -3173,10 +3236,99 @@ impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::PaymentsSessionD
             order_details,
             email: payment_data.email,
             surcharge_details: payment_data.surcharge_details,
+            apple_pay_recurring_details,
         })
     }
 }
 
+impl
+    ForeignFrom<(
+        diesel_models::types::ApplePayRecurringDetails,
+        StringMajorUnit,
+    )> for api_models::payments::ApplePayRecurringPaymentRequest
+{
+    fn foreign_from(
+        (apple_pay_recurring_details, net_amount): (
+            diesel_models::types::ApplePayRecurringDetails,
+            StringMajorUnit,
+        ),
+    ) -> Self {
+        Self {
+            payment_description: apple_pay_recurring_details.payment_description,
+            regular_billing: api_models::payments::ApplePayRegularBillingRequest {
+                amount: net_amount,
+                label: apple_pay_recurring_details.regular_billing.label,
+                payment_timing: api_models::payments::ApplePayPaymentTiming::Recurring,
+                recurring_payment_start_date: apple_pay_recurring_details
+                    .regular_billing
+                    .recurring_payment_start_date,
+                recurring_payment_end_date: apple_pay_recurring_details
+                    .regular_billing
+                    .recurring_payment_end_date,
+                recurring_payment_interval_unit: apple_pay_recurring_details
+                    .regular_billing
+                    .recurring_payment_interval_unit
+                    .map(ForeignFrom::foreign_from),
+                recurring_payment_interval_count: apple_pay_recurring_details
+                    .regular_billing
+                    .recurring_payment_interval_count,
+            },
+            billing_agreement: apple_pay_recurring_details.billing_agreement,
+            management_url: apple_pay_recurring_details.management_url,
+        }
+    }
+}
+
+impl ForeignFrom<diesel_models::types::ApplePayRecurringDetails>
+    for api_models::payments::ApplePayRecurringDetails
+{
+    fn foreign_from(
+        apple_pay_recurring_details: diesel_models::types::ApplePayRecurringDetails,
+    ) -> Self {
+        Self {
+            payment_description: apple_pay_recurring_details.payment_description,
+            regular_billing: ForeignFrom::foreign_from(apple_pay_recurring_details.regular_billing),
+            billing_agreement: apple_pay_recurring_details.billing_agreement,
+            management_url: apple_pay_recurring_details.management_url,
+        }
+    }
+}
+
+impl ForeignFrom<diesel_models::types::ApplePayRegularBillingDetails>
+    for api_models::payments::ApplePayRegularBillingDetails
+{
+    fn foreign_from(
+        apple_pay_regular_billing: diesel_models::types::ApplePayRegularBillingDetails,
+    ) -> Self {
+        Self {
+            label: apple_pay_regular_billing.label,
+            recurring_payment_start_date: apple_pay_regular_billing.recurring_payment_start_date,
+            recurring_payment_end_date: apple_pay_regular_billing.recurring_payment_end_date,
+            recurring_payment_interval_unit: apple_pay_regular_billing
+                .recurring_payment_interval_unit
+                .map(ForeignFrom::foreign_from),
+            recurring_payment_interval_count: apple_pay_regular_billing
+                .recurring_payment_interval_count,
+        }
+    }
+}
+
+impl ForeignFrom<diesel_models::types::RecurringPaymentIntervalUnit>
+    for api_models::payments::RecurringPaymentIntervalUnit
+{
+    fn foreign_from(
+        apple_pay_recurring_payment_interval_unit: diesel_models::types::RecurringPaymentIntervalUnit,
+    ) -> Self {
+        match apple_pay_recurring_payment_interval_unit {
+            diesel_models::types::RecurringPaymentIntervalUnit::Day => Self::Day,
+            diesel_models::types::RecurringPaymentIntervalUnit::Month => Self::Month,
+            diesel_models::types::RecurringPaymentIntervalUnit::Year => Self::Year,
+            diesel_models::types::RecurringPaymentIntervalUnit::Hour => Self::Hour,
+            diesel_models::types::RecurringPaymentIntervalUnit::Minute => Self::Minute,
+        }
+    }
+}
+
 #[cfg(feature = "v1")]
 impl<F: Clone> TryFrom<PaymentAdditionalData<'_, F>> for types::SetupMandateRequestData {
     type Error = error_stack::Report<errors::ApiErrorResponse>;

## 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 -->
Whenever a customer makes an Applepay payment a unique network token called a DPAN (Device Primary Account Number) is created and stored securely on the customer’s Apple device. This token acts as the payment information for all purchases and keeps the raw card number safe from bad actors.

However, Apple Pay’s DPAN (Device Primary Account Number) may not be ideal for all subscription businesses, because it can result in involuntary churn.

Visa is making enhancements to network tokens to ensure their continued compatibility with follow-on transactions. Due to these changes, there is impact to a few use cases for Apple Pay recurring transactions. [Beginning July 30th, 2025, the current device generated Apple Pay network tokens will no longer be applicable for Standing Instruction transactions](https://support.visaacceptance.com/knowledgebase/knowledgearticle/?code=KA-04318). Standing Instruction use cases constitute recurring, installments, or unscheduled credential on file token usages.

In order to add support apple pay MPAN recurring object needs to be passed to apple pay in the /sessions call.

This adds supports to accept the `ApplePayRecurringPaymentRequest` in the `FeatureMetadata` for the payment request. Based the request details passed the appropriate recurring details will be displayed in the apple pay modal during the customer authentication.

### Additional Changes

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

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

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


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

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


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
-> Create a merchant connector account with applepay metadata to decrypt the apple pay token at hyperswitch
-> Create a payment by passing `apple_pay_recurring_details`
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_9ZJ9etprVKsDp4YNdgBxXsiq8bvL2ksaGVHJFTrBawKCd0ylxJb4hN8IAct6DTDa' \
--data-raw '{
    "amount": 6100,
    "currency": "USD",
    "confirm": false,
    "business_country": "US",
    "business_label": "default",
    "amount_to_capture": 6100,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "return_url": "https://google.com",
    "email": "something@gmail.com",
    "setup_future_usage": "off_session",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "customer_id": "1733817585",
    "feature_metadata": {
        "apple_pay_recurring_details": {
            "payment_description": "this is the apple pay recurring payment",
            "regular_billing": {
                "amount": 10,
                "label": "pay to hyperswitch'\''s merchant",
                "recurring_payment_start_date": "2027-09-10T10:11:12.000Z",
                "recurring_payment_end_date": "2027-09-10T10:11:12.000Z",
                "recurring_payment_interval_unit": "year",
                "recurring_payment_interval_count": 1
            },
            "billing_agreement": "billing starts from the above mentioned start date",
            "management_url": "https://applepaydemo.apple.com"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    }
}'
```
```
{
    "payment_id": "pay_VMgqfeubSlEFDvzkl0uf",
    "merchant_id": "merchant_1733816953",
    "status": "requires_payment_method",
    "amount": 6100,
    "net_amount": 6100,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "pay_VMgqfeubSlEFDvzkl0uf_secret_ewyd5zHoVQckfAXdzF9V",
    "created": "2024-12-10T07:59:03.063Z",
    "currency": "USD",
    "customer_id": "1733817543",
    "customer": {
        "id": "1733817543",
        "name": "Joseph Doe",
        "email": "something@gmail.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": null,
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": null,
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": "US",
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "1733817543",
        "created_at": 1733817543,
        "expires": 1733821143,
        "secret": "epk_8c23ceac435c470ea279d9ea0e1659ca"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": {
            "payment_description": "this is the apple pay recurring payment",
            "regular_billing": {
                "amount": 10,
                "label": "pay to hyperswitch's merchant",
                "recurring_payment_start_date": "2027-09-10T10:11:12.000Z",
                "recurring_payment_end_date": "2027-09-10T10:11:12.000Z",
                "recurring_payment_interval_unit": "year",
                "recurring_payment_interval_count": 1
            },
            "billing_agreement": "billing starts from the above mentioned start date",
            "management_url": "https://applepaydemo.apple.com"
        }
    },
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_JcYIJy9B8xXAnFuBEdhc",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-12-10T08:14:03.063Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-12-10T07:59:03.107Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}
```
-> session call
```
curl --location 'http://localhost:8080/payments/session_tokens' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_4bc816e9fc4549d6b50106976df7b29b' \
--data '{
    "payment_id": "pay_VMgqfeubSlEFDvzkl0uf",
    "wallets": [],
    "client_secret": "pay_VMgqfeubSlEFDvzkl0uf_secret_ewyd5zHoVQckfAXdzF9V"
}'
```
```
{
    "payment_id": "pay_VMgqfeubSlEFDvzkl0uf",
    "client_secret": "pay_VMgqfeubSlEFDvzkl0uf_secret_ewyd5zHoVQckfAXdzF9V",
    "session_token": [
        {
            "wallet_name": "google_pay",
            "merchant_info": {
                "merchant_name": "Stripe"
            },
            "shipping_address_required": false,
            "email_required": false,
            "shipping_address_parameters": {
                "phone_number_required": false
            },
            "allowed_payment_methods": [
                {
                    "type": "CARD",
                    "parameters": {
                        "allowed_auth_methods": [
                            "PAN_ONLY",
                            "CRYPTOGRAM_3DS"
                        ],
                        "allowed_card_networks": [
                            "AMEX",
                            "DISCOVER",
                            "INTERAC",
                            "JCB",
                            "MASTERCARD",
                            "VISA"
                        ],
                        "billing_address_required": false
                    },
                    "tokenization_specification": {
                        "type": "PAYMENT_GATEWAY",
                        "parameters": {
                            "gateway": "stripe",
                            "stripe:version": "2018-10-31",
                            "stripe:publishableKey": "pk_test_51Msk2GAGHc77EJXX78h549SX2uaOnEkUYqBfjcoD05PIpAnDkYxMn8nQ4d19im85NQuX4Z6WDyHaUw2fFTPBWsIY00Wa7oNerO"
                        }
                    }
                }
            ],
            "transaction_info": {
                "country_code": "US",
                "currency_code": "USD",
                "total_price_status": "Final",
                "total_price": "61.00"
            },
            "delayed_session_token": false,
            "connector": "cybersource",
            "sdk_next_action": {
                "next_action": "confirm"
            },
            "secrets": null
        },
        {
            "wallet_name": "samsung_pay",
            "version": "2",
            "service_id": "49400558c67f4a97b3925f",
            "order_number": "pay-VMgqfeubSlEFDvzkl0uf",
            "merchant": {
                "name": "Hyperswitch",
                "url": null,
                "country_code": "IN"
            },
            "amount": {
                "option": "FORMAT_TOTAL_PRICE_ONLY",
                "currency_code": "USD",
                "total": "61.00"
            },
            "protocol": "PROTOCOL3DS",
            "allowed_brands": [
                "visa",
                "masterCard",
                "amex",
                "discover"
            ]
        },
        {
            "wallet_name": "apple_pay",
            "session_token_data": {
                "epoch_timestamp": 1733817642366,
                "expires_at": 1733821242366,
                "merchant_session_identifier": "SSH9848925D8DD4473D8EA96E628A9F20C0_A0E617ED4A56A343E07C6E1255BD4098423B3A8E1243236462D07B14B4A0F7C3",
                "nonce": "ebdd4037",
                "merchant_identifier": "6ACD34193A900BA07E215155E3647CF4759340CF486BABAEE6C0840F9267AB10",
                "domain_name": "debuglab.basilisk-char.ts.net",
                "display_name": "Zurich Insurance (non-PROD)",
                "signature": "308006092a864886f70d010702a0803080020101310d300b0609608648016503040201308006092a864886f70d0107010000a080308203e330820388a003020102020816634c8b0e305717300a06082a8648ce3d040302307a312e302c06035504030c254170706c65204170706c69636174696f6e20496e746567726174696f6e204341202d20473331263024060355040b0c1d4170706c652043657274696669636174696f6e20417574686f7269747931133011060355040a0c0a4170706c6520496e632e310b3009060355040613025553301e170d3234303432393137343732375a170d3239303432383137343732365a305f3125302306035504030c1c6563632d736d702d62726f6b65722d7369676e5f5543342d50524f4431143012060355040b0c0b694f532053797374656d7331133011060355040a0c0a4170706c6520496e632e310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d03010703420004c21577edebd6c7b2218f68dd7090a1218dc7b0bd6f2c283d846095d94af4a5411b83420ed811f3407e83331f1c54c3f7eb3220d6bad5d4eff49289893e7c0f13a38202113082020d300c0603551d130101ff04023000301f0603551d2304183016801423f249c44f93e4ef27e6c4f6286c3fa2bbfd2e4b304506082b0601050507010104393037303506082b060105050730018629687474703a2f2f6f6373702e6170706c652e636f6d2f6f63737030342d6170706c65616963613330323082011d0603551d2004820114308201103082010c06092a864886f7636405013081fe3081c306082b060105050702023081b60c81b352656c69616e6365206f6e207468697320636572746966696361746520627920616e7920706172747920617373756d657320616363657074616e6365206f6620746865207468656e206170706c696361626c65207374616e64617264207465726d7320616e6420636f6e646974696f6e73206f66207573652c20636572746966696361746520706f6c69637920616e642063657274696669636174696f6e2070726163746963652073746174656d656e74732e303606082b06010505070201162a687474703a2f2f7777772e6170706c652e636f6d2f6365727469666963617465617574686f726974792f30340603551d1f042d302b3029a027a0258623687474703a2f2f63726c2e6170706c652e636f6d2f6170706c6561696361332e63726c301d0603551d0e041604149457db6fd57481868989762f7e578507e79b5824300e0603551d0f0101ff040403020780300f06092a864886f76364061d04020500300a06082a8648ce3d0403020349003046022100c6f023cb2614bb303888a162983e1a93f1056f50fa78cdb9ba4ca241cc14e25e022100be3cd0dfd16247f6494475380e9d44c228a10890a3a1dc724b8b4cb8889818bc308202ee30820275a0030201020208496d2fbf3a98da97300a06082a8648ce3d0403023067311b301906035504030c124170706c6520526f6f74204341202d20473331263024060355040b0c1d4170706c652043657274696669636174696f6e20417574686f7269747931133011060355040a0c0a4170706c6520496e632e310b3009060355040613025553301e170d3134303530363233343633305a170d3239303530363233343633305a307a312e302c06035504030c254170706c65204170706c69636174696f6e20496e746567726174696f6e204341202d20473331263024060355040b0c1d4170706c652043657274696669636174696f6e20417574686f7269747931133011060355040a0c0a4170706c6520496e632e310b30090603550406130255533059301306072a8648ce3d020106082a8648ce3d03010703420004f017118419d76485d51a5e25810776e880a2efde7bae4de08dfc4b93e13356d5665b35ae22d097760d224e7bba08fd7617ce88cb76bb6670bec8e82984ff5445a381f73081f4304606082b06010505070101043a3038303606082b06010505073001862a687474703a2f2f6f6373702e6170706c652e636f6d2f6f63737030342d6170706c65726f6f7463616733301d0603551d0e0416041423f249c44f93e4ef27e6c4f6286c3fa2bbfd2e4b300f0603551d130101ff040530030101ff301f0603551d23041830168014bbb0dea15833889aa48a99debebdebafdacb24ab30370603551d1f0430302e302ca02aa0288626687474703a2f2f63726c2e6170706c652e636f6d2f6170706c65726f6f74636167332e63726c300e0603551d0f0101ff0404030201063010060a2a864886f7636406020e04020500300a06082a8648ce3d040302036700306402303acf7283511699b186fb35c356ca62bff417edd90f754da28ebef19c815e42b789f898f79b599f98d5410d8f9de9c2fe0230322dd54421b0a305776c5df3383b9067fd177c2c216d964fc6726982126f54f87a7d1b99cb9b0989216106990f09921d00003182018930820185020101308186307a312e302c06035504030c254170706c65204170706c69636174696f6e20496e746567726174696f6e204341202d20473331263024060355040b0c1d4170706c652043657274696669636174696f6e20417574686f7269747931133011060355040a0c0a4170706c6520496e632e310b3009060355040613025553020816634c8b0e305717300b0609608648016503040201a08193301806092a864886f70d010903310b06092a864886f70d010701301c06092a864886f70d010905310f170d3234313231303038303034325a302806092a864886f70d010934311b3019300b0609608648016503040201a10a06082a8648ce3d040302302f06092a864886f70d01090431220420ddd14d539103e445be353bf622995c58155b83740ac408582cfd95adffe59ccb300a06082a8648ce3d04030204483046022100a7071bc77f59318dc772a5e7e8a1270262a56887b019b2f449735169e2eebdf8022100c0682381a1d93da7cfa6928896cde5a58efec957855d82476531135bc359c04f000000000000",
                "operational_analytics_identifier": "Zurich Insurance (non-PROD):6ACD34193A900BA07E215155E3647CF4759340CF486BABAEE6C0840F9267AB10",
                "retries": 0,
                "psp_id": "6ACD34193A900BA07E215155E3647CF4759340CF486BABAEE6C0840F9267AB10"
            },
            "payment_request_data": {
                "country_code": "AU",
                "currency_code": "USD",
                "total": {
                    "label": "applepay",
                    "type": "final",
                    "amount": "61.00"
                },
                "merchant_capabilities": [
                    "supports3DS"
                ],
                "supported_networks": [
                    "visa",
                    "masterCard",
                    "amex",
                    "discover"
                ],
                "merchant_identifier": "merchant.sandbox.hyperswitch",
                "recurring_payment_request": {
                    "payment_description": "this is the apple pay recurring payment",
                    "regular_billing": {
                        "amount": "10",
                        "label": "pay to hyperswitch's merchant",
                        "payment_timing": "recurring",
                        "recurring_payment_start_date": "2027-09-10T10:11:12.000Z",
                        "recurring_payment_end_date": "2027-09-10T10:11:12.000Z",
                        "recurring_payment_interval_unit": "year",
                        "recurring_payment_interval_count": 1
                    },
                    "billing_agreement": "billing starts from the above mentioned start date",
                    "management_url": "https://applepaydemo.apple.com"
                }
            },
            "connector": "cybersource",
            "delayed_session_token": false,
            "sdk_next_action": {
                "next_action": "confirm"
            },
            "connector_reference_id": null,
            "connector_sdk_public_key": null,
            "connector_merchant_id": null
        }
    ]
}
```
-> Confirm the payment with the token
```
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_9ZJ9etprVKsDp4YNdgBxXsiq8bvL2ksaGVHJFTrBawKCd0ylxJb4hN8IAct6DTDa' \
--data-raw '{
    "amount": 650,
    "currency": "USD",
    "confirm": true,
    "business_country": "US",
    "business_label": "default",
    "amount_to_capture": 650,
    "customer_id": "cu_1733817737",
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "authentication_type": "no_three_ds",
    "return_url": "https://google.com",
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "Its my first payment request",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "payment_method": "wallet",
    "payment_method_type": "apple_pay",
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "payment_method_data": {
        "wallet": {
            "apple_pay": {
                "payment_data": "CnsiZGF0YSI6IjhmMFppZDhMTGd4U1dwcE84Z3VZY25pK3RacTVTcGRJTlFOYkszZGQyMTk5ZlJGTUZrazFNUjFORkFyM1pQMjVEaEtMaHZrM1B1c05GRlRDY0hqQ1g3OXlGWTZ6WEs5T2NLYVJqVllLa3lQOUdndnpxVm1CS3pYazhMV09Ba3JBdXZ4TlVjQW1aVnZIUDZ1Mm1zWEcrQ3JFdnA0TnE0dGxwTlQ3aGFjUm5zZFd6bmlFQ0dpYWw4R3ZwM1k3aWlyeGEvL0l6RkFHSkxjdk9qOURUTWh5NVBieXpzWGQ1S3JWVGU5U1ZKcEFmT3RXaERQOHN3NnlnUWV5SnJIT2hlcXNzY3VzT3FEclZBWW5HSTRYalB0bC91aXJFZTJDUmlRQ2lVY2ZTdDdVelNLODN5ZTB0d0ErdjlTZ2VTWUhZVlN6TWQwcGdkWnVLbkJWYmJRa0JNZElFTU56aUZjRnhLOCttRlpIUVV0cll3N0JsOU5STmZzdG5qS3hPa0d5TW9Pd3RqNTdjRS9yQWphLzk2UDg5a1dHSU9PYlhzdEoxaUp2Wms4RVp3YUVRSmc9Iiwic2lnbmF0dXJlIjoiTUlBR0NTcUdTSWIzRFFFSEFxQ0FNSUFDQVFFeERUQUxCZ2xnaGtnQlpRTUVBZ0V3Z0FZSktvWklodmNOQVFjQkFBQ2dnRENDQStRd2dnT0xvQU1DQVFJQ0NGbllvYnlxOU9QTk1Bb0dDQ3FHU000OUJBTUNNSG94TGpBc0JnTlZCQU1NSlVGd2NHeGxJRUZ3Y0d4cFkyRjBhVzl1SUVsdWRHVm5jbUYwYVc5dUlFTkJJQzBnUnpNeEpqQWtCZ05WQkFzTUhVRndjR3hsSUVObGNuUnBabWxqWVhScGIyNGdRWFYwYUc5eWFYUjVNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVFzd0NRWURWUVFHRXdKVlV6QWVGdzB5TVRBME1qQXhPVE0zTURCYUZ3MHlOakEwTVRreE9UTTJOVGxhTUdJeEtEQW1CZ05WQkFNTUgyVmpZeTF6YlhBdFluSnZhMlZ5TFhOcFoyNWZWVU0wTFZOQlRrUkNUMWd4RkRBU0JnTlZCQXNNQzJsUFV5QlRlWE4wWlcxek1STXdFUVlEVlFRS0RBcEJjSEJzWlNCSmJtTXVNUXN3Q1FZRFZRUUdFd0pWVXpCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQklJdy9hdkRuUGRlSUN4UTJadEZFdVkzNHFrQjNXeXo0TEhOUzFKbm1QalBUcjNvR2lXb3doNU1NOTNPamlxV3d2YXZvWk1EUmNUb2VrUW16cFViRXBXamdnSVJNSUlDRFRBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZEl3UVlNQmFBRkNQeVNjUlBrK1R2SitiRTlpaHNQNks3L1M1TE1FVUdDQ3NHQVFVRkJ3RUJCRGt3TnpBMUJnZ3JCZ0VGQlFjd0FZWXBhSFIwY0RvdkwyOWpjM0F1WVhCd2JHVXVZMjl0TDI5amMzQXdOQzFoY0hCc1pXRnBZMkV6TURJd2dnRWRCZ05WSFNBRWdnRVVNSUlCRURDQ0FRd0dDU3FHU0liM1kyUUZBVENCL2pDQnd3WUlLd1lCQlFVSEFnSXdnYllNZ2JOU1pXeHBZVzVqWlNCdmJpQjBhR2x6SUdObGNuUnBabWxqWVhSbElHSjVJR0Z1ZVNCd1lYSjBlU0JoYzNOMWJXVnpJR0ZqWTJWd2RHRnVZMlVnYjJZZ2RHaGxJSFJvWlc0Z1lYQndiR2xqWVdKc1pTQnpkR0Z1WkdGeVpDQjBaWEp0Y3lCaGJtUWdZMjl1WkdsMGFXOXVjeUJ2WmlCMWMyVXNJR05sY25ScFptbGpZWFJsSUhCdmJHbGplU0JoYm1RZ1kyVnlkR2xtYVdOaGRHbHZiaUJ3Y21GamRHbGpaU0J6ZEdGMFpXMWxiblJ6TGpBMkJnZ3JCZ0VGQlFjQ0FSWXFhSFIwY0RvdkwzZDNkeTVoY0hCc1pTNWpiMjB2WTJWeWRHbG1hV05oZEdWaGRYUm9iM0pwZEhrdk1EUUdBMVVkSHdRdE1Dc3dLYUFub0NXR0kyaDBkSEE2THk5amNtd3VZWEJ3YkdVdVkyOXRMMkZ3Y0d4bFlXbGpZVE11WTNKc01CMEdBMVVkRGdRV0JCUUNKREFMbXU3dFJqR1hwS1phS1o1Q2NZSWNSVEFPQmdOVkhROEJBZjhFQkFNQ0I0QXdEd1lKS29aSWh2ZGpaQVlkQkFJRkFEQUtCZ2dxaGtqT1BRUURBZ05IQURCRUFpQjBvYk1rMjBKSlF3M1RKMHhRZE1TQWpab2ZTQTQ2aGNYQk5pVm1NbCs4b3dJZ2FUYVFVNnYxQzFwUytmWUFUY1dLcld4UXA5WUlhRGVRNEtjNjBCNUsyWUV3Z2dMdU1JSUNkYUFEQWdFQ0FnaEpiUysvT3BqYWx6QUtCZ2dxaGtqT1BRUURBakJuTVJzd0dRWURWUVFEREJKQmNIQnNaU0JTYjI5MElFTkJJQzBnUnpNeEpqQWtCZ05WQkFzTUhVRndjR3hsSUVObGNuUnBabWxqWVhScGIyNGdRWFYwYUc5eWFYUjVNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVFzd0NRWURWUVFHRXdKVlV6QWVGdzB4TkRBMU1EWXlNelEyTXpCYUZ3MHlPVEExTURZeU16UTJNekJhTUhveExqQXNCZ05WQkFNTUpVRndjR3hsSUVGd2NHeHBZMkYwYVc5dUlFbHVkR1ZuY21GMGFXOXVJRU5CSUMwZ1J6TXhKakFrQmdOVkJBc01IVUZ3Y0d4bElFTmxjblJwWm1sallYUnBiMjRnUVhWMGFHOXlhWFI1TVJNd0VRWURWUVFLREFwQmNIQnNaU0JKYm1NdU1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCUEFYRVlRWjEyU0YxUnBlSllFSGR1aUFvdS9lZTY1TjRJMzhTNVBoTTFiVlpsczFyaUxRbDNZTklrNTd1Z2o5ZGhmT2lNdDJ1Mlp3dnNqb0tZVC9WRVdqZ2Zjd2dmUXdSZ1lJS3dZQkJRVUhBUUVFT2pBNE1EWUdDQ3NHQVFVRkJ6QUJoaXBvZEhSd09pOHZiMk56Y0M1aGNIQnNaUzVqYjIwdmIyTnpjREEwTFdGd2NHeGxjbTl2ZEdOaFp6TXdIUVlEVlIwT0JCWUVGQ1B5U2NSUGsrVHZKK2JFOWloc1A2SzcvUzVMTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SHdZRFZSMGpCQmd3Rm9BVXU3RGVvVmd6aUpxa2lwbmV2cjNycjlyTEpLc3dOd1lEVlIwZkJEQXdMakFzb0NxZ0tJWW1hSFIwY0RvdkwyTnliQzVoY0hCc1pTNWpiMjB2WVhCd2JHVnliMjkwWTJGbk15NWpjbXd3RGdZRFZSMFBBUUgvQkFRREFnRUdNQkFHQ2lxR1NJYjNZMlFHQWc0RUFnVUFNQW9HQ0NxR1NNNDlCQU1DQTJjQU1HUUNNRHJQY29OUkZwbXhodnMxdzFiS1lyLzBGKzNaRDNWTm9vNis4WnlCWGtLM2lmaVk5NXRabjVqVlFRMlBuZW5DL2dJd01pM1ZSQ0d3b3dWM2JGM3pPRHVRWi8wWGZDd2hiWlpQeG5KcGdoSnZWUGg2ZlJ1Wnk1c0ppU0ZoQnBrUENaSWRBQUF4Z2dHSU1JSUJoQUlCQVRDQmhqQjZNUzR3TEFZRFZRUUREQ1ZCY0hCc1pTQkJjSEJzYVdOaGRHbHZiaUJKYm5SbFozSmhkR2x2YmlCRFFTQXRJRWN6TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNQ0NGbllvYnlxOU9QTk1Bc0dDV0NHU0FGbEF3UUNBYUNCa3pBWUJna3Foa2lHOXcwQkNRTXhDd1lKS29aSWh2Y05BUWNCTUJ3R0NTcUdTSWIzRFFFSkJURVBGdzB5TkRFeU1UQXdOekU1TkRWYU1DZ0dDU3FHU0liM0RRRUpOREViTUJrd0N3WUpZSVpJQVdVREJBSUJvUW9HQ0NxR1NNNDlCQU1DTUM4R0NTcUdTSWIzRFFFSkJERWlCQ0M5bGcwVE43Vmhxa1h3eWphQTVGYjVuc0I2WDBZdE5najVvdXJHU3V3cVBUQUtCZ2dxaGtqT1BRUURBZ1JITUVVQ0lRRFp3ZENJQUFxenJlWGpnbk9paG43QXFpdTQ3TnhhUFRJR0ZBdEVMRVpkcHdJZ0ZKRDFUK25GRHd2QkxBSlpKMmVJN21qdnB6NzRlVlF3Q0ZhcWh1d2wrNElBQUFBQUFBQT0iLCJoZWFkZXIiOnsicHVibGljS2V5SGFzaCI6IjJDZ1k1N0xESVRVRDBxUjdEd3lIbHVUbTEyMkJ6MDlzYXMyQlVaK0VFOVU9IiwiZXBoZW1lcmFsUHVibGljS2V5IjoiTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFcVFmOTU1a0FnbmhJZzBHUmdBUU52dzBCRjBZVTRxbjdKVzdmZFY4K084Wk1mZlRWQTdwV2ZZYkwrd0M3RHl3MEFuT25INDJYWDluTS81ZWVpRjI5ZUE9PSIsInRyYW5zYWN0aW9uSWQiOiJjMWU5NGZmMjBhYjYyMTFkYzE5MWIxOTc0MDM2ZmE2NGMxNWJiNTQyYmFlMGJhMmQ4YWM4ODhiNDlhNzgwZGY5In0sInZlcnNpb24iOiJFQ192MSJ9",
                "payment_method": {
                    "display_name": "Discover 9319",
                    "network": "Discover",
                    "type": "credit"
                },
                "transaction_identifier": "c635c5b3af900d7bd81fecd7028f1262f9d030754ee65ec7afd988a678194751"
            }
        }
    }
}'
```
```
{
    "payment_id": "pay_1wv3HjvEqjxUQqEEY2RE",
    "merchant_id": "merchant_1733816953",
    "status": "succeeded",
    "amount": 650,
    "net_amount": 650,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 650,
    "connector": "cybersource",
    "client_secret": "pay_1wv3HjvEqjxUQqEEY2RE_secret_oPQa4cWsuyqIneiCfSFW",
    "created": "2024-12-10T07:49:21.254Z",
    "currency": "USD",
    "customer_id": "cu_1733816961",
    "customer": {
        "id": "cu_1733816961",
        "name": "Joseph Doe",
        "email": "something@gmail.com",
        "phone": "999999999",
        "phone_country_code": "+65"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "wallet",
    "payment_method_data": {
        "wallet": {
            "apple_pay": {
                "last4": "9319",
                "card_network": "Discover",
                "type": "credit"
            }
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": null
    },
    "order_details": null,
    "email": "something@gmail.com",
    "name": "Joseph Doe",
    "phone": "999999999",
    "return_url": "https://google.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "Juspay",
    "statement_descriptor_suffix": "Router",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "apple_pay",
    "connector_label": "cybersource_US_default_default",
    "business_country": "US",
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "cu_1733816961",
        "created_at": 1733816961,
        "expires": 1733820561,
        "secret": "epk_cc4776fce33d4024a350427ee01be604"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "7338169629566049304951",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "pay_1wv3HjvEqjxUQqEEY2RE_1",
    "payment_link": null,
    "profile_id": "pro_JcYIJy9B8xXAnFuBEdhc",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_pC2ENkiwqh6uOUT1d4lQ",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2024-12-10T08:04:21.254Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2024-12-10T07:49:23.458Z",
    "charges": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null
}
```



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

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