{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","admonition","tabs","tab","br","details","required"]},"type":"markdown"},"seo":{"title":"Withdrawal flow","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":"withdrawal-flow","__idx":0},"children":["Withdrawal flow"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Send payouts to customers using PayPal account credentials provided by your backend."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The withdrawal flow is designed for customers whose PayPal account credentials your backend provides. This provides a streamlined experience — the customer simply reviews the payout details and confirms."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This flow uses the receiver and submission components together, displaying the PayPal account information and providing a \"Withdraw\" button."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"payout-flow","__idx":2},"children":["Payout flow"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The withdrawal flow consists of five key steps for customer payouts."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-display-payout-details","__idx":3},"children":["Step 1: Display payout details"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The customer sees their PayPal email displayed alongside the payout amount. The receiver component shows the wallet destination, optionally masked for privacy."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-submission","__idx":4},"children":["Step 2: Submission"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The customer taps the \"Withdraw with PayPal\" button. The SDK validates the payout configuration and PayPal account details before proceeding. If validation fails, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," is triggered."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-3-payout-approval-sdk-managed-mode","__idx":5},"children":["Step 3: Payout approval (SDK-managed mode)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPrePayoutSubmit"]}," callback is triggered, giving you the opportunity to show a confirmation dialog or perform additional validation before the payout executes."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Return a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PrePayoutSubmitResult"]}," with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["isApproved: true"]}," to proceed with the payout, or return ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["nil"]}," to cancel."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-4-payout-execution","__idx":6},"children":["Step 4: Payout execution"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For SDK-managed mode, the SDK automatically sends the payout request to the PXP gateway. For backend-managed mode, your backend triggers the payout via API."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-5-payout-result","__idx":7},"children":["Step 5: Payout result"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostPayout"]}," callback receives the transaction result. You can display a success message and navigate the customer to a confirmation screen."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"implementation","__idx":8},"children":["Implementation"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"before-you-start","__idx":9},"children":["Before you start"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To use the withdrawal flow for payouts:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Ensure your PayPal merchant account is onboarded with PXP."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Have sufficient funds in your gateway balance to cover payout amounts and fees."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Have PayPal account credentials provided by your backend."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1-configure-your-sdk","__idx":10},"children":["Step 1: Configure your SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set up your SDK configuration with PayPal account credentials from your backend to trigger the withdrawal flow."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import PXPCheckoutSDK\n\n// Get session data from your backend\nlet sessionData = try await fetchSessionData()\n\n// Get customer wallet credentials from your backend\nlet customerWallet = try await getCustomerWalletFromBackend(userId: currentUserId)\n\n// Configure transaction data for payout\nlet transactionData = TransactionData(\n    amount: Decimal(150.00),\n    currency: \"USD\",\n    entryType: .ecom,\n    intent: TransactionIntentData(\n        card: nil,\n        paypal: .payout\n    ),\n    merchantTransactionId: \"payout-\\(UUID().uuidString)\",\n    merchantTransactionDate: { Date() }\n)\n\n// Configure PayPal with wallet credentials from backend (withdrawal flow)\nlet paypalConfig = PayPalConfig(\n    payout: PayPalPayoutConfig(\n        paypalWallet: PayPalWallet(\n            email: customerWallet.email,       // PayPal email from backend\n            payerId: customerWallet.payerId,   // Required: payer ID from backend\n            proceedPayoutWithSdk: true\n        )\n    )\n)\n\n// Initialise the SDK\nlet checkoutConfig = CheckoutConfig(\n    environment: .test,  // Use .live for production\n    session: sessionData,\n    transactionData: transactionData,\n    merchantShopperId: \"customer-123\",\n    ownerId: \"your-owner-id\",\n    paypalConfig: paypalConfig\n)\n\nlet pxpCheckout = try PxpCheckout.initialize(config: checkoutConfig)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The withdrawal flow requires PayPal account credentials provided by your backend in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PayPalWallet"]},":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["payerId"]}," is ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["required"]}," for payout execution"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["email"]}," is optional but recommended for display purposes in the receiver component"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// Configure with credentials from your backend\nPayPalWallet(\n    email: \"user@example.com\",  // Optional, for display\n    payerId: \"PAYERID123\",       // Required for payout\n    proceedPayoutWithSdk: true\n)\n","lang":"swift"},"children":[]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2-create-the-components","__idx":11},"children":["Step 2: Create the components"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the amount, receiver, and submission components to build the withdrawal experience."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The submission component automatically reads data from the amount and receiver components when the user taps \"Withdraw\":"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Amount value from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PayoutAmountComponent"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Receiver email from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PayPalPayoutReceiverComponent"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Payer ID from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PayPalWallet"]}," configuration"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You don't need to manually wire these components together - the SDK handles data collection automatically."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"// Create the amount display component\nlet amountComponent = try pxpCheckout.create(\n    .payoutAmount,\n    componentConfig: PayoutAmountComponentConfig(\n        label: \"Withdrawal Amount\"\n    )\n)\n\n// Create the PayPal receiver display component\nlet receiverComponent = try pxpCheckout.create(\n    .paypalPayoutReceiver,\n    componentConfig: PayPalPayoutReceiverComponentConfig(\n        label: \"PayPal Account\",\n        showMaskToggle: true,  // Display a toggle (eye icon) to show/hide email\n        applyMask: true        // Start with email masked\n    )\n)\n\n// Create the payout submission component\nlet submissionComponent = try pxpCheckout.create(\n    .payoutSubmission,\n    componentConfig: PayoutSubmissionComponentConfig(\n        submitText: \"Withdraw with PayPal\",\n        \n        // OPTIONAL: Called when button is clicked (before validation)\n        onClick: {\n            print(\"Withdrawal button clicked\")\n            // Track analytics, show loading state, etc.\n        },\n        \n        // OPTIONAL: Called before payout execution (SDK-managed mode only)\n        onPrePayoutSubmit: {\n            let confirmed = await showConfirmationDialog()\n            return confirmed ? PrePayoutSubmitResult(isApproved: true) : nil\n        },\n        \n        // OPTIONAL: Called when payout completes (SDK-managed mode only)\n        onPostPayout: { result in\n            print(\"Payout successful:\", result.merchantTransactionId)\n            showSuccessMessage(\"Your withdrawal has been processed!\")\n            navigateToSuccessScreen(transactionId: result.merchantTransactionId)\n        },\n        \n        // OPTIONAL: Called when user cancels\n        onCancel: {\n            print(\"Withdrawal cancelled by user\")\n            showMessage(\"No problem! Withdraw when you're ready.\")\n        },\n        \n        // OPTIONAL: Called on any error\n        onError: { error in\n            print(\"Error occurred:\", error.errorMessage)\n            showErrorMessage(\"Something went wrong. Please try again.\")\n        }\n    )\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-3-render-the-components","__idx":12},"children":["Step 3: Render the components"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Render the components in your SwiftUI view."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"struct WithdrawalFlowView: View {\n    @State private var amountComponent: BaseComponent?\n    @State private var receiverComponent: BaseComponent?\n    @State private var submissionComponent: BaseComponent?\n    \n    var body: some View {\n        VStack(spacing: 20) {\n            Text(\"Withdraw Funds\")\n                .font(.title)\n            \n            // Amount display\n            if let amountComponent = amountComponent {\n                amountComponent.buildContent()\n                    .frame(height: 60)\n            }\n            \n            // Receiver display\n            if let receiverComponent = receiverComponent {\n                receiverComponent.buildContent()\n                    .frame(height: 60)\n            }\n            \n            Spacer()\n            \n            // Submit button\n            if let submissionComponent = submissionComponent {\n                submissionComponent.buildContent()\n                    .frame(height: 50)\n            }\n        }\n        .padding()\n        .onAppear {\n            initialiseComponents()\n        }\n    }\n    \n    private func initialiseComponents() {\n        Task {\n            do {\n                let components = try await createPayoutComponents()\n                await MainActor.run {\n                    self.amountComponent = components.amount\n                    self.receiverComponent = components.receiver\n                    self.submissionComponent = components.submission\n                }\n            } catch {\n                print(\"Failed to initialise: \\(error)\")\n            }\n        }\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-4-handle-payout-modes","__idx":13},"children":["Step 4: Handle payout modes"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["proceedPayoutWithSdk"]}," parameter controls whether the SDK or your backend executes the payout. The default value is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]}," (backend-managed)."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"SDK-managed payout","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["proceedPayoutWithSdk: true"]},", the SDK handles the complete flow:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer taps \"Withdraw with PayPal\"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPrePayoutSubmit"]}," is called for approval."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The SDK executes the payout automatically."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostPayout"]}," is called with the result."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let paypalConfig = PayPalConfig(\n    payout: PayPalPayoutConfig(\n        paypalWallet: PayPalWallet(\n            email: customerWallet.email,\n            payerId: customerWallet.payerId,\n            proceedPayoutWithSdk: true  // SDK handles payout execution\n        )\n    )\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["With ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["proceedPayoutWithSdk: true"]},", both ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPrePayoutSubmit"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostPayout"]}," callbacks are triggered. The SDK manages the payout execution after approval."]}]}]},{"$$mdtype":"Tag","name":"TabItemFragment","attributes":{"label":"Backend-managed payout","disable":false},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["proceedPayoutWithSdk: false"]}," (default), your backend controls payout execution:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer taps \"Withdraw with PayPal\"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Components display the payout details."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your backend must execute the payout via the PXP API."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let paypalConfig = PayPalConfig(\n    payout: PayPalPayoutConfig(\n        paypalWallet: PayPalWallet(\n            email: customerWallet.email,\n            payerId: customerWallet.payerId,\n            proceedPayoutWithSdk: false  // Backend controls (default)\n        )\n    )\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["With ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["proceedPayoutWithSdk: false"]},", the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPrePayoutSubmit"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostPayout"]}," callbacks aren't triggered. The SDK only displays payout information. Your backend must execute the payout via the PXP API independently."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This mode is ideal for:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Custom validation or compliance checks"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Multi-step approval workflows"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Delayed or scheduled payouts"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Batch processing"]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-5-handle-errors","__idx":14},"children":["Step 5: Handle errors"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement comprehensive error handling for the withdrawal process."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"let submissionComponent = try pxpCheckout.create(\n    .payoutSubmission,\n    componentConfig: PayoutSubmissionComponentConfig(\n        submitText: \"Withdraw with PayPal\",\n        onPrePayoutSubmit: {\n            return await showConfirmationDialog()\n        },\n        \n        onError: { error in\n            print(\"Payout error:\", error)\n            \n            // Handle specific error types\n            let userMessage: String\n            \n            switch error.errorCode {\n            case \"SDK0803\":\n                userMessage = \"PayPal receiver information is missing.\"\n            case \"SDK0805\":\n                userMessage = \"Invalid receiver type. Only email is supported.\"\n            case \"SDK0808\":\n                userMessage = \"Invalid PayPal email format.\"\n            case \"SDK0809\":\n                userMessage = \"PayPal account information is missing.\"\n            case \"SDK0810\", \"SDK0811\", \"SDK0812\":\n                userMessage = \"Invalid payout amount. Please contact support.\"\n            case \"SDK0817\":\n                userMessage = \"PayPal account identifier is too long.\"\n            case \"SDK0818\":\n                userMessage = \"Invalid PayPal account.\"\n            case \"SDK0819\":\n                userMessage = \"Payout transaction failed. Please try again.\"\n            default:\n                userMessage = \"An error occurred. Please try again or contact support.\"\n            }\n            \n            showErrorAlert(userMessage)\n        }\n    )\n)\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For a complete list of error codes including ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK0812"]},"-",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK0816"]}," (amount/currency validation), see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/paypal/payouts/data-validation"},"children":["Data validation"]},"."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"example","__idx":15},"children":["Example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following example shows a complete withdrawal flow implementation."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"import SwiftUI\nimport PXPCheckoutSDK\n\nstruct PayoutWithdrawalFlowView: View {\n    @State private var pxpCheckout: PxpCheckout?\n    @State private var amountComponent: BaseComponent?\n    @State private var receiverComponent: BaseComponent?\n    @State private var submissionComponent: BaseComponent?\n    @State private var isLoading = true\n    @State private var errorMessage: String?\n    @State private var showApprovalAlert = false\n    @State private var pendingApprovalContinuation: CheckedContinuation<PrePayoutSubmitResult?, Never>?\n    \n    let currentUserId: String = \"user123\"\n    var payoutAmount: Double = 0\n    var customerEmail: String = \"\"\n    \n    var body: some View {\n        VStack(spacing: 20) {\n            Text(\"Withdraw Funds\")\n                .font(.title)\n                .fontWeight(.bold)\n            \n            if isLoading {\n                ProgressView(\"Initialising...\")\n            } else if let error = errorMessage {\n                Text(error)\n                    .foregroundColor(.red)\n                    .multilineTextAlignment(.center)\n            } else {\n                // Amount component\n                if let amountComponent = amountComponent {\n                    amountComponent.buildContent()\n                        .frame(height: 60)\n                }\n                \n                // Receiver component\n                if let receiverComponent = receiverComponent {\n                    receiverComponent.buildContent()\n                        .frame(height: 60)\n                }\n                \n                Spacer()\n                \n                // Submission button\n                if let submissionComponent = submissionComponent {\n                    submissionComponent.buildContent()\n                        .frame(height: 50)\n                }\n            }\n        }\n        .padding()\n        .alert(\"Confirm Payout\", isPresented: $showApprovalAlert) {\n            Button(\"Cancel\", role: .cancel) {\n                pendingApprovalContinuation?.resume(returning: nil)\n                pendingApprovalContinuation = nil\n            }\n            Button(\"Confirm\") {\n                pendingApprovalContinuation?.resume(returning: \n                    PrePayoutSubmitResult(isApproved: true)\n                )\n                pendingApprovalContinuation = nil\n            }\n        } message: {\n            Text(\"Send $\\(String(format: \"%.2f\", payoutAmount)) to \\(customerEmail)?\")\n        }\n        .onAppear {\n            initialisePayoutFlow()\n        }\n    }\n    \n    private func initialisePayoutFlow() {\n        Task {\n            do {\n                isLoading = true\n                \n                // Get session data from backend\n                let sessionResponse = try await getSessionDataFromBackend()\n                \n                payoutAmount = sessionResponse.payoutAmount\n                customerEmail = sessionResponse.customerWallet.email\n                \n                // Configure transaction data\n                let transactionData = TransactionData(\n                    amount: Decimal(sessionResponse.payoutAmount),\n                    currency: sessionResponse.currency,\n                    entryType: .ecom,\n                    intent: TransactionIntentData(\n                        card: nil,\n                        paypal: .payout\n                    ),\n                    merchantTransactionId: \"payout-\\(UUID().uuidString)\",\n                    merchantTransactionDate: { Date() }\n                )\n                \n                // Configure PayPal with wallet credentials from backend\n                let paypalConfig = PayPalConfig(\n                    payout: PayPalPayoutConfig(\n                        paypalWallet: PayPalWallet(\n                            email: sessionResponse.customerWallet.email,\n                            payerId: sessionResponse.customerWallet.payerId,\n                            proceedPayoutWithSdk: true\n                        )\n                    )\n                )\n                \n                // Initialise SDK\n                let checkoutConfig = CheckoutConfig(\n                    environment: .test,\n                    session: sessionResponse.session,\n                    transactionData: transactionData,\n                    merchantShopperId: currentUserId,\n                    ownerId: \"Unity\",\n                    paypalConfig: paypalConfig\n                )\n                \n                let pxpCheckout = try PxpCheckout.initialize(config: checkoutConfig)\n                \n                // Create components\n                let amountComponent = try pxpCheckout.create(\n                    .payoutAmount,\n                    componentConfig: PayoutAmountComponentConfig(\n                        label: \"Withdrawal Amount\"\n                    )\n                )\n                \n                let receiverComponent = try pxpCheckout.create(\n                    .paypalPayoutReceiver,\n                    componentConfig: PayPalPayoutReceiverComponentConfig(\n                        label: \"PayPal Account\",\n                        showMaskToggle: true,\n                        applyMask: true\n                    )\n                )\n                \n                let submissionComponent = try pxpCheckout.create(\n                    .payoutSubmission,\n                    componentConfig: PayoutSubmissionComponentConfig(\n                        submitText: \"Withdraw with PayPal\",\n                        \n                        onPrePayoutSubmit: { [self] in\n                            return await showPayoutApproval()\n                        },\n                        \n                        onPostPayout: { result in\n                            handlePayoutSuccess(result)\n                        },\n                        \n                        onCancel: {\n                            handleCancellation()\n                        },\n                        \n                        onError: { error in\n                            handleError(error)\n                        }\n                    )\n                )\n                \n                await MainActor.run {\n                    self.pxpCheckout = pxpCheckout\n                    self.amountComponent = amountComponent\n                    self.receiverComponent = receiverComponent\n                    self.submissionComponent = submissionComponent\n                    self.isLoading = false\n                }\n                \n            } catch {\n                await MainActor.run {\n                    self.errorMessage = \"Failed to initialise: \\(error.localizedDescription)\"\n                    self.isLoading = false\n                }\n            }\n        }\n    }\n    \n    private func showPayoutApproval() async -> PrePayoutSubmitResult? {\n        return await withCheckedContinuation { continuation in\n            Task { @MainActor in\n                self.pendingApprovalContinuation = continuation\n                self.showApprovalAlert = true\n            }\n        }\n    }\n    \n    private func handlePayoutSuccess(_ result: MerchantSubmitResult) {\n        print(\"🎉 Payout successful!\")\n        print(\"Merchant TX ID: \\(result.merchantTransactionId)\")\n        print(\"System TX ID: \\(result.systemTransactionId)\")\n        \n        // Show success message and navigate\n        // showSuccessMessage(\"Withdrawal completed successfully!\")\n        // navigateToSuccessScreen()\n    }\n    \n    private func handleCancellation() {\n        print(\"User cancelled payout\")\n        // showMessage(\"No problem! Withdraw when you're ready.\")\n    }\n    \n    private func handleError(_ error: BaseSdkException) {\n        print(\"❌ Error: \\(error.errorCode) - \\(error.errorMessage)\")\n        errorMessage = \"Payout failed: \\(error.errorMessage)\"\n    }\n    \n    // Backend API call\n    \n    struct SessionResponse {\n        let session: SessionData\n        let payoutAmount: Double\n        let currency: String\n        let customerWallet: (email: String, payerId: String)\n    }\n    \n    private func getSessionDataFromBackend() async throws -> SessionResponse {\n        // Call your backend endpoint: POST /api/sessions/payout\n        // Returns session data and customer wallet details\n        fatalError(\"Implement your backend call\")\n    }\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"callback-data","__idx":16},"children":["Callback data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This section describes the data received by the different callbacks as part of the withdrawal flow."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onclick","__idx":17},"children":["onClick"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onClick"]}," callback is triggered when the user taps the withdrawal button, before validation begins."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"onClick: {\n    print(\"Withdrawal button clicked\")\n    // Track analytics, show loading state, etc.\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback receives no parameters and is useful for analytics tracking and UI state management."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onprepayoutsubmit","__idx":18},"children":["onPrePayoutSubmit"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPrePayoutSubmit"]}," callback is called before payout execution. Return an object indicating whether to proceed."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is only triggered when ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["proceedPayoutWithSdk: true"]},". If set to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]},", this callback won't be called and your backend must handle payout execution independently."]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"onPrePayoutSubmit: {\n    let approved = await showConfirmationDialog()\n    return approved ? PrePayoutSubmitResult(isApproved: true) : nil\n}\n","lang":"swift"},"children":[]},{"$$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":"Return property"},"children":["Return property"]},{"$$mdtype":"Tag","name":"th","attributes":{"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":["isApproved"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["Bool"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Required","attributes":{},"children":[]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Whether to proceed with the payout. Return ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["nil"]}," to cancel."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onpostpayout","__idx":19},"children":["onPostPayout"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostPayout"]}," callback receives the payout result when the transaction completes successfully."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"onPostPayout: { result in\n    print(\"Transaction ID:\", result.systemTransactionId)\n}\n","lang":"swift"},"children":[]},{"$$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":"Parameter"},"children":["Parameter"]},{"$$mdtype":"Tag","name":"th","attributes":{"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":["result"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["MerchantSubmitResult"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Object containing transaction identifiers."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.merchantTransactionId"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your unique identifier for the transaction."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.systemTransactionId"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The system's unique identifier for the transaction."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"oncancel","__idx":20},"children":["onCancel"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onCancel"]}," callback is triggered when the user cancels the payout."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"onCancel: {\n    print(\"User cancelled payout\")\n    showMessage(\"You can try again anytime.\")\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onerror","__idx":21},"children":["onError"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onError"]}," callback receives error information when the payout fails."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"onError: { error in\n    print(\"Error:\", error.errorCode, error.errorMessage)\n}\n","lang":"swift"},"children":[]},{"$$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":"Parameter"},"children":["Parameter"]},{"$$mdtype":"Tag","name":"th","attributes":{"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":["error"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["BaseSdkException"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The error object containing details about what went wrong."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorCode"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The error code identifier (e.g., \"SDK0803\")."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.errorMessage"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Human-readable error message describing what went wrong."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.localizedDescription"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["String"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The localised error description (same as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["errorMessage"]},")."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"whats-next","__idx":22},"children":["What's next?"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Once you've implemented the withdrawal flow, explore these additional resources:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/paypal/payouts/submission-component"},"children":["Payout submission component"]},": Configure the submission button's appearance and behaviour."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/paypal/payouts/receiver-component"},"children":["Payout receiver component"]},": Customise the receiver display."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/paypal/payouts/amount-component"},"children":["Payout amount component"]},": Configure the amount display."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/paypal/payouts/events"},"children":["Events"]},": Handle additional payout events and callbacks."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/ios/paypal/payouts/testing"},"children":["Testing"]},": Test your payout integration."]}]}]},"headings":[{"value":"Withdrawal flow","id":"withdrawal-flow","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Payout flow","id":"payout-flow","depth":2},{"value":"Step 1: Display payout details","id":"step-1-display-payout-details","depth":3},{"value":"Step 2: Submission","id":"step-2-submission","depth":3},{"value":"Step 3: Payout approval (SDK-managed mode)","id":"step-3-payout-approval-sdk-managed-mode","depth":3},{"value":"Step 4: Payout execution","id":"step-4-payout-execution","depth":3},{"value":"Step 5: Payout result","id":"step-5-payout-result","depth":3},{"value":"Implementation","id":"implementation","depth":2},{"value":"Before you start","id":"before-you-start","depth":3},{"value":"Step 1: Configure your SDK","id":"step-1-configure-your-sdk","depth":3},{"value":"Step 2: Create the components","id":"step-2-create-the-components","depth":3},{"value":"Step 3: Render the components","id":"step-3-render-the-components","depth":3},{"value":"Step 4: Handle payout modes","id":"step-4-handle-payout-modes","depth":3},{"value":"Step 5: Handle errors","id":"step-5-handle-errors","depth":3},{"value":"Example","id":"example","depth":2},{"value":"Callback data","id":"callback-data","depth":2},{"value":"onClick","id":"onclick","depth":3},{"value":"onPrePayoutSubmit","id":"onprepayoutsubmit","depth":3},{"value":"onPostPayout","id":"onpostpayout","depth":3},{"value":"onCancel","id":"oncancel","depth":3},{"value":"onError","id":"onerror","depth":3},{"value":"What's next?","id":"whats-next","depth":2}],"frontmatter":{"seo":{"title":"Withdrawal flow"}},"lastModified":"2026-04-13T14:44:58.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/components/ios/paypal/payouts/withdrawal-flow","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}