{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","admonition","endpoint"]},"type":"markdown"},"seo":{"title":"Recurring payments","description":"Transform your commerce with PXP's unified platform—seamless payments, real-time insights, and global growth in one powerful integration.","lang":"en-UK","siteUrl":"https://developer.pxp.io","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"recurring-payments","__idx":0},"children":["Recurring payments"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Perform Apple Pay recurring, deferred, and automatic reload transactions for iOS applications."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Apple Pay supports three types of recurring payment scenarios:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Recurring payments:"]}," For subscription-based payments where the customer signs up and pays initially, and you then automatically charge them at specified intervals (monthly, yearly, etc.). Apple Pay handles the subscription lifecycle with proper customer consent."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Deferred payments:"]}," For transactions where authorisation happens now, but payment is processed later (e.g., hotel bookings, pre-orders). Apple Pay provides secure payment promises."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Automatic reload payments:"]}," For topping up stored value accounts when balance falls below a threshold (e.g., gift cards, transit cards). Apple Pay manages the reload triggers automatically."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All Apple Pay recurring payment types provide enhanced security, customer control, and transparent billing through Apple's ecosystem."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["While Apple Pay provides the UI and customer consent flow for recurring payments, PXP doesn't provide an automatic payment scheduler. You must implement your own scheduling system to initiate subsequent charges (recurring billing, deferred payments, and automatic reloads) via the Transactions API."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"recurring-payments-1","__idx":2},"children":["Recurring payments"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-set-up-the-sdk-config","__idx":3},"children":["Step 1: Set up the SDK config"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To set up a recurring Apple Pay payment, you need to include recurring payment configuration in your Apple Pay component setup."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// Configure subscription transaction data\nlet transactionData = TransactionData(\n    amount: 9.99,\n    currency: \"USD\",\n    entryType: .ecom,\n    intent: TransactionIntentData(card: .purchase),\n    merchantTransactionId: \"sub-setup-123\",\n    merchantTransactionDate: { Date() }\n)\n\n// Create complete SDK configuration\nlet checkoutConfig = CheckoutConfig(\n    environment: .test,\n    session: SessionData(\n        sessionId: \"your-session-id\",\n        hmacKey: \"your-hmac-key\",\n        encryptionKey: \"your-encryption-key\",\n        allowedFundingTypes: AllowedFundingType(\n            wallets: Wallets(\n                applePay: ApplePay(\n                    merchantId: \"merchant.com.yourcompany\"\n                )\n            )\n        )\n    ),\n    transactionData: transactionData,\n    merchantShopperId: \"customer-123\",\n    ownerId: \"your-owner-id\",\n    ownerType: \"MerchantGroup\",\n    onGetShopper: {\n        return TransactionShopper(\n            email: \"customer@example.com\",\n            firstName: \"John\",\n            lastName: \"Doe\"\n        )\n    }\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-create-your-apple-pay-component-with-recurring-configuration","__idx":4},"children":["Step 2: Create your Apple Pay component with recurring configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Next, you're going to use your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["checkoutConfig"]}," to create the Apple Pay component with recurring payment configuration. When the customer authorises with Apple Pay, the recurring payments will start."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let applePayConfig = ApplePayButtonComponentConfig()\n\n// Basic configuration\napplePayConfig.merchantDisplayName = \"Subscription Service\"\napplePayConfig.paymentDescription = \"Monthly Premium Subscription\"\napplePayConfig.currencyCode = \"USD\"\napplePayConfig.countryCode = \"US\"\napplePayConfig.supportedNetworks = [.visa, .masterCard, .amex]\napplePayConfig.merchantCapabilities = [.threeDSecure, .emv, .credit, .debit]\n\n// Payment items for first payment\napplePayConfig.totalPaymentItem = ApplePayPaymentSummaryItem(\n    amount: Decimal(9.99),\n    type: .final,\n    label: \"First Month\"\n)\n\n// Button appearance - use subscribe type\napplePayConfig.buttonType = .subscribe // Use subscribe button type\napplePayConfig.buttonStyle = .black\napplePayConfig.buttonRadius = 8.0\n\n\n// Recurring payment configuration\napplePayConfig.recurringRequest = ApplePayRecurringPaymentRequest(\n  paymentDescription: \"Monthly Premium Subscription\",\n  regularBilling: ApplePayRegularBilling(\n    label: \"Monthly Subscription\",\n    amount: Decimal(9.99),\n    paymentTiming: .recurring,\n    intervalUnit: .month,\n    intervalCount: 1,\n    startDate: Calendar.current.date(byAdding: .month, value: 1, to: Date()),\n    endDate: Calendar.current.date(byAdding: .year, value: 1, to: Date())\n  ),\n  managementURL: URL(string: \"https://yoursite.com/manage-subscription\")!,\n  tokenNotificationURL: URL(string: \"https://yoursite.com/webhook/subscription\")\n)\n\n// Post-authorisation callback\napplePayConfig.onPostAuthorisation = { [weak self] result, applePayResult in\n    if let authorizedResult = result as? AuthorisedSubmitResult {\n        print(\"Recurring Apple Pay subscription started!\")\n        print(\"Transaction ID: \\(authorizedResult.provider.code)\")\n        \n        // Store recurring payment information\n        self?.storeRecurringPayment(RecurringPaymentInfo(\n            transactionId: authorizedResult.provider.code,\n            customerId: \"customer@example.com\",\n            subscriptionType: \"monthly\",\n            amount: 9.99,\n            currency: \"USD\",\n            startDate: Calendar.current.date(byAdding: .month, value: 1, to: Date()) ?? Date(),\n            endDate: Calendar.current.date(byAdding: .year, value: 1, to: Date()) ?? Date()\n        ))\n        \n        // Navigate to success screen\n        DispatchQueue.main.async {\n            self?.navigateToSubscriptionSuccess()\n        }\n    }\n}\n\napplePayConfig.onError = { [weak self] error in\n    print(\"Apple Pay subscription error: \\(error)\")\n    DispatchQueue.main.async {\n        self?.showError(\"Failed to start subscription. Please try again.\")\n    }\n}\n\n// Create and mount the Apple Pay component\ndo {\n    let applePayComponent = try checkout.create(.applePayButton, componentConfig: applePayConfig)\n    \n    if let componentView = applePayComponent.render() {\n        // Add to your view hierarchy\n        applePayContainer.addSubview(componentView)\n        // Setup constraints as needed\n    }\n} catch {\n    print(\"Failed to create Apple Pay component: \\(error)\")\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"advanced-recurring-payment-with-trial-period","__idx":5},"children":["Advanced recurring payment with trial period"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For subscriptions with trial periods, you can configure both trial and regular billing:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let applePayConfig = ApplePayButtonComponentConfig()\n\n// Basic configuration\napplePayConfig.merchantDisplayName = \"SaaS Platform\"\napplePayConfig.paymentDescription = \"Annual Subscription with Trial\"\napplePayConfig.currencyCode = \"USD\"\napplePayConfig.countryCode = \"US\"\napplePayConfig.supportedNetworks = [.visa, .masterCard, .amex]\napplePayConfig.merchantCapabilities = [.threeDSecure, .emv, .credit, .debit]\n\n// Payment items for trial period\napplePayConfig.totalPaymentItem = ApplePayPaymentSummaryItem(\n    amount: Decimal(0.00), // Free trial\n    type: .final,\n    label: \"Trial Period\"\n)\n\n// Recurring payment configuration with trial\napplePayConfig.recurringRequest = ApplePayRecurringPaymentRequest(\n  paymentDescription: \"Annual SaaS Subscription\",\n  regularBilling: ApplePayRegularBilling(\n    label: \"Annual Subscription\",\n    amount: Decimal(299.99),\n    paymentTiming: .recurring,\n    intervalUnit: .year,\n    intervalCount: 1,\n    startDate: Calendar.current.date(byAdding: .day, value: 15, to: Date())\n  ),\n  managementURL: URL(string: \"https://yoursite.com/manage-subscription\")!,\n  trialBilling: ApplePayTrialBilling(\n    label: \"14-Day Free Trial\",\n    amount: Decimal(0.00),\n    paymentTiming: .recurring,\n    intervalUnit: .day,\n    intervalCount: 14,\n    startDate: Date(),\n    endDate: Calendar.current.date(byAdding: .day, value: 14, to: Date())\n  ),\n  tokenNotificationURL: URL(string: \"https://yoursite.com/webhook/subscription\")\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"charging-subsequent-recurring-payments","__idx":6},"children":["Charging subsequent recurring payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After setting up the initial recurring payment, you must initiate subsequent charges from your backend using the Transactions API. The SDK creates a payment token during the initial setup that you can use for future charges."]},{"$$mdtype":"Tag","name":"Endpoint","attributes":{"method":"POST"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["/v1/transactions"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the following request to charge a customer for a subsequent recurring payment. You'll need the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gatewayTokenId"]}," from the initial transaction."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"merchant\": \"MERCHANT-1\",\n  \"site\": \"SITE-1\",\n  \"merchantTransactionId\": \"sub-charge-456\",\n  \"merchantTransactionDate\": \"2025-02-27T08:51:02.826Z\",\n  \"transactionMethod\": {\n    \"intent\": \"Purchase\",\n    \"entryType\": \"Ecom\",\n    \"fundingType\": \"Card\"\n  },\n  \"fundingData\": {\n    \"card\": {\n      \"gatewayTokenId\": \"5fbd77ce-02c1-40ed-94bc-1016660b7512\"\n    }\n  },\n  \"amounts\": {\n    \"transaction\": 9.99,\n    \"currencyCode\": \"USD\"\n  },\n  \"recurring\": {\n    \"processingModel\": \"MerchantInitiatedSubsequentRecurring\"\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gatewayTokenId"]}," is returned in the initial transaction response and should be stored in your system along with the subscription details. You'll use this token for all subsequent recurring charges until the subscription expires or is cancelled."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/transactions/initiate-transactions"},"children":["Learn more about initiating transactions via API"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"deferred-payments","__idx":7},"children":["Deferred payments"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-set-up-deferred-payment-configuration","__idx":8},"children":["Step 1: Set up deferred payment configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For deferred payments (e.g., hotel bookings or pre-orders), configure the payment to be charged at a future date:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let deferredApplePayConfig = ApplePayButtonComponentConfig()\n\n// Basic configuration\ndeferredApplePayConfig.merchantDisplayName = \"Travel Agency\"\ndeferredApplePayConfig.paymentDescription = \"Hotel Booking\"\ndeferredApplePayConfig.currencyCode = \"USD\"\ndeferredApplePayConfig.countryCode = \"US\"\ndeferredApplePayConfig.supportedNetworks = [.visa, .masterCard, .amex]\ndeferredApplePayConfig.merchantCapabilities = [.threeDSecure, .emv, .credit, .debit]\n\n// Payment items\ndeferredApplePayConfig.totalPaymentItem = ApplePayPaymentSummaryItem(\n    amount: Decimal(200.00),\n    type: .final,\n    label: \"Hotel Booking\"\n)\n\n// Deferred payment configuration\ndeferredApplePayConfig.deferredPaymentRequest = ApplePayDeferredPaymentRequest(\n  paymentDescription: \"Hotel Booking - Payment Due at Check-in\",\n  deferredBilling: ApplePayDeferredPaymentItem(\n    label: \"Hotel Payment\",\n    amount: Decimal(200.00),\n    paymentTiming: .deferred,\n    type: .final,\n    deferredPaymentDate: Calendar.current.date(byAdding: .day, value: 30, to: Date()) ?? Date()\n  ),\n  managementURL: URL(string: \"https://yoursite.com/manage-booking\")!,\n  freeCancellationDate: Calendar.current.date(byAdding: .day, value: 25, to: Date()),\n  tokenNotificationURL: URL(string: \"https://yoursite.com/webhook/deferred-payment\")\n)\n\n// Post-authorisation callback\ndeferredApplePayConfig.onPostAuthorisation = { [weak self] result, applePayResult in\n    if let authorizedResult = result as? AuthorisedSubmitResult {\n        print(\"Deferred Apple Pay payment authorized!\")\n        \n        // Store deferred payment information\n        self?.storeDeferredPayment(DeferredPaymentInfo(\n            authorizationId: authorizedResult.provider.code,\n            customerId: \"customer@example.com\",\n            bookingReference: \"HTL-\\(Int(Date().timeIntervalSince1970))\",\n            amount: 200.00,\n            currency: \"USD\",\n            chargeDate: Calendar.current.date(byAdding: .day, value: 30, to: Date()) ?? Date(),\n            cancellationDeadline: Calendar.current.date(byAdding: .day, value: 25, to: Date()) ?? Date()\n        ))\n        \n        // Navigate to booking confirmed screen\n        DispatchQueue.main.async {\n            self?.navigateToBookingConfirmed()\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-handle-deferred-payment-execution","__idx":9},"children":["Step 2: Handle deferred payment execution"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When the deferred payment date arrives, you'll need to process the actual charge:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// This would typically run in a background job on the deferred payment date\nfunc processDeferredPayment(deferredPaymentId: String) async throws {\n    do {\n        let deferredPayment = try await getDeferredPayment(deferredPaymentId)\n        \n        // Process the actual charge using the stored authorisation\n        let chargeResult = try await chargeDeferredApplePayment(ChargeRequest(\n            originalAuthorizationId: deferredPayment.authorizationId,\n            amount: deferredPayment.amount,\n            currency: deferredPayment.currency,\n            merchantTransactionId: \"deferred-\\(deferredPaymentId)\"\n        ))\n        \n        if chargeResult.success {\n            print(\"Deferred payment charged successfully\")\n            try await updateDeferredPaymentStatus(deferredPaymentId, status: .charged)\n            try await sendPaymentConfirmation(deferredPayment.customerId)\n        } else {\n            print(\"Deferred payment failed: \\(chargeResult.error ?? \"Unknown error\")\")\n            try await updateDeferredPaymentStatus(deferredPaymentId, status: .failed)\n            try await sendPaymentFailureNotification(deferredPayment.customerId)\n        }\n    } catch {\n        print(\"Error processing deferred payment: \\(error)\")\n        throw error\n    }\n}\n\nstruct DeferredPaymentInfo {\n    let authorizationId: String\n    let customerId: String\n    let bookingReference: String\n    let amount: Double\n    let currency: String\n    let chargeDate: Date\n    let cancellationDeadline: Date\n}\n\nstruct ChargeRequest {\n    let originalAuthorizationId: String\n    let amount: Double\n    let currency: String\n    let merchantTransactionId: String\n}\n\nenum DeferredPaymentStatus {\n    case authorized, charged, failed, cancelled\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"automatic-reload-payments","__idx":10},"children":["Automatic reload payments"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-set-up-automatic-reload-configuration","__idx":11},"children":["Step 1: Set up automatic reload configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For automatic reload payments (e.g., gift cards, transit cards), configure the reload trigger and amount:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let autoReloadApplePayConfig = ApplePayButtonComponentConfig()\n\n// Basic configuration\nautoReloadApplePayConfig.merchantDisplayName = \"Gift Card Store\"\nautoReloadApplePayConfig.paymentDescription = \"Gift Card Purchase\"\nautoReloadApplePayConfig.currencyCode = \"USD\"\nautoReloadApplePayConfig.countryCode = \"US\"\nautoReloadApplePayConfig.supportedNetworks = [.visa, .masterCard, .amex]\nautoReloadApplePayConfig.merchantCapabilities = [.threeDSecure, .emv, .credit, .debit]\n\n// Payment items for initial purchase\nautoReloadApplePayConfig.totalPaymentItem = ApplePayPaymentSummaryItem(\n    amount: Decimal(50.00),\n    type: .final,\n    label: \"Gift Card\"\n)\n\n// Automatic reload configuration\nautoReloadApplePayConfig.automaticReloadPaymentRequest = ApplePayAutomaticReloadPaymentRequest(\n  paymentDescription: \"Automatic Reload for Gift Card\",\n  automaticReloadBilling: ApplePayAutomaticReloadPaymentItem(\n    label: \"Auto Reload\",\n    amount: Decimal(25.00),\n    thresholdAmount: Decimal(10.00)\n  ),\n  managementURL: URL(string: \"https://yoursite.com/manage-gift-card\")!,\n  tokenNotificationURL: URL(string: \"https://yoursite.com/webhook/auto-reload\")\n)\n\n// Post-authorisation callback\nautoReloadApplePayConfig.onPostAuthorisation = { [weak self] result, applePayResult in\n    if let authorizedResult = result as? AuthorisedSubmitResult {\n        print(\"Apple Pay automatic reload set up!\")\n        \n        // Store automatic reload configuration\n        self?.storeAutoReloadConfig(AutoReloadConfig(\n            transactionId: authorizedResult.provider.code,\n            customerId: \"customer@example.com\",\n            giftCardId: \"GC-\\(Int(Date().timeIntervalSince1970))\",\n            initialAmount: 50.00,\n            reloadAmount: 25.00,\n            thresholdAmount: 10.00,\n            currency: \"USD\"\n        ))\n        \n        // Navigate to gift card success screen\n        DispatchQueue.main.async {\n            self?.navigateToGiftCardSuccess()\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-handle-automatic-reload-triggers","__idx":12},"children":["Step 2: Handle automatic reload triggers"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Monitor account balances and trigger automatic reloads when thresholds are reached:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// This would typically run as a scheduled job to check balances\nfunc checkAutoReloadTriggers() async throws {\n    let autoReloadAccounts = try await getActiveAutoReloadAccounts()\n    \n    for account in autoReloadAccounts {\n        let currentBalance = try await getAccountBalance(account.giftCardId)\n        \n        if currentBalance <= account.thresholdAmount {\n            do {\n                print(\"Triggering auto-reload for account \\(account.giftCardId)\")\n                \n                // Process automatic reload using stored authorization\n                let reloadResult = try await processAutoReload(AutoReloadRequest(\n                    originalTransactionId: account.transactionId,\n                    amount: account.reloadAmount,\n                    currency: account.currency,\n                    accountId: account.giftCardId,\n                    merchantTransactionId: \"reload-\\(account.giftCardId)-\\(Int(Date().timeIntervalSince1970))\"\n                ))\n                \n                if reloadResult.success {\n                    // Update account balance\n                    try await updateAccountBalance(\n                        account.giftCardId,\n                        newBalance: currentBalance + account.reloadAmount\n                    )\n                    \n                    // Send notification to customer\n                    try await sendAutoReloadNotification(account.customerId, notification: AutoReloadNotification(\n                        amount: account.reloadAmount,\n                        newBalance: currentBalance + account.reloadAmount,\n                        transactionId: reloadResult.transactionId\n                    ))\n                    \n                    print(\"Auto-reload completed successfully\")\n                } else {\n                    print(\"Auto-reload failed: \\(reloadResult.error ?? \"Unknown error\")\")\n                    try await sendAutoReloadFailureNotification(account.customerId)\n                }\n            } catch {\n                print(\"Error processing auto-reload: \\(error)\")\n            }\n        }\n    }\n}\n\nstruct AutoReloadConfig {\n    let transactionId: String\n    let customerId: String\n    let giftCardId: String\n    let initialAmount: Double\n    let reloadAmount: Double\n    let thresholdAmount: Double\n    let currency: String\n}\n\nstruct AutoReloadRequest {\n    let originalTransactionId: String\n    let amount: Double\n    let currency: String\n    let accountId: String\n    let merchantTransactionId: String\n}\n\nstruct AutoReloadNotification {\n    let amount: Double\n    let newBalance: Double\n    let transactionId: String\n}\n\n// Schedule to run every hour to check for reload triggers\nfunc scheduleAutoReloadChecks() {\n    Timer.scheduledTimer(withTimeInterval: 3600, repeats: true) { _ in\n        Task {\n            try await checkAutoReloadTriggers()\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"combined-payment-types","__idx":13},"children":["Combined payment types"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can combine multiple payment types in a single Apple Pay transaction:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let combinedApplePayConfig = ApplePayButtonComponentConfig()\n\n// Basic configuration\ncombinedApplePayConfig.merchantDisplayName = \"Premium Service\"\ncombinedApplePayConfig.paymentDescription = \"Premium Subscription with Auto-Reload\"\ncombinedApplePayConfig.currencyCode = \"USD\"\ncombinedApplePayConfig.countryCode = \"US\"\ncombinedApplePayConfig.supportedNetworks = [.visa, .masterCard, .amex]\ncombinedApplePayConfig.merchantCapabilities = [.threeDSecure, .emv, .credit, .debit]\n\n// Payment items for first payment\ncombinedApplePayConfig.totalPaymentItem = ApplePayPaymentSummaryItem(\n    amount: Decimal(29.99),\n    type: .final,\n    label: \"First Payment\"\n)\n\n// Recurring payment for subscription\ncombinedApplePayConfig.recurringRequest = ApplePayRecurringPaymentRequest(\n  paymentDescription: \"Monthly Premium Subscription\",\n  regularBilling: ApplePayRegularBilling(\n    label: \"Monthly Premium\",\n    amount: Decimal(29.99),\n    paymentTiming: .recurring,\n    intervalUnit: .month,\n    intervalCount: 1,\n    startDate: Calendar.current.date(byAdding: .month, value: 1, to: Date()),\n    endDate: Calendar.current.date(byAdding: .year, value: 1, to: Date())\n  ),\n  managementURL: URL(string: \"https://yoursite.com/manage-subscription\")!,\n  tokenNotificationURL: URL(string: \"https://yoursite.com/webhook/subscription\")\n)\n\n// Automatic reload for credits\ncombinedApplePayConfig.automaticReloadPaymentRequest = ApplePayAutomaticReloadPaymentRequest(\n  paymentDescription: \"Auto Reload Credits\",\n  automaticReloadBilling: ApplePayAutomaticReloadPaymentItem(\n    label: \"Credit Reload\",\n    amount: Decimal(10.00),\n    thresholdAmount: Decimal(5.00)\n  ),\n  managementURL: URL(string: \"https://yoursite.com/manage-credits\")!\n)\n\n// Post-authorisation callback\ncombinedApplePayConfig.onPostAuthorisation = { [weak self] result, applePayResult in\n    if let authorizedResult = result as? AuthorisedSubmitResult {\n        print(\"Combined Apple Pay payment configured!\")\n        \n        // Store both recurring and auto-reload configurations\n        self?.storeCombinedPaymentConfig(CombinedPaymentConfig(\n            transactionId: authorizedResult.provider.code,\n            customerId: \"customer@example.com\",\n            subscription: SubscriptionConfig(\n                amount: 29.99,\n                interval: \"monthly\",\n                startDate: calendar.date(byAdding: .month, value: 1, to: Date()) ?? Date(),\n                endDate: calendar.date(byAdding: .year, value: 1, to: Date()) ?? Date()\n            ),\n            autoReload: AutoReloadConfig(\n                transactionId: authorizedResult.provider.code,\n                customerId: \"customer@example.com\",\n                giftCardId: \"GC-\\(Int(Date().timeIntervalSince1970))\",\n                initialAmount: 0,\n                reloadAmount: 10.00,\n                thresholdAmount: 5.00,\n                currency: \"USD\"\n            )\n        ))\n    }\n}\n\nstruct CombinedPaymentConfig {\n    let transactionId: String\n    let customerId: String\n    let subscription: SubscriptionConfig\n    let autoReload: AutoReloadConfig\n}\n\nstruct SubscriptionConfig {\n    let amount: Double\n    let interval: String\n    let startDate: Date\n    let endDate: Date\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"customer-consent-and-management","__idx":14},"children":["Customer consent and management"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"apple-pay-consent-component","__idx":15},"children":["Apple Pay consent component"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For recurring payments, you should also implement a consent component to clearly communicate the recurring nature of the payment:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// Create Apple Pay consent component\nlet applePayConsentConfig = ApplePayConsentComponentConfig(\n    label: \"I agree to store my Device Primary Account Number (DPAN) for recurring payments and authorise monthly charges of $9.99\",\n    checkedColor: Color.blue,\n    uncheckedColor: Color.gray,\n    size: 20.0,\n    checked: false\n)\n\nlet applePayConsentComponent = try checkout.create(.applePayConsent, componentConfig: applePayConsentConfig)\n\n// Connect consent to Apple Pay button\napplePayConfig.applePayConsentComponent = applePayConsentComponent as? ApplePayConsentComponent\n\n// Alternative: Use callback for consent\napplePayConfig.onGetConsent = { [weak self] in\n    return self?.recurringConsentSwitch.isOn ?? false\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"customer-management-urls","__idx":16},"children":["Customer management URLs"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Apple Pay requires management URLs for recurring payments where customers can:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["View upcoming charges."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Modify subscription details."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Cancel subscriptions."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Update payment information."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// Example management functionality\nclass SubscriptionManager {\n    \n    func getSubscriptions(for customerId: String) async throws -> [Subscription] {\n        let url = URL(string: \"https://yourapi.com/customers/\\(customerId)/subscriptions\")!\n        let (data, _) = try await URLSession.shared.data(from: url)\n        return try JSONDecoder().decode([Subscription].self, from: data)\n    }\n    \n    func cancelSubscription(_ subscriptionId: String) async throws -> Bool {\n        // Cancel with Apple Pay notification\n        try await notifyApplePayCancellation(subscriptionId)\n        \n        // Cancel in your system\n        let url = URL(string: \"https://yourapi.com/subscriptions/\\(subscriptionId)/cancel\")!\n        var request = URLRequest(url: url)\n        request.httpMethod = \"POST\"\n        \n        let (_, response) = try await URLSession.shared.data(for: request)\n        return (response as? HTTPURLResponse)?.statusCode == 200\n    }\n    \n    func updateSubscription(_ subscriptionId: String, updates: SubscriptionUpdate) async throws -> Bool {\n        let url = URL(string: \"https://yourapi.com/subscriptions/\\(subscriptionId)\")!\n        var request = URLRequest(url: url)\n        request.httpMethod = \"PATCH\"\n        request.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\n        request.httpBody = try JSONEncoder().encode(updates)\n        \n        let (_, response) = try await URLSession.shared.data(for: request)\n        return (response as? HTTPURLResponse)?.statusCode == 200\n    }\n    \n    private func notifyApplePayCancellation(_ subscriptionId: String) async throws {\n        // Implement Apple Pay notification for cancellation\n        // This ensures Apple Pay is aware of the cancellation\n    }\n}\n\nstruct Subscription: Codable {\n    let id: String\n    let customerId: String\n    let amount: Double\n    let currency: String\n    let status: SubscriptionStatus\n    let nextPaymentDate: Date\n}\n\nstruct SubscriptionUpdate: Codable {\n    let amount: Double?\n    let nextPaymentDate: Date?\n    let status: SubscriptionStatus?\n}\n\nenum SubscriptionStatus: String, Codable {\n    case active, paused, cancelled, failed\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"error-handling-and-edge-cases","__idx":17},"children":["Error handling and edge cases"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"recurring-payment-failures","__idx":18},"children":["Recurring payment failures"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle various failure scenarios for recurring payments:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let applePayConfig = ApplePayButtonComponentConfig()\n\napplePayConfig.onError = { [weak self] error in\n    print(\"Apple Pay recurring payment error: \\(error)\")\n    \n    DispatchQueue.main.async {\n        if error.localizedDescription.contains(\"recurring\") {\n            self?.showError(\"Unable to set up recurring payments. Please try again.\")\n        } else if error.localizedDescription.contains(\"deferred\") {\n            self?.showError(\"Unable to authorise future payment. Please try again.\")\n        } else if error.localizedDescription.contains(\"reload\") {\n            self?.showError(\"Unable to set up automatic reload. Please try again.\")\n        } else {\n            self?.showError(\"Payment setup failed. Please try again.\")\n        }\n    }\n}\n\napplePayConfig.onPostAuthorisation = { [weak self] result, applePayResult in\n    if let failedResult = result as? FailedSubmitResult {\n        DispatchQueue.main.async {\n            // Handle specific recurring payment failures\n            switch failedResult.errorCode {\n            case \"RECURRING_NOT_SUPPORTED\":\n                self?.showError(\"Recurring payments are not supported for this card.\")\n            case \"DEFERRED_NOT_SUPPORTED\":\n                self?.showError(\"Deferred payments are not supported for this card.\")\n            case \"AUTO_RELOAD_NOT_SUPPORTED\":\n                self?.showError(\"Automatic reload is not supported for this card.\")\n            case \"INSUFFICIENT_FUNDS\":\n                self?.showError(\"Insufficient funds for recurring payment setup.\")\n            default:\n                self?.showError(\"Payment authorisation failed. Please try again.\")\n            }\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"webhook-handling","__idx":19},"children":["Webhook handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement webhooks to handle Apple Pay notifications for recurring payments:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// Example webhook handler using Vapor framework\nimport Vapor\n\nfunc routes(_ app: Application) throws {\n    app.post(\"webhook\", \"apple-pay\") { req -> HTTPStatus in\n        let webhookData = try req.content.decode(ApplePayWebhook.self)\n        \n        switch webhookData.type {\n        case .recurringPaymentCharged:\n            try await handleRecurringPaymentCharged(webhookData.data)\n        case .recurringPaymentFailed:\n            try await handleRecurringPaymentFailed(webhookData.data)\n        case .subscriptionCancelled:\n            try await handleSubscriptionCancelled(webhookData.data)\n        case .autoReloadTriggered:\n            try await handleAutoReloadTriggered(webhookData.data)\n        case .deferredPaymentDue:\n            try await handleDeferredPaymentDue(webhookData.data)\n        default:\n            print(\"Unknown webhook type: \\(webhookData.type)\")\n        }\n        \n        return .ok\n    }\n}\n\nstruct ApplePayWebhook: Content {\n    let type: WebhookType\n    let data: WebhookData\n}\n\nenum WebhookType: String, Codable {\n    case recurringPaymentCharged = \"RECURRING_PAYMENT_CHARGED\"\n    case recurringPaymentFailed = \"RECURRING_PAYMENT_FAILED\"\n    case subscriptionCancelled = \"SUBSCRIPTION_CANCELLED\"\n    case autoReloadTriggered = \"AUTO_RELOAD_TRIGGERED\"\n    case deferredPaymentDue = \"DEFERRED_PAYMENT_DUE\"\n}\n\nstruct WebhookData: Content {\n    let subscriptionId: String?\n    let customerId: String\n    let amount: Double?\n    let currency: String?\n    let failureReason: String?\n    let nextRetryDate: Date?\n}\n\nfunc handleRecurringPaymentCharged(_ data: WebhookData) async throws {\n    // Update subscription status\n    try await updateSubscriptionStatus(data.subscriptionId!, status: .active)\n    \n    // Send receipt to customer\n    try await sendRecurringPaymentReceipt(data.customerId, data: data)\n    \n    // Update customer balance/access\n    try await updateCustomerAccess(data.customerId, subscriptionType: \"premium\")\n}\n\nfunc handleRecurringPaymentFailed(_ data: WebhookData) async throws {\n    // Update subscription status\n    try await updateSubscriptionStatus(data.subscriptionId!, status: .failed)\n    \n    // Send payment failure notification\n    try await sendPaymentFailureNotification(data.customerId, details: PaymentFailureDetails(\n        reason: data.failureReason ?? \"Unknown\",\n        nextAttempt: data.nextRetryDate\n    ))\n    \n    // Implement grace period or suspend access\n    try await suspendCustomerAccess(data.customerId, subscriptionType: \"premium\")\n}\n\nstruct PaymentFailureDetails {\n    let reason: String\n    let nextAttempt: Date?\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"complete-implementation-example","__idx":20},"children":["Complete implementation example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's a comprehensive example showing all recurring payment types working together:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import UIKit\nimport PXPCheckoutSDK\n\nclass RecurringPaymentsViewController: UIViewController {\n    \n    private var applePayComponent: ApplePayButtonComponent?\n    private var applePayConsentComponent: ApplePayConsentComponent?\n    private var checkout: PxpCheckout?\n    \n    @IBOutlet weak var paymentTypeSegmentedControl: UISegmentedControl!\n    @IBOutlet weak var recurringConsentSwitch: UISwitch!\n    @IBOutlet weak var applePayContainer: UIView!\n    @IBOutlet weak var consentContainer: UIView!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        setupRecurringPayments()\n    }\n    \n    private func setupRecurringPayments() {\n        let checkoutConfig = CheckoutConfig(\n            environment: .test,\n            session: SessionData(\n                sessionId: \"your-session-id\",\n                hmacKey: \"your-hmac-key\",\n                encryptionKey: \"your-encryption-key\"\n            ),\n            transactionData: TransactionData(\n                amount: 29.99,\n                currency: \"USD\",\n                entryType: .ecom,\n                intent: TransactionIntentData(card: .purchase),\n                merchantTransactionId: \"recurring-\\(Int(Date().timeIntervalSince1970))\",\n                merchantTransactionDate: { Date() }\n            ),\n            merchantShopperId: \"customer-123\",\n            ownerId: \"your-owner-id\"\n        )\n        \n        do {\n            checkout = try PxpCheckout.initialize(config: checkoutConfig)\n            setupConsentComponent()\n            updatePaymentConfiguration()\n        } catch {\n            print(\"Failed to initialize: \\(error)\")\n        }\n    }\n    \n    private func setupConsentComponent() {\n        let consentConfig = ApplePayConsentComponentConfig(\n            label: \"I agree to store my payment information for recurring payments\",\n            checkedColor: Color.blue,\n            uncheckedColor: Color.gray,\n            size: 20.0,\n            checked: false\n        )\n        \n        do {\n            applePayConsentComponent = try checkout?.create(.applePayConsent, componentConfig: consentConfig) as? ApplePayConsentComponent\n            \n            if let consentView = applePayConsentComponent?.render() {\n                consentContainer.addSubview(consentView)\n                setupConstraints(for: consentView, in: consentContainer)\n            }\n        } catch {\n            print(\"Failed to create consent component: \\(error)\")\n        }\n    }\n    \n    @IBAction func paymentTypeChanged(_ sender: UISegmentedControl) {\n        updatePaymentConfiguration()\n    }\n    \n    private func updatePaymentConfiguration() {\n        guard let checkout = checkout else { return }\n        \n        // Remove existing component\n        applePayComponent = nil\n        applePayContainer.subviews.forEach { $0.removeFromSuperview() }\n        \n        let config: ApplePayButtonComponentConfig\n        \n        switch paymentTypeSegmentedControl.selectedSegmentIndex {\n        case 0: // Recurring\n            config = createRecurringPaymentConfig()\n        case 1: // Deferred\n            config = createDeferredPaymentConfig()\n        case 2: // Auto-reload\n            config = createAutoReloadPaymentConfig()\n        default:\n            config = createRecurringPaymentConfig()\n        }\n        \n        do {\n            applePayComponent = try checkout.create(.applePayButton, componentConfig: config)\n            \n            if let componentView = applePayComponent?.render() {\n                applePayContainer.addSubview(componentView)\n                setupConstraints(for: componentView, in: applePayContainer)\n            }\n        } catch {\n            print(\"Failed to create Apple Pay component: \\(error)\")\n        }\n    }\n    \n    private func createRecurringPaymentConfig() -> ApplePayButtonComponentConfig {\n        let config = ApplePayButtonComponentConfig()\n        \n        // Basic configuration\n        config.merchantDisplayName = \"Subscription Service\"\n        config.paymentDescription = \"Monthly Premium Subscription\"\n        config.currencyCode = \"USD\"\n        config.countryCode = \"US\"\n        config.supportedNetworks = [.visa, .masterCard, .amex]\n        config.merchantCapabilities = [.threeDSecure, .emv, .credit, .debit]\n        config.buttonType = .subscribe\n        config.buttonStyle = .black\n        config.buttonRadius = 8.0\n        \n        // Payment items\n        config.totalPaymentItem = ApplePayPaymentSummaryItem(\n            amount: Decimal(29.99),\n            type: .final,\n            label: \"First Month\"\n        )\n        \n        // Recurring configuration\n        config.recurringRequest = ApplePayRecurringPaymentRequest(\n            paymentDescription: \"Monthly Premium Subscription\",\n            regularBilling: ApplePayRegularBilling(\n                label: \"Monthly Subscription\",\n                amount: Decimal(29.99),\n                paymentTiming: .recurring,\n                intervalUnit: .month,\n                intervalCount: 1,\n                startDate: calendar.date(byAdding: .month, value: 1, to: Date())\n            ),\n            managementURL: URL(string: \"https://yoursite.com/manage-subscription\")!\n        )\n        \n        // Connect consent component\n        config.applePayConsentComponent = applePayConsentComponent\n        \n        // Callbacks\n        setupCallbacks(for: config, type: .recurring)\n        \n        return config\n    }\n    \n    private func createDeferredPaymentConfig() -> ApplePayButtonComponentConfig {\n        let config = ApplePayButtonComponentConfig()\n        \n        // Basic configuration\n        config.merchantDisplayName = \"Travel Agency\"\n        config.paymentDescription = \"Hotel Booking\"\n        config.currencyCode = \"USD\"\n        config.countryCode = \"US\"\n        config.supportedNetworks = [.visa, .masterCard, .amex]\n        config.merchantCapabilities = [.threeDSecure, .emv, .credit, .debit]\n        config.buttonType = .book\n        config.buttonStyle = .black\n        config.buttonRadius = 8.0\n        \n        // Payment items\n        config.totalPaymentItem = ApplePayPaymentSummaryItem(\n            amount: Decimal(200.00),\n            type: .final,\n            label: \"Hotel Booking\"\n        )\n        \n        // Deferred configuration\n        config.deferredPaymentRequest = ApplePayDeferredPaymentRequest(\n            paymentDescription: \"Hotel Payment Due at Check-in\",\n            deferredBilling: ApplePayDeferredPaymentItem(\n                label: \"Hotel Payment\",\n                amount: Decimal(200.00),\n                paymentTiming: .deferred,\n                type: .final,\n                deferredPaymentDate: Calendar.current.date(byAdding: .day, value: 30, to: Date()) ?? Date()\n            ),\n            managementURL: URL(string: \"https://yoursite.com/manage-booking\")!\n        )\n        \n        // Callbacks\n        setupCallbacks(for: config, type: .deferred)\n        \n        return config\n    }\n    \n    private func createAutoReloadPaymentConfig() -> ApplePayButtonComponentConfig {\n        let config = ApplePayButtonComponentConfig()\n        \n        // Basic configuration\n        config.merchantDisplayName = \"Gift Card Store\"\n        config.paymentDescription = \"Gift Card with Auto-Reload\"\n        config.currencyCode = \"USD\"\n        config.countryCode = \"US\"\n        config.supportedNetworks = [.visa, .masterCard, .amex]\n        config.merchantCapabilities = [.threeDSecure, .emv, .credit, .debit]\n        config.buttonType = .addMoney\n        config.buttonStyle = .black\n        config.buttonRadius = 8.0\n        \n        // Payment items\n        config.totalPaymentItem = ApplePayPaymentSummaryItem(\n            amount: Decimal(50.00),\n            type: .final,\n            label: \"Gift Card\"\n        )\n        \n        // Auto-reload configuration\n        config.automaticReloadPaymentRequest = ApplePayAutomaticReloadPaymentRequest(\n            paymentDescription: \"Automatic Gift Card Reload\",\n            automaticReloadBilling: ApplePayAutomaticReloadPaymentItem(\n                label: \"Auto Reload\",\n                amount: Decimal(25.00),\n                thresholdAmount: Decimal(10.00)\n            ),\n            managementURL: URL(string: \"https://yoursite.com/manage-gift-card\")!\n        )\n        \n        // Callbacks\n        setupCallbacks(for: config, type: .autoReload)\n        \n        return config\n    }\n    \n    private func setupCallbacks(for config: ApplePayButtonComponentConfig, type: PaymentType) {\n        config.onPostAuthorisation = { [weak self] result, applePayResult in\n            DispatchQueue.main.async {\n                if let authorizedResult = result as? AuthorisedSubmitResult {\n                    self?.handleSuccessfulPayment(result: authorizedResult, type: type)\n                } else if let failedResult = result as? FailedSubmitResult {\n                    self?.handleFailedPayment(result: failedResult, type: type)\n                }\n            }\n        }\n        \n        config.onError = { [weak self] error in\n            DispatchQueue.main.async {\n                self?.handlePaymentError(error: error, type: type)\n            }\n        }\n    }\n    \n    private func handleSuccessfulPayment(result: AuthorisedSubmitResult, type: PaymentType) {\n        let message: String\n        \n        switch type {\n        case .recurring:\n            message = \"Recurring subscription set up successfully!\"\n        case .deferred:\n            message = \"Deferred payment authorised successfully!\"\n        case .autoReload:\n            message = \"Auto-reload configured successfully!\"\n        }\n        \n        let alert = UIAlertController(title: \"Success\", message: message, preferredStyle: .alert)\n        alert.addAction(UIAlertAction(title: \"OK\", style: .default))\n        present(alert, animated: true)\n    }\n    \n    private func handleFailedPayment(result: FailedSubmitResult, type: PaymentType) {\n        let message = \"Payment failed: \\(result.errorReason)\"\n        let alert = UIAlertController(title: \"Payment Failed\", message: message, preferredStyle: .alert)\n        alert.addAction(UIAlertAction(title: \"OK\", style: .default))\n        present(alert, animated: true)\n    }\n    \n    private func handlePaymentError(error: Error, type: PaymentType) {\n        let message = \"Error: \\(error.localizedDescription)\"\n        let alert = UIAlertController(title: \"Error\", message: message, preferredStyle: .alert)\n        alert.addAction(UIAlertAction(title: \"OK\", style: .default))\n        present(alert, animated: true)\n    }\n    \n    // Helper methods\n    private func setupConstraints(for view: UIView, in container: UIView) {\n        view.translatesAutoresizingMaskIntoConstraints = false\n        \n        NSLayoutConstraint.activate([\n            view.leadingAnchor.constraint(equalTo: container.leadingAnchor),\n            view.trailingAnchor.constraint(equalTo: container.trailingAnchor),\n            view.topAnchor.constraint(equalTo: container.topAnchor),\n            view.bottomAnchor.constraint(equalTo: container.bottomAnchor)\n        ])\n    }\n    \n    enum PaymentType {\n        case recurring, deferred, autoReload\n    }\n}\n\n// Data models for storing payment information\nstruct RecurringPaymentInfo {\n    let transactionId: String\n    let customerId: String\n    let subscriptionType: String\n    let amount: Double\n    let currency: String\n    let startDate: Date\n    let endDate: Date\n}\n","lang":"swift"},"children":[]}]},"headings":[{"value":"Recurring payments","id":"recurring-payments","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Recurring payments","id":"recurring-payments-1","depth":2},{"value":"Step 1: Set up the SDK config","id":"step-1-set-up-the-sdk-config","depth":3},{"value":"Step 2: Create your Apple Pay component with recurring configuration","id":"step-2-create-your-apple-pay-component-with-recurring-configuration","depth":3},{"value":"Advanced recurring payment with trial period","id":"advanced-recurring-payment-with-trial-period","depth":3},{"value":"Charging subsequent recurring payments","id":"charging-subsequent-recurring-payments","depth":3},{"value":"Deferred payments","id":"deferred-payments","depth":2},{"value":"Step 1: Set up deferred payment configuration","id":"step-1-set-up-deferred-payment-configuration","depth":3},{"value":"Step 2: Handle deferred payment execution","id":"step-2-handle-deferred-payment-execution","depth":3},{"value":"Automatic reload payments","id":"automatic-reload-payments","depth":2},{"value":"Step 1: Set up automatic reload configuration","id":"step-1-set-up-automatic-reload-configuration","depth":3},{"value":"Step 2: Handle automatic reload triggers","id":"step-2-handle-automatic-reload-triggers","depth":3},{"value":"Combined payment types","id":"combined-payment-types","depth":2},{"value":"Customer consent and management","id":"customer-consent-and-management","depth":2},{"value":"Apple Pay consent component","id":"apple-pay-consent-component","depth":3},{"value":"Customer management URLs","id":"customer-management-urls","depth":3},{"value":"Error handling and edge cases","id":"error-handling-and-edge-cases","depth":2},{"value":"Recurring payment failures","id":"recurring-payment-failures","depth":3},{"value":"Webhook handling","id":"webhook-handling","depth":3},{"value":"Complete implementation example","id":"complete-implementation-example","depth":2}],"frontmatter":{"seo":{"title":"Recurring payments"}},"lastModified":"2026-04-02T13:24:43.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/components/ios/apple-pay/recurring-payments","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}