{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","br","details","admonition","tabs","tab"]},"type":"markdown"},"seo":{"title":"PayPal","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":"paypal","__idx":0},"children":["PayPal"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Accept PayPal and Pay Later payments with automatic popup handling and saved PayPal accounts for returning customers."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal is automatically included in the drop-in when enabled in your session. The drop-in handles all PayPal setup, button rendering, web view interaction, and payment processing automatically."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"key-benefits","__idx":2},"children":["Key benefits"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["PayPal appears automatically in the drop-in when it's enabled in your session configuration."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The drop-in handles all PayPal setup, so you don't need PayPal-specific code."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["PayPal uses the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," callbacks as other payment methods for a unified integration."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Customers can pay using PayPal or Pay Later financing options."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Returning customers can use saved PayPal accounts when vaulting is enabled."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Standard PayPal branding is included automatically, ensuring a familiar checkout experience."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"how-it-works","__idx":3},"children":["How it works"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a customer selects PayPal:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer taps \"PayPal\" in the payment options list."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Drop-in validates the configuration and creates a pending PayPal transaction/order through Unity."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The PayPal web view opens with the order details."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer logs in to their PayPal account."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer approves the payment in the PayPal interface."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The web view closes automatically."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Drop-in fires your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback with the pending transaction result."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Critical:"]}," You must verify the final transaction state on your backend before fulfilling the order."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"configuration","__idx":4},"children":["Configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure PayPal-specific settings for the PayPal button, checkout flow, and shipping integration."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"configuration-properties","__idx":5},"children":["Configuration properties"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following properties are available for PayPal configuration through ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DropInPaypalConfig"]},":"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"width":"50%","data-label":"Property"},"children":["Property "]},{"$$mdtype":"Tag","name":"th","attributes":{"width":"50%","data-label":"Description"},"children":["Description "]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fundingSources"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["[DropInPaypalFundingSources]?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Which PayPal funding sources to display. Falls back to session configuration if not specified.",{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},"Possible values:",{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".paypal"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".paylater"]}]}]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["payeeEmailAddress"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payee email address for the PayPal transaction."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["paymentDescription"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["A description of the payment shown to the customer in PayPal."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["consentComponent"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["Bool?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Controls whether Drop-in creates the PayPal consent checkbox for vaulting. When ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]},", a consent checkbox renders for logged-in shoppers (requires ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," to return a shopper ID)."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["shippingPreference"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["PayPalShippingPreference?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["How shipping address is handled in PayPal.",{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},"Possible values:",{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".noShipping"]}," - No shipping address required (digital goods)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".getFromFile"]}," - Get address from buyer's PayPal account"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".setProvidedAddress"]}," - Use merchant-provided address"]}]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},"Note: When using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".getFromFile"]}," with shipping options, configure ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global.shippingOptions"]},"."]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal locale is configured through the top-level ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CheckoutDropInConfig.locale"]}," parameter, not through ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DropInPaypalConfig"]},". Use hyphenated format (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["\"en-US\""]},") for locale configuration."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To display Pay Later as a payment option, ensure ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":[".paylater"]}," is included in your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fundingSources"]}," configuration ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["and"]}," that Pay Later is enabled for your merchant account in the Unity Portal."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"settings-used-from-global-configuration","__idx":6},"children":["Settings used from global configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal inherits the following settings from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global"]},":"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"width":"40%","data-label":"Property"},"children":["Property "]},{"$$mdtype":"Tag","name":"th","attributes":{"width":"60%","data-label":"Description"},"children":["Description "]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetConsent"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["(DropInPaymentMethod) -> Bool"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.paypal.consentComponent"]}," controls whether Drop-in creates the PayPal consent checkbox. ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global.onGetConsent(.paypal)"]}," provides a fallback consent value when no consent component is used."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["shippingOptions"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["[DropInShippingOption]?"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Shipping options for PayPal transactions. Requires ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["shippingPreference: .getFromFile"]}," in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DropInPaypalConfig"]},"."]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global.onCancel"]}," isn't currently wired for PayPal in Drop-in. The SDK overrides the PayPal cancel handler to clear processing state. User cancellations result in no callback being fired to the merchant app."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"complete-example","__idx":7},"children":["Complete example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This example shows a full PayPal configuration with shipping options and all supported ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["DropInPaypalConfig"]}," properties:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"methodConfig: DropInMethodConfig(\n    // Global settings that apply to PayPal\n    global: DropInGlobalConfig(\n        // Shipping options for PayPal (requires shippingPreference: .getFromFile)\n        shippingOptions: [\n            DropInShippingOption(\n                id: \"standard\",\n                label: \"Standard Shipping\",\n                description: \"Arrives in 3-5 business days\",\n                amount: \"10.00\"\n            ),\n            DropInShippingOption(\n                id: \"express\",\n                label: \"Express Shipping\",\n                description: \"Arrives in 1-2 business days\",\n                amount: \"25.00\"\n            )\n        ],\n        \n        // Provide fallback consent value for PayPal vaulting\n        onGetConsent: { paymentMethod in\n            return paymentMethod == .paypal\n        }\n    ),\n    \n    paypal: DropInPaypalConfig(\n        // Funding sources to display\n        fundingSources: [\n            .paypal,\n            .paylater\n        ],\n        \n        // Payee email address\n        payeeEmailAddress: \"merchant@example.com\",\n        \n        // Payment description shown to buyer\n        paymentDescription: \"Purchase from Demo Store\",\n        \n        // Show/hide consent checkbox for vaulting\n        consentComponent: true,\n        \n        // Shipping preference\n        shippingPreference: .getFromFile  // Required for shipping options\n    )\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"paypal-requirements","__idx":8},"children":["PayPal requirements"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal requires the following to function correctly:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["iOS compatibility:"]}," iOS 14.0 or higher."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Internet connection:"]}," Active internet connection required for PayPal web view."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Customer setup:"]}," The customer must have a PayPal account (created during checkout if needed)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["HTTPS:"]}," Your backend endpoints must be served over HTTPS."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Unity Portal configuration:"]}," PayPal must be enabled and configured in the Unity Portal."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Entry type:"]}," PayPal only supports ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["entryType: .ecom"]},"."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal vaulting requires the buyer to have previously authorised your merchant account. Authorisations must be captured within 29 days for PayPal."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"implementation","__idx":9},"children":["Implementation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal works through the standard implementation, with no PayPal-specific code needed:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import SwiftUI\nimport PXPCheckoutSDK\n\nstruct CheckoutView: View {\n    @StateObject private var viewModel = CheckoutViewModel()\n    \n    var body: some View {\n        Group {\n            if let dropIn = viewModel.dropIn {\n                dropIn.buildContent()\n            } else if let errorMessage = viewModel.errorMessage {\n                Text(errorMessage)\n            } else {\n                ProgressView(\"Loading checkout...\")\n            }\n        }\n        .task {\n            await viewModel.loadDropIn()\n        }\n    }\n}\n\n@MainActor\nfinal class CheckoutViewModel: ObservableObject {\n    @Published var dropIn: CheckoutDropIn?\n    @Published var errorMessage: String?\n    \n    func loadDropIn() async {\n        // Fetch session from backend (with PayPal enabled)\n        guard let sessionData = await fetchSessionFromBackend() else {\n            errorMessage = \"Failed to create session\"\n            return\n        }\n        \n        // Initialise Drop-in\n        let config = CheckoutDropInConfig(\n            environment: .test,\n            session: sessionData,\n            transactionData: DropInTransactionData(\n                amount: Decimal(string: \"99.99\") ?? 0,\n                currency: \"GBP\",\n                entryType: .ecom,\n                intent: DropInTransactionIntentData(\n                    card: .authorisation,\n                    paypal: .purchase  // Choose .purchase or .authorisation\n                ),\n                merchantTransactionId: UUID().uuidString,\n                merchantTransactionDate: { Date() }\n            ),\n            merchantShopperId: \"shopper-123\",\n            ownerId: \"MERCHANT-1\",\n            onGetShopper: {\n                TransactionShopper(id: \"shopper-123\")\n            },\n            onSuccess: { result in\n                print(\"PayPal payment successful!\")\n                print(\"System transaction ID: \\(result.systemTransactionId)\")\n                print(\"Payment method: \\(result.paymentMethod.rawValue)\") // \"Paypal\"\n                \n                // CRITICAL: Verify on backend\n                Task {\n                    await verifyPaymentOnBackend(result)\n                }\n            },\n            onError: { paymentMethod, error in\n                print(\"PayPal payment failed: \\(error.errorMessage)\")\n                Task { @MainActor in\n                    self.errorMessage = \"Payment failed: \\(error.errorMessage)\"\n                }\n            }\n        )\n        \n        do {\n            let instance = try CheckoutDropIn(config: config)\n            await instance.create()\n            dropIn = instance\n        } catch {\n            errorMessage = error.localizedDescription\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"session-configuration-backend","__idx":10},"children":["Session configuration (backend)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Enable PayPal in your session request:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// BACKEND: Create a session with PayPal enabled\nconst sessionRequest = {\n  merchant: \"MERCHANT-1\",\n  site: \"SITE-1\",\n  sessionTimeout: 120,\n  merchantTransactionId: crypto.randomUUID(),\n  transactionMethod: {\n    intent: {\n      paypal: \"Purchase\"  // or \"Authorisation\"\n    }\n  },\n  amounts: {\n    currencyCode: \"GBP\",\n    transactionValue: 99.99\n  },\n  allowedFundingTypes: {\n    wallets: {\n      paypal: {\n        // PayPal configuration from the Unity Portal will be used\n        // You can optionally specify allowedFundingOptions here\n        allowedFundingOptions: [\"paypal\", \"paylater\"]\n      }\n    }\n  },\n  allowTransaction: true,\n  serviceType: \"CheckoutDropIn\"\n};\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"payment-flows","__idx":11},"children":["Payment flows"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Drop-in supports two PayPal payment flows, configured via the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["intent"]}," parameter:"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Pay now (purchase)","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Immediate, single-step payment where funds are captured right away."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"transactionData: DropInTransactionData(\n    amount: Decimal(string: \"99.99\") ?? 0,\n    currency: \"GBP\",\n    entryType: .ecom,\n    intent: DropInTransactionIntentData(\n        card: .authorisation,\n        paypal: .purchase  // Pay Now flow\n    ),\n    merchantTransactionId: UUID().uuidString,\n    merchantTransactionDate: { Date() }\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use this flow for:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Digital products"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Simple orders with immediate fulfillment"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Subscriptions"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Donations"]}]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Confirm payment (authorisation)","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Two-step payment: authorise now, capture later (within 29 days for PayPal)."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"transactionData: DropInTransactionData(\n    amount: Decimal(string: \"149.99\") ?? 0,\n    currency: \"GBP\",\n    entryType: .ecom,\n    intent: DropInTransactionIntentData(\n        card: .authorisation,\n        paypal: .authorisation  // Confirm Payment flow\n    ),\n    merchantTransactionId: UUID().uuidString,\n    merchantTransactionDate: { Date() }\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use this flow for:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Physical products (capture on shipment)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Inventory validation needed"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Final amount may change (shipping, taxes)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Complex order workflows"]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"handling-responses","__idx":12},"children":["Handling responses"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"paypal-callback-data","__idx":13},"children":["PayPal callback data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a PayPal payment succeeds, your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback receives the same standard result as other payment methods:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"onSuccess: { result in\n    print(\"Payment details:\")\n    print(\"- System transaction ID: \\(result.systemTransactionId)\")\n    print(\"- Merchant transaction ID: \\(result.merchantTransactionId ?? \"N/A\")\")\n    print(\"- Payment method: \\(result.paymentMethod.rawValue)\") // \"Paypal\"\n    \n    // Note: Amount, currency, and other transaction details must be retrieved from backend\n    // PayPal authentication is handled internally by PayPal\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"error-handling","__idx":14},"children":["Error handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle PayPal-specific errors:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"onError: { paymentMethod, error in\n    print(\"Error code: \\(error.errorCode)\")\n    print(\"Error message: \\(error.errorMessage)\")\n    \n    // Handle specific error codes\n    let userMessage: String\n    switch error.errorCode {\n    case \"SDK1117\":\n        userMessage = \"PayPal payment failed. Please try again or use another payment method.\"\n    case \"SDK1120\":\n        userMessage = \"PayPal requires entryType .ecom.\"\n    default:\n        // Fall back to message-based detection\n        if error.errorMessage.localizedCaseInsensitiveContains(\"cancelled\") ||\n           error.errorMessage.localizedCaseInsensitiveContains(\"closed\") {\n            // User intentionally cancelled - don't show error\n            return\n        } else if error.errorMessage.localizedCaseInsensitiveContains(\"insufficient funds\") {\n            userMessage = \"Insufficient funds in PayPal account. Please add funds or use a different payment method.\"\n        } else if error.errorMessage.localizedCaseInsensitiveContains(\"restricted\") {\n            userMessage = \"Your PayPal account is restricted. Please contact PayPal support.\"\n        } else if error.errorMessage.localizedCaseInsensitiveContains(\"declined\") {\n            userMessage = \"Payment declined by PayPal. Please try a different payment method.\"\n        } else {\n            userMessage = \"PayPal payment failed: \\(error.errorMessage)\"\n        }\n    }\n    \n    Task { @MainActor in\n        showError(userMessage)\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"common-error-scenarios","__idx":15},"children":["Common error scenarios"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following table describes common PayPal error scenarios:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Scenario"},"children":["Scenario"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"How to detect"},"children":["How to detect"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Recommended action"},"children":["Recommended action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["PayPal payment failed"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorCode == \"SDK1117\""]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Suggest trying again or using another payment method."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Invalid entry type"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorCode == \"SDK1120\""]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["entryType: .ecom"]}," for PayPal transactions."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["User cancelled"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorMessage"]}," contains \"cancelled\" or \"closed\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No alert needed because the user action was intentional."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Insufficient funds"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorMessage"]}," contains \"insufficient\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Suggest adding funds or using a different payment method."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Account restricted"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorMessage"]}," contains \"restricted\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Direct the user to contact PayPal support."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Payment declined"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorMessage"]}," contains \"declined\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Suggest trying a different payment method."]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal errors include both error codes (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK1117"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK1120"]},") and descriptive messages. Use ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorCode"]}," for programmatic handling and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorMessage"]}," for additional context. Note that ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global.onCancel"]}," is not currently wired for PayPal in Drop-in."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"backend-verification","__idx":16},"children":["Backend verification"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Always verify PayPal payments on your backend to ensure payment success before fulfilling orders:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"onSuccess: { result in\n    // Send to backend for verification\n    Task {\n        do {\n            let response = try await apiClient.post(\"/api/verify-payment\", body: [\n                \"systemTransactionId\": result.systemTransactionId,\n                \"merchantTransactionId\": result.merchantTransactionId ?? \"\"\n            ])\n            \n            if response.success {\n                // Navigate to success screen\n                await MainActor.run {\n                    navigateToSuccess(orderId: response.orderId)\n                }\n            } else {\n                await MainActor.run {\n                    showError(\"Payment verification failed\")\n                }\n            }\n        } catch {\n            print(\"Verification error: \\(error.localizedDescription)\")\n            await MainActor.run {\n                showError(\"Failed to verify payment\")\n            }\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"backend-verification-code","__idx":17},"children":["Backend verification code"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the following backend code to verify PayPal transactions via the PXP API:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// BACKEND: Verify PayPal payment\napp.post('/api/verify-payment', async (req, res) => {\n  const { systemTransactionId, merchantTransactionId } = req.body;\n  \n  try {\n    // Query the PXP API to get transaction details\n    const txnPath = `api/v1/transactions/${systemTransactionId}`;\n    const { authHeader, requestId } = createAuthHeader(\n      txnPath,\n      '',\n      process.env.PXP_TOKEN_ID,\n      process.env.PXP_TOKEN_VALUE\n    );\n    \n    const transaction = await fetch(\n      `https://api-services.pxp.io/${txnPath}`,\n      {\n        headers: {\n          'X-Client-Id': process.env.PXP_CLIENT_ID,\n          'X-Request-Id': requestId,\n          'Authorization': authHeader\n        }\n      }\n    ).then(r => r.json());\n    \n    // Verify transaction state\n    if (transaction.state !== 'Authorised' && transaction.state !== 'Captured') {\n      return res.json({ success: false, error: 'Transaction not successful' });\n    }\n    \n    // Verify merchant transaction ID matches\n    if (transaction.merchantTransactionId !== merchantTransactionId) {\n      return res.json({ success: false, error: 'Transaction ID mismatch' });\n    }\n    \n    // Verify amount matches expected amount from your order records\n    const order = await getOrderByMerchantTransactionId(merchantTransactionId);\n    const txnAmount = transaction.amounts?.transactionValue || transaction.amount || 0;\n    if (Math.abs(txnAmount - order.amount) > 0.01) {\n      return res.json({ success: false, error: 'Amount mismatch' });\n    }\n    \n    // PayPal payments show as PayPal funding type\n    const fundingType = transaction.fundingData?.fundingType || \n                       transaction.fundingType || \n                       'Unknown';\n    if (fundingType !== 'PayPal') {\n      return res.json({ success: false, error: 'Invalid funding type' });\n    }\n    \n    // Fulfill order\n    const orderId = await fulfillOrder(transaction);\n    \n    return res.json({ success: true, orderId });\n    \n  } catch (error) {\n    console.error('Verification error:', error);\n    return res.json({ success: false, error: 'Verification failed' });\n  }\n});\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"advanced-paypal-flows","__idx":18},"children":["Advanced PayPal flows"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"paypal-vaulting-saved-paypal-account","__idx":19},"children":["PayPal vaulting (saved PayPal account)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal vaulting allows returning customers to pay with a saved PayPal account. When enabled, customers who have previously connected their PayPal account can use it for checkout."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"how-it-works-1","__idx":20},"children":["How it works"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer pays with PayPal and agrees to save their account."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["PayPal vaults the account and returns a vault ID."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["On return visit, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," provides the shopper ID."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Drop-in displays the saved PayPal account for payment."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer completes the payment flow with their saved PayPal account."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"enable-paypal-vaulting","__idx":21},"children":["Enable PayPal vaulting"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," to enable vaulting:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import SwiftUI\nimport PXPCheckoutSDK\n\n@MainActor\nfinal class CheckoutViewModel: ObservableObject {\n    @Published var dropIn: CheckoutDropIn?\n    @Published var errorMessage: String?\n    \n    func loadDropIn() async {\n        // Fetch session from backend (with PayPal enabled)\n        guard let sessionData = await fetchSessionFromBackend() else {\n            errorMessage = \"Failed to create session\"\n            return\n        }\n        \n        // Initialise Drop-in\n        let config = CheckoutDropInConfig(\n            environment: .test,\n            session: sessionData,\n            transactionData: DropInTransactionData(\n                amount: Decimal(string: \"99.99\") ?? 0,\n                currency: \"GBP\",\n                entryType: .ecom,\n                intent: DropInTransactionIntentData(\n                    card: .purchase,\n                    paypal: .purchase\n                ),\n                merchantTransactionId: UUID().uuidString,\n                merchantTransactionDate: { Date() }\n            ),\n            merchantShopperId: \"shopper-123\",\n            ownerId: \"MERCHANT-1\",\n            // REQUIRED: Provide shopper ID to enable PayPal vaulting\n            onGetShopper: {\n                let user = getCurrentUser()\n                return TransactionShopper(id: user.shopperId) // e.g., TransactionShopper(id: \"shopper-123\")\n            },\n            onSuccess: { result in\n                Task {\n                    await verifyPaymentOnBackend(result)\n                    await MainActor.run {\n                        navigateToSuccess()\n                    }\n                }\n            },\n            onError: { paymentMethod, error in\n                print(\"PayPal payment failed: \\(error.errorMessage)\")\n                Task { @MainActor in\n                    self.errorMessage = \"Payment failed: \\(error.errorMessage)\"\n                }\n            }\n        )\n        \n        do {\n            let instance = try CheckoutDropIn(config: config)\n            await instance.create()\n            dropIn = instance\n        } catch {\n            errorMessage = error.localizedDescription\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," returns a shopper ID, the SDK automatically:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Fetches the PayPal user ID token from the PXP API."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Displays saved PayPal accounts for faster checkout."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handles vault setup during the first payment."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"paypal-vaulting-configuration","__idx":22},"children":["PayPal vaulting configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PayPal vaulting is enabled by implementing ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," and configuring the consent component:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"CheckoutDropInConfig(\n    // ... other config\n    onGetShopper: {\n        let user = getCurrentUser()\n        return TransactionShopper(id: user.shopperId)  // Required for vaulting\n    },\n    methodConfig: DropInMethodConfig(\n        global: DropInGlobalConfig(\n            // Provide fallback consent value\n            onGetConsent: { paymentMethod in\n                return paymentMethod == .paypal\n            }\n        ),\n        paypal: DropInPaypalConfig(\n            // Control whether Drop-in creates the PayPal consent checkbox\n            consentComponent: true\n        )\n    )\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Requirements for PayPal vaulting:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," must return a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["TransactionShopper"]}," with a non-empty ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.paypal.consentComponent"]}," controls whether Drop-in creates the consent checkbox."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Consent is sent as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["vaultingConsent"]}," when the shopper opts in or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetConsent(.paypal)"]}," returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The SDK automatically fetches the PayPal user ID token and handles vault setup during the first payment."]}]}]},"headings":[{"value":"PayPal","id":"paypal","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Key benefits","id":"key-benefits","depth":3},{"value":"How it works","id":"how-it-works","depth":2},{"value":"Configuration","id":"configuration","depth":2},{"value":"Configuration properties","id":"configuration-properties","depth":3},{"value":"Settings used from global configuration","id":"settings-used-from-global-configuration","depth":3},{"value":"Complete example","id":"complete-example","depth":3},{"value":"PayPal requirements","id":"paypal-requirements","depth":3},{"value":"Implementation","id":"implementation","depth":2},{"value":"Session configuration (backend)","id":"session-configuration-backend","depth":3},{"value":"Payment flows","id":"payment-flows","depth":3},{"value":"Handling responses","id":"handling-responses","depth":2},{"value":"PayPal callback data","id":"paypal-callback-data","depth":3},{"value":"Error handling","id":"error-handling","depth":3},{"value":"Common error scenarios","id":"common-error-scenarios","depth":4},{"value":"Backend verification","id":"backend-verification","depth":2},{"value":"Backend verification code","id":"backend-verification-code","depth":3},{"value":"Advanced PayPal flows","id":"advanced-paypal-flows","depth":2},{"value":"PayPal vaulting (saved PayPal account)","id":"paypal-vaulting-saved-paypal-account","depth":3},{"value":"How it works","id":"how-it-works-1","depth":4},{"value":"Enable PayPal vaulting","id":"enable-paypal-vaulting","depth":4},{"value":"PayPal vaulting configuration","id":"paypal-vaulting-configuration","depth":4}],"frontmatter":{"seo":{"title":"PayPal"}},"lastModified":"2026-09-17T12:55:47.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/drop-in/ios/paypal","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}