{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","br","details","admonition"]},"type":"markdown"},"seo":{"title":"Events","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":"events","__idx":0},"children":["Events"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement callbacks to customise your Drop-in payment flow."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Drop-in provides a unified event system that works consistently across all payment methods. You can use these callbacks to inject your own business logic and user experience customisations into the payment flow at critical moments. They ensure that while the SDK handles the complex technical aspects of payment processing, you retain full control over the customer experience and can seamlessly integrate payments into your broader business workflows and systems."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Callbacks enable you to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Validate business rules before payments proceed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display custom loading states and progress indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Show user-friendly error messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Tailor user interfaces to match your brand's look and feel."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Integrate with your own systems for fraud detection or customer management."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Control exactly how your customers experience both successful and failed transactions."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track analytics and monitor payment performance."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Handle shipping calculations and address validation in real-time (PayPal, Apple Pay, Google Pay)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Implement card-on-file functionality for returning customers."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Offer alternative payment methods when errors occur."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your callbacks receive normalised data regardless of whether the customer paid with cards, PayPal, Google Pay, or Apple Pay."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All events are optional except ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]},", which is required for card-on-file functionality."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"supported-events","__idx":2},"children":["Supported events"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"ongetshopper","__idx":3},"children":["onGetShopper"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is required to provide shopper information for card-on-file functionality, allowing returning customers to use saved payment methods."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Provide shopper ID for logged-in users."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Generate anonymous shopper ID for guest checkout."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Enable card-on-file for returning customers."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Associate payment methods with customer accounts."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data","__idx":4},"children":["Event data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback receives no parameters and must return a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Promise<Shopper>"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"return-value","__idx":5},"children":["Return value"]},{"$$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":"Property"},"children":["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":["id"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["string"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Unique shopper identifier. Use customer ID for logged-in users or generate a unique ID for guests."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation","__idx":6},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"const checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  onGetShopper: () => {\n    // For logged-in users, return their customer ID\n    const customerId = getCurrentCustomerId();\n    if (customerId) {\n      return Promise.resolve({\n        id: customerId\n      });\n    }\n    \n    // For guest users, generate or retrieve a session-based ID\n    const guestId = getOrCreateGuestId();\n    return Promise.resolve({\n      id: guestId\n    });\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is required for Checkout Drop-in initialisation. The shopper ID is used to store and retrieve saved payment methods. For guests, generate a unique ID (e.g., UUID) that persists across the session. For registered users, use their customer/account ID from your system."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onbeforesubmit","__idx":7},"children":["onBeforeSubmit"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered when a payment method is selected and the user is about to submit payment. This is your last chance to validate data or cancel the payment before it's processed."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Perform final validation before payment submission."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Check inventory availability."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify customer account status."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display confirmation dialogs."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track analytics events."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Perform fraud checks."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-1","__idx":8},"children":["Event data"]},{"$$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":["before"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["any"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Payment selection details containing information about the selected payment method."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"return-value-1","__idx":9},"children":["Return value"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["undefined"]},": Continue with payment submission."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]},": Cancel payment submission."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Promise<boolean>"]},": Async validation (resolved value determines whether to proceed)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-1","__idx":10},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\n\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  onBeforeSubmit: async (before) => {\n    console.log('Payment method selected:', before);\n    \n    // Track analytics\n    analytics.track('payment_initiated', {\n      paymentMethod: before\n    });\n    \n    // Show confirmation dialog\n    const confirmed = await showConfirmationDialog({\n      title: 'Confirm Payment',\n      message: 'Proceed with payment?',\n      confirmText: 'Confirm',\n      cancelText: 'Cancel'\n    });\n    \n    if (!confirmed) {\n      console.log('Payment cancelled by user');\n      return false; // Cancel payment\n    }\n    \n    // Check inventory availability\n    const inventoryCheck = await fetch('/api/check-inventory', {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ items: getCartItems() })\n    }).then(r => r.json());\n    \n    if (!inventoryCheck.available) {\n      alert('Some items are no longer available. Please review your cart.');\n      return false; // Cancel payment\n    }\n    \n    // Verify customer account is in good standing\n    const accountCheck = await fetch('/api/verify-account', {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ customerId: getCurrentCustomerId() })\n    }).then(r => r.json());\n    \n    if (!accountCheck.valid) {\n      alert('Account verification failed. Please contact support.');\n      return false; // Cancel payment\n    }\n    \n    console.log('All checks passed, proceeding with payment');\n    return true; // Continue with payment\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Simple validation example:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"onBeforeSubmit: (before) => {\n  // Simple synchronous validation\n  if (!isValidOrder()) {\n    alert('Please complete all required fields');\n    return false; // Payment will not proceed\n  }\n  \n  return true; // Payment will proceed\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onsubmit","__idx":11},"children":["onSubmit"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered when payment processing begins, after ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onBeforeSubmit"]}," validation passes. Use this to show loading indicators and disable UI elements."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Show loading spinners or progress indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Disable submit buttons to prevent double-submission."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display \"Processing payment...\" messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Update UI to show payment is in progress."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track analytics for payment submission."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-2","__idx":12},"children":["Event data"]},{"$$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":["submit"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["any"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Payment submission details containing information about the payment being processed."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-2","__idx":13},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"const checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  onSubmit: (submit) => {\n    console.log('Processing payment with:', submit);\n    \n    // Show loading overlay\n    const overlay = document.getElementById('loading-overlay');\n    if (overlay) {\n      overlay.style.display = 'flex';\n      overlay.querySelector('.message').textContent = 'Processing payment...';\n    }\n    \n    // Disable submit button to prevent double-submission\n    const submitBtn = document.querySelector('button[type=\"submit\"]');\n    if (submitBtn) {\n      submitBtn.disabled = true;\n      submitBtn.textContent = 'Processing...';\n    }\n    \n    // Track analytics\n    analytics.track('payment_processing', {\n      paymentMethod: submit\n    });\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Complete loading state management:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"let loadingTimeout;\n\nonSubmit: (submit) => {\n  // Show loading state\n  setLoadingState(true);\n  \n  // Set timeout in case payment takes too long\n  loadingTimeout = setTimeout(() => {\n    showWarning('Payment is taking longer than expected. Please wait...');\n  }, 10000); // 10 seconds\n  \n  // Track start time for performance monitoring\n  window.paymentStartTime = Date.now();\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onsuccess","__idx":14},"children":["onSuccess"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered after payment succeeds. It receives the final transaction result from the payment processing system."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Verify payment on your backend (REQUIRED)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Redirect to success page after verification."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display success messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track successful payment analytics."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Update stock levels for purchased items."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Send order confirmation emails to customers."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Clear shopping cart."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-3","__idx":15},"children":["Event data"]},{"$$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":"Event data"},"children":["Event data"]},{"$$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":["BaseSubmitResult"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment processing result from PXP's backend."]}]},{"$$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":["Unity's system transaction identifier. Use for backend verification."]}]},{"$$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 | undefined"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your unique transaction identifier (optional)."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.paymentMethod"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["PaymentMethod"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The payment method used: ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.Card"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.Paypal"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.GooglePay"]},", or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod.ApplePay"]},"."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BaseSubmitResult"]}," type:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"interface BaseSubmitResult {\n  systemTransactionId: string;\n  merchantTransactionId?: string;  // Optional\n  paymentMethod: PaymentMethod;\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["While ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authenticationId"]}," is available in some payment responses, you should always retrieve and verify authentication details on your backend by querying the PXP API with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["systemTransactionId"]}," for secure, production-ready implementations."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback is a frontend event and can be manipulated by malicious users. Never fulfill orders based solely on this callback. Always verify payments on your backend using Unity webhooks or the Query Transaction API before fulfilling orders."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-3","__idx":16},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\nimport { BaseSubmitResult } from '@pxpio/web-components-sdk/src/checkoutDropIn/types/BaseSubmitResult';\n\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  onSuccess: async (result: BaseSubmitResult) => {\n    console.log('Payment successful (frontend notification only)');\n    console.log('System transaction ID:', result.systemTransactionId);\n    console.log('Merchant transaction ID:', result.merchantTransactionId);\n    console.log('Payment method:', result.paymentMethod);\n    \n    // Clear loading timeout if set\n    if (loadingTimeout) {\n      clearTimeout(loadingTimeout);\n    }\n    \n    // Hide loading overlay\n    setLoadingState(false);\n    \n    // Track analytics\n    const processingTime = Date.now() - window.paymentStartTime;\n    analytics.track('payment_success_frontend', {\n      systemTransactionId: result.systemTransactionId,\n      merchantTransactionId: result.merchantTransactionId,\n      paymentMethod: result.paymentMethod,\n      processingTime: processingTime\n    });\n    \n    // Show temporary success message\n    showMessage('Payment received! Verifying...', 'success');\n    \n    // CRITICAL: Verify payment on backend before fulfilling order\n    try {\n      const verification = await fetch('/api/verify-payment', {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({\n          systemTransactionId: result.systemTransactionId,\n          merchantTransactionId: result.merchantTransactionId\n        })\n      }).then(response => {\n        if (!response.ok) {\n          throw new Error('Verification request failed');\n        }\n        return response.json();\n      });\n      \n      if (verification.success) {\n        // Payment verified on backend - safe to proceed\n        console.log('Payment verified on backend:', verification.orderId);\n        \n        // Track backend verification success\n        analytics.track('payment_verified', {\n          orderId: verification.orderId,\n          systemTransactionId: result.systemTransactionId\n        });\n        \n        // Clear cart\n        clearShoppingCart();\n        \n        // Redirect to success page\n        window.location.href = `/order-confirmation?orderId=${verification.orderId}`;\n      } else {\n        // Verification failed\n        console.error('Backend verification failed:', verification.error);\n        \n        analytics.track('payment_verification_failed', {\n          systemTransactionId: result.systemTransactionId,\n          error: verification.error\n        });\n        \n        alert(\n          'Payment verification failed. Please contact support with ' +\n          `transaction ID: ${result.merchantTransactionId}`\n        );\n      }\n    } catch (error) {\n      // Network or server error during verification\n      console.error('Failed to verify payment:', error);\n      \n      analytics.track('payment_verification_error', {\n        systemTransactionId: result.systemTransactionId,\n        error: error.message\n      });\n      \n      // Show error but don't clear cart (webhook may still process it)\n      alert(\n        'Unable to verify payment. Your payment may still be processing. ' +\n        'Please check your email for confirmation or contact support with ' +\n        `transaction ID: ${result.merchantTransactionId}`\n      );\n    }\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Backend verification endpoint example:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// Node.js/Express backend\napp.post('/api/verify-payment', async (req, res) => {\n  const { systemTransactionId, merchantTransactionId } = req.body;\n  \n  // Retrieve expected amount/currency from your order database\n  const order = await db.orders.findOne({ merchantTransactionId });\n  if (!order) {\n    return res.json({ success: false, error: 'Order not found' });\n  }\n  \n  const expectedAmount = order.amount;\n  const expectedCurrency = order.currency;\n  \n  try {\n    // Check if webhook already processed this transaction\n    const existingTransaction = await db.transactions.findOne({\n      systemTransactionId: systemTransactionId\n    });\n    \n    if (existingTransaction) {\n      // Webhook already processed - return order details\n      return res.json({\n        success: true,\n        orderId: existingTransaction.orderId,\n        source: 'webhook'\n      });\n    }\n    \n    // Webhook hasn't arrived yet - query PXP API as fallback\n    const requestPath = `api/v1/transactions?systemTransactionId=${systemTransactionId}`;\n    const requestBody = '';\n    const { authHeader, requestId } = createAuthHeader(\n      requestPath, \n      requestBody, \n      process.env.PXP_TOKEN_ID, \n      process.env.PXP_TOKEN_VALUE\n    );\n    \n    const response = await fetch(\n      `https://api-services.pxp.io/${requestPath}`,\n      {\n        headers: {\n          'X-Client-Id': process.env.PXP_CLIENT_ID,\n          'X-Request-Id': requestId,\n          'Authorization': authHeader\n        }\n      }\n    );\n    \n    if (!response.ok) {\n      throw new Error('PXP API request failed');\n    }\n    \n    const transaction = await response.json();\n    \n    // Verify transaction details\n    if (transaction.state !== 'Authorised' && transaction.state !== 'Captured') {\n      return res.json({ success: false, error: 'Transaction not authorised' });\n    }\n    \n    const txnAmount = transaction.amounts?.transactionValue || transaction.amount || 0;\n    if (Math.abs(txnAmount - expectedAmount) > 0.01) {\n      return res.json({ success: false, error: 'Amount mismatch' });\n    }\n    \n    if (transaction.merchantTransactionId !== merchantTransactionId) {\n      return res.json({ success: false, error: 'Transaction ID mismatch' });\n    }\n    \n    // For 3DS card transactions, authenticationId is in the transaction response\n    if (transaction.authenticationId) {\n      const authPath = `api/v1/threedsecure/integrated/authentications/${transaction.authenticationId}`;\n      const { authHeader: auth3dsHeader, requestId: auth3dsRequestId } = createAuthHeader(\n        authPath,\n        '',\n        process.env.PXP_TOKEN_ID,\n        process.env.PXP_TOKEN_VALUE\n      );\n      \n      const authResponse = await fetch(\n        `https://api-services.pxp.io/${authPath}`,\n        {\n          headers: {\n            'X-Client-Id': process.env.PXP_CLIENT_ID,\n            'X-Request-Id': auth3dsRequestId,\n            'Authorization': auth3dsHeader\n          }\n        }\n      );\n      \n      const authResult = await authResponse.json();\n      \n      if (authResult.transactionStatus !== 'Y' && authResult.transactionStatus !== 'A') {\n        return res.json({ success: false, error: '3DS authentication failed' });\n      }\n    }\n    \n    // Find order\n    const order = await db.orders.findOne({\n      transactionId: merchantTransactionId\n    });\n    \n    if (!order) {\n      return res.json({ success: false, error: 'Order not found' });\n    }\n    \n    // Record transaction\n    const recordedAmount = transaction.amounts?.transactionValue || transaction.amount;\n    await db.transactions.create({\n      systemTransactionId,\n      merchantTransactionId,\n      orderId: order.id,\n      amount: recordedAmount,\n      state: transaction.state,\n      processedAt: new Date(),\n      source: 'api_fallback'\n    });\n    \n    // Fulfill order\n    await fulfillOrder(order.id, systemTransactionId);\n    \n    res.json({\n      success: true,\n      orderId: order.id,\n      source: 'api'\n    });\n  } catch (error) {\n    console.error('Payment verification error:', error);\n    res.status(500).json({ success: false, error: 'Verification failed' });\n  }\n});\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"onerror","__idx":17},"children":["onError"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This callback is triggered when an error occurs during the payment process."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can use it to:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Display user-friendly error messages."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Log errors for debugging and monitoring."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track failed payment analytics."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Offer alternative payment methods."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Provide retry options."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Hide loading indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Re-enable form controls."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"event-data-4","__idx":18},"children":["Event data"]},{"$$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.message"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["string"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Human-readable error message."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["string"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["SDK error code in format ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["SDK####"]}," (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["'SDK1114'"]}," for authentication failed, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["'SDK0500'"]}," for network error). Use this for programmatic error handling."]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BaseSdkException"]}," type:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"common-error-scenarios","__idx":19},"children":["Common error scenarios"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following table shows common error scenarios and how to detect and respond to them:"]},{"$$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":"Detection approach"},"children":["Detection approach"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"User action"},"children":["User action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Card declined"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"declined\" or specific provider messages"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Try a different card."]}]},{"$$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.message"]}," contains \"insufficient funds\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Use a different payment method."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Expired card"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"expired\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Use a different card."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Invalid CVV"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"CVV\" or \"security code\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check security code."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3DS authentication failed"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code === 'SDK1114'"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"Authentication failed\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Try again or use different card."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["3DS timeout"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"timeout\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check connection and retry."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["User cancelled 3DS"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"cancel\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Retry payment."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["PayPal error"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code === 'SDK1117'"]}," or payment method is PayPal"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Try again or use different method."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Session expired"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.message"]}," contains \"session\" or \"expired\""]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Refresh page and retry."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Network error"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code === 'SDK0500'"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check connection and retry."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Configuration error"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["error.code"]}," starts with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["'SDK01'"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["'SDK02'"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Contact support."]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-implementation-4","__idx":20},"children":["Example implementation"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\nimport BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';\n\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  onError: (error: BaseSdkException) => {\n    console.error('Payment failed');\n    console.error('Error code:', error.code);\n    console.error('Error message:', error.message);\n    \n    // Clear loading timeout if set\n    if (loadingTimeout) {\n      clearTimeout(loadingTimeout);\n    }\n    \n    // Hide loading overlay\n    setLoadingState(false);\n    \n    // Re-enable submit button\n    const submitBtn = document.querySelector('button[type=\"submit\"]');\n    if (submitBtn) {\n      submitBtn.disabled = false;\n      submitBtn.textContent = 'Pay Now';\n    }\n    \n    // Track error analytics\n    analytics.track('payment_failed', {\n      errorCode: error.code,\n      errorMessage: error.message\n    });\n    \n    // Log error for monitoring\n    logErrorToMonitoring({\n      category: 'payment_error',\n      code: error.code,\n      message: error.message,\n      userAgent: navigator.userAgent\n    });\n    \n    // Show user-friendly error message based on error code and message\n    let userMessage = 'Payment failed. Please try again or contact support.';\n    \n    // Check by SDK error code\n    if (error.code === 'SDK0500') {\n      userMessage = 'Network connection issue. Please check your internet connection and try again.';\n    } else if (error.code === 'SDK1114') {\n      userMessage = '3D Secure authentication failed. Please try again or use a different card.';\n    } else if (error.code === 'SDK1116') {\n      userMessage = 'Card payment failed. Please check your card details and try again.';\n    } else if (error.code === 'SDK1117') {\n      userMessage = 'PayPal payment failed. Please try again or use a different payment method.';\n    } else if (error.code === 'SDK1118') {\n      userMessage = 'Google Pay payment failed. Please try again or use a different payment method.';\n    } else if (error.code === 'SDK1119') {\n      userMessage = 'Apple Pay payment failed. Please try again or use a different payment method.';\n    }\n    // Check by message content for provider-specific errors\n    else if (error.message.toLowerCase().includes('declined')) {\n      userMessage = 'Your card was declined. Please try a different card or contact your bank.';\n    } else if (error.message.toLowerCase().includes('insufficient funds')) {\n      userMessage = 'Insufficient funds. Please use a different payment method.';\n    } else if (error.message.toLowerCase().includes('expired')) {\n      userMessage = 'This card has expired. Please use a different card.';\n    } else if (error.message.toLowerCase().includes('cvv') || error.message.toLowerCase().includes('security code')) {\n      userMessage = 'Invalid security code. Please check your CVV and try again.';\n    } else if (error.message.toLowerCase().includes('timeout')) {\n      userMessage = 'Request timed out. Please check your internet connection and try again.';\n    } else if (error.message.toLowerCase().includes('cancel')) {\n      userMessage = 'Payment was cancelled. Please try again to complete your payment.';\n    } else if (error.message.toLowerCase().includes('session') || error.message.toLowerCase().includes('expired')) {\n      userMessage = 'Your payment session has expired. Please refresh the page and try again.';\n    }\n    \n    showErrorMessage(userMessage);\n    \n    // Offer alternatives for card errors\n    if (error.code === 'SDK1116' || error.message.toLowerCase().includes('declined') || \n        error.message.toLowerCase().includes('insufficient funds')) {\n      showAlternativePaymentOptions();\n    }\n    \n    // Offer retry for network errors\n    if (error.code === 'SDK0500' || error.message.toLowerCase().includes('network') || \n        error.message.toLowerCase().includes('timeout')) {\n      showRetryButton();\n    }\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Error handling with retry logic:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"let retryCount = 0;\nconst MAX_RETRIES = 3;\n\nonError: (error) => {\n  // Check if error is retryable (network issues, timeouts)\n  const isNetworkError = error.code === 'SDK0500';\n  const isTimeout = error.message.toLowerCase().includes('timeout');\n  const isRetryable = isNetworkError || isTimeout;\n  \n  if (isRetryable && retryCount < MAX_RETRIES) {\n    retryCount++;\n    \n    console.log(`Retryable error, attempt ${retryCount}/${MAX_RETRIES}`);\n    \n    showMessage(\n      `Connection issue. Attempt ${retryCount}/${MAX_RETRIES}. ` +\n      'Please try your payment again.',\n      'warning'\n    );\n  } else {\n    retryCount = 0; // Reset retry count\n    \n    if (isRetryable) {\n      showMessage(\n        'Unable to process payment after multiple attempts. ' +\n        'Please check your connection and try again later.',\n        'error'\n      );\n    } else {\n      showMessage(\n        'Payment failed: ' + error.message,\n        'error'\n      );\n    }\n    \n    // Show alternative options for persistent failures\n    showAlternativePaymentMethods();\n  }\n}\n\n### onGetConsent\n\nThis callback controls whether to show a consent checkbox for a specific payment method. This is typically used to get user permission to save payment information for future use (card-on-file).\n\nYou can use it to:\n* Show consent checkbox only for specific payment methods.\n* Comply with regulations requiring explicit consent for storing payment data.\n* Allow users to opt-in to card-on-file functionality.\n* Control consent display based on user type (guest vs registered).\n\n#### Event data\n\n\n#### Return value\n\n* `true`: Show consent checkbox for this payment method.\n* `false`: Hide consent checkbox for this payment method.\n\n#### Example implementation\n```typescript\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  methodConfig: {\n    global: {\n      // Control consent checkbox for card-on-file\n      onGetConsent: (paymentMethod: PaymentMethod) => {\n        // Show consent for cards and PayPal, but not for wallet payments\n        if (paymentMethod === PaymentMethod.Card || paymentMethod === PaymentMethod.Paypal) {\n          return true;\n        }\n        return false;\n      }\n    }\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Dynamic consent based on user type:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"onGetConsent: (paymentMethod: PaymentMethod) => {\n  // Only show consent for logged-in users\n  const isLoggedIn = checkUserLoginStatus();\n  \n  if (!isLoggedIn) {\n    return false; // Guest users cannot save payment methods\n  }\n  \n  // Show consent for cards only\n  return paymentMethod === PaymentMethod.Card;\n}\n\n### onCancel\n\nThis callback is triggered when a payment is cancelled by the user. This allows you to track cancellations, update UI, or perform cleanup operations.\n\nYou can use it to:\n* Track payment abandonment analytics.\n* Show user-friendly cancellation message.\n* Re-enable form fields or buttons.\n* Clear loading indicators.\n* Offer alternative payment methods.\n* Send abandonment emails for cart recovery.\n\n#### Event data\n\n\nThis callback is triggered when:\n\n* User closes PayPal popup without completing payment.\n* User cancels Apple Pay payment sheet.\n* User cancels Google Pay payment sheet.\n* User closes 3D Secure authentication window.\n* User explicitly cancels the payment flow.\n\n#### Example implementation\n```typescript\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  methodConfig: {\n    global: {\n      onCancel: (paymentMethod: PaymentMethod, data: any) => {\n        console.log('Payment cancelled:', paymentMethod);\n        \n        // Track analytics\n        analytics.track('payment_cancelled', {\n          method: paymentMethod,\n          timestamp: Date.now()\n        });\n        \n        // Hide loading spinner\n        setIsProcessing(false);\n        \n        // Re-enable checkout button\n        setCheckoutButtonDisabled(false);\n        \n        // Show cancellation message\n        showNotification({\n          type: 'info',\n          message: `${paymentMethod} payment was cancelled. Please try again or choose a different payment method.`\n        });\n        \n        // Reset payment form\n        resetPaymentForm();\n      }\n    }\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"event-data-structures","__idx":21},"children":["Event data structures"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"paymentmethod-enum","__idx":22},"children":["PaymentMethod enum"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PaymentMethod"]}," enum identifies which payment method is being used:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"enum PaymentMethod {\n  Card = 'Card',\n  Paypal = 'Paypal',\n  ApplePay = 'ApplePay',\n  GooglePay = 'GooglePay'\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Import from:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import PaymentMethod from '@pxpio/web-components-sdk/src/components/checkoutDropInComponents/types/PaymentMethod';\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"basesubmitresult-interface","__idx":23},"children":["BaseSubmitResult interface"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The success callback receives a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BaseSubmitResult"]}," object:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"interface BaseSubmitResult {\n  systemTransactionId: string;      // Unity's transaction ID\n  merchantTransactionId?: string;   // Your transaction ID (optional)\n  paymentMethod: PaymentMethod;     // Payment method used\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Import from:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import { BaseSubmitResult } from '@pxpio/web-components-sdk/src/checkoutDropIn/types/BaseSubmitResult';\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"basesdkexception-interface","__idx":24},"children":["BaseSdkException interface"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The error callback receives a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BaseSdkException"]}," object:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"interface BaseSdkException {\n  message: string;      // Human-readable error message\n  ErrorCode: string;    // SDK error code (e.g., 'SDK1114')\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Import from:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"shopper-interface","__idx":25},"children":["Shopper interface"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," callback must return a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Shopper"]}," object:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"interface Shopper {\n  id: string;  // Unique shopper identifier\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"error-handling-in-events","__idx":26},"children":["Error handling in events"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Event callbacks should handle errors gracefully and provide appropriate feedback to customers. Here's a comprehensive error handling example:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"const checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  \n  onError: (error: BaseSdkException) => {\n    // Log error for debugging\n    console.error('Payment error:', error.code, error.message);\n    \n    // Clear any loading states\n    hideLoadingIndicator();\n    \n    // Track error for analytics\n    analytics.track('payment_error', {\n      code: error.code,\n      message: error.message,\n      timestamp: Date.now()\n    });\n    \n    // Categorize error type\n    let errorCategory = 'unknown';\n    let userMessage = 'Payment failed. Please try again.';\n    let showAlternatives = false;\n    \n    // Network and timeout errors\n    if (error.code === 'SDK0500' || error.message.toLowerCase().includes('network')) {\n      errorCategory = 'network';\n      userMessage = 'Network connection issue. Please check your internet and try again.';\n    }\n    // Card-specific errors\n    else if (error.code === 'SDK1116' || error.message.toLowerCase().includes('card')) {\n      errorCategory = 'card';\n      if (error.message.toLowerCase().includes('declined')) {\n        userMessage = 'Card declined. Please try a different card.';\n        showAlternatives = true;\n      } else if (error.message.toLowerCase().includes('insufficient funds')) {\n        userMessage = 'Insufficient funds. Please use a different payment method.';\n        showAlternatives = true;\n      } else if (error.message.toLowerCase().includes('expired')) {\n        userMessage = 'This card has expired. Please use a different card.';\n      } else if (error.message.toLowerCase().includes('cvv')) {\n        userMessage = 'Invalid security code. Please check your CVV.';\n      }\n    }\n    // 3DS authentication errors\n    else if (error.code === 'SDK1114' || error.message.toLowerCase().includes('authentication')) {\n      errorCategory = '3ds';\n      userMessage = '3D Secure authentication failed. Please try again.';\n    }\n    // Wallet payment errors\n    else if (error.code === 'SDK1117') {\n      errorCategory = 'paypal';\n      userMessage = 'PayPal payment failed. Please try again or use a different method.';\n    } else if (error.code === 'SDK1118') {\n      errorCategory = 'googlepay';\n      userMessage = 'Google Pay payment failed. Please try again or use a different method.';\n    } else if (error.code === 'SDK1119') {\n      errorCategory = 'applepay';\n      userMessage = 'Apple Pay payment failed. Please try again or use a different method.';\n    }\n    // Session errors\n    else if (error.message.toLowerCase().includes('session') || error.message.toLowerCase().includes('expired')) {\n      errorCategory = 'session';\n      userMessage = 'Your session has expired. Please refresh the page.';\n    }\n    \n    // Display error message to user\n    showErrorMessage(userMessage);\n    \n    // Show alternative payment methods if appropriate\n    if (showAlternatives) {\n      showAlternativePaymentMethodsPrompt();\n    }\n    \n    // Log to monitoring service\n    logToMonitoring({\n      level: 'error',\n      category: errorCategory,\n      code: error.code,\n      message: error.message,\n      context: {\n        userAgent: navigator.userAgent,\n        timestamp: new Date().toISOString()\n      }\n    });\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"advanced-event-usage","__idx":27},"children":["Advanced event usage"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"payment-method-specific-callbacks","__idx":28},"children":["Payment method-specific callbacks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Checkout Drop-in supports advanced callbacks for dynamic pricing, shipping updates, and payment customisation. These callbacks are configured within ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig"]}," for each payment method."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["PayPal callbacks"]}," (in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.paypal"]},"):"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onShippingAddressChange"]}," - Triggered when shipping address changes in the PayPal popup."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onShippingOptionsChange"]}," - Triggered when shipping option changes in the PayPal popup."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Apple Pay callbacks"]}," (in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.applePay"]},"):"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onShippingContactSelected"]}," - Triggered when shipping contact is selected in the Apple Pay sheet."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onShippingMethodSelected"]}," - Triggered when shipping method is selected in the Apple Pay sheet."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPaymentMethodSelected"]}," - Triggered when payment method (card type) is selected in the Apple Pay sheet."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onCouponCodeChanged"]}," - Triggered when coupon code is entered in the Apple Pay sheet (iOS 15.0+)."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Google Pay callbacks"]}," (in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.googlePay"]},"):"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPaymentDataChanged"]}," - Triggered when payment data changes in the Google Pay sheet."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For detailed documentation on these advanced callbacks, see:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/drop-in/web/configuration"},"children":["Configuration guide"]}," - Payment method-specific configuration."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/drop-in/web/paypal"},"children":["PayPal documentation"]}," - PayPal callbacks and settings."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/drop-in/web/apple-pay"},"children":["Apple Pay documentation"]}," - Apple Pay callbacks and settings."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/drop-in/web/google-pay"},"children":["Google Pay documentation"]}," - Google Pay callbacks and settings."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"callback-execution-order","__idx":29},"children":["Callback execution order"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Understanding the callback flow helps you implement proper payment handling:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["onGetShopper"]}," - Initial setup"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Called during Drop-in initialisation."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Must return shopper ID for card-on-file functionality."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["onBeforeSubmit"]}," - Validation phase"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["User selects payment method and clicks submit."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Receives payment selection details as parameter."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Return ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["true"]}," to proceed, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]}," to cancel."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Perform business validation and fraud checks."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["onSubmit"]}," - Processing starts (if onBeforeSubmit returns true or undefined)"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Receives payment submission details as parameter."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Show loading indicators."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Disable form fields."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Track analytics."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["onSuccess"]}," OR ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["onError"]}," - Payment completes"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["onSuccess"]}," - Payment succeeded (verify on backend before fulfilling)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["onError"]}," - Payment failed (show error message and offer alternatives)."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["onCancel"]}," - User cancels (optional)"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Triggered if user closes payment window/sheet."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Update UI and track analytics."]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"execution-flow-diagram","__idx":30},"children":["Execution flow diagram"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"Initialisation\n    ↓\nonGetShopper() → Returns shopper ID\n    ↓\nUser selects payment method and clicks submit\n    ↓\nonBeforeSubmit(before) → Returns true/false\n    ↓\n    ├─ false → Payment cancelled, flow stops\n    └─ true  → Continue\n           ↓\n       onSubmit(submit) → Show loading state\n           ↓\n       Payment processing\n           ↓\n           ├─ Success → onSuccess(result) → Verify on backend → Redirect\n           ├─ Error   → onError(error) → Show error message\n           └─ Cancel  → onCancel(paymentMethod, data) → Reset UI\n"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"complete-integration-example","__idx":31},"children":["Complete integration example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's a complete example showing all callbacks working together:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import CheckoutDropIn from '@pxpio/web-components-sdk/src/checkoutDropIn/CheckoutDropIn';\nimport IntentType from '@pxpio/web-components-sdk/src/basePxpCheckout/types/IntentType';\nimport { BaseSubmitResult } from '@pxpio/web-components-sdk/src/checkoutDropIn/types/BaseSubmitResult';\nimport BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';\nimport PaymentMethod from '@pxpio/web-components-sdk/src/components/checkoutDropInComponents/types/PaymentMethod';\n\nlet loadingTimeout;\nlet retryCount = 0;\nconst MAX_RETRIES = 3;\n\nasync function initializeCheckout() {\n  // Get session from backend\n  const sessionData = await fetch('/api/create-session', {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/json' },\n    body: JSON.stringify({ amount: 25.00, currency: 'USD' })\n  }).then(r => r.json());\n  \n  // Initialise Drop-in with all callbacks\n  const checkoutDropIn = CheckoutDropIn.initialize({\n    environment: 'production',\n    session: sessionData,\n    ownerId: 'YourMerchantId',\n    ownerType: 'MerchantGroup',\n    transactionData: {\n      currency: 'USD',\n      amount: 25.00,\n      entryType: 'Ecom',\n      intent: {\n        card: IntentType.Authorisation,\n        paypal: IntentType.Authorisation\n      },\n      merchantTransactionId: crypto.randomUUID(),\n      merchantTransactionDate: () => new Date().toISOString()\n    },\n    \n    // Required: Get shopper information\n    onGetShopper: () => {\n      const customerId = getCurrentCustomerId();\n      return Promise.resolve({\n        id: customerId || 'guest-' + crypto.randomUUID()\n      });\n    },\n    \n    // Before payment submission\n    onBeforeSubmit: async (before) => {\n      console.log('Payment method selected:', before);\n      \n      // Track analytics\n      analytics.track('payment_initiated', {\n        paymentMethod: before,\n        amount: 25.00\n      });\n      \n      // Show confirmation for large amounts\n      if (25.00 > 100) {\n        const confirmed = await showConfirmation(\n          `Confirm payment of 25.00 USD?`\n        );\n        if (!confirmed) return false;\n      }\n      \n      // Validate inventory\n      const hasStock = await checkInventory();\n      if (!hasStock) {\n        alert('Some items are no longer available');\n        return false;\n      }\n      \n      return true; // Proceed with payment\n    },\n    \n    // Payment processing started\n    onSubmit: (submit) => {\n      console.log('Processing payment...');\n      \n      // Show loading state\n      document.getElementById('loading-overlay').style.display = 'flex';\n      document.getElementById('submit-btn').disabled = true;\n      \n      // Set timeout warning\n      loadingTimeout = setTimeout(() => {\n        showMessage('Payment is taking longer than expected...', 'warning');\n      }, 10000);\n      \n      // Track processing start\n      window.paymentStartTime = Date.now();\n      \n      analytics.track('payment_processing', {\n        paymentMethod: submit\n      });\n    },\n    \n    // Payment succeeded (frontend notification)\n    onSuccess: async (result: BaseSubmitResult) => {\n      console.log('Payment successful (verifying on backend...)');\n      \n      // Clear timeout\n      if (loadingTimeout) clearTimeout(loadingTimeout);\n      \n      // Calculate processing time\n      const processingTime = Date.now() - window.paymentStartTime;\n      console.log(`Payment processed in ${processingTime}ms`);\n      \n      // Track frontend success\n      analytics.track('payment_success_frontend', {\n        systemTransactionId: result.systemTransactionId,\n        paymentMethod: result.paymentMethod,\n        processingTime\n      });\n      \n      // Show verifying message\n      showMessage('Payment received! Verifying...', 'success');\n      \n      // CRITICAL: Verify on backend\n      try {\n        const verified = await fetch('/api/verify-payment', {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json' },\n          body: JSON.stringify({\n            systemTransactionId: result.systemTransactionId,\n            merchantTransactionId: result.merchantTransactionId\n          })\n        }).then(r => r.json());\n        \n        if (verified.success) {\n          // Backend verification passed\n          analytics.track('payment_verified', {\n            orderId: verified.orderId\n          });\n          \n          // Clear cart and redirect\n          clearCart();\n          window.location.href = `/success?orderId=${verified.orderId}`;\n        } else {\n          throw new Error(verified.error || 'Verification failed');\n        }\n      } catch (error) {\n        console.error('Verification error:', error);\n        document.getElementById('loading-overlay').style.display = 'none';\n        alert(\n          'Payment verification failed. Please contact support with ' +\n          `transaction ID: ${result.merchantTransactionId}`\n        );\n      }\n    },\n    \n    // Payment failed\n    onError: (error: BaseSdkException) => {\n      console.error('Payment failed:', error.code);\n      console.error('Error message:', error.message);\n      \n      // Clear timeout\n      if (loadingTimeout) clearTimeout(loadingTimeout);\n      \n      // Hide loading state\n      document.getElementById('loading-overlay').style.display = 'none';\n      document.getElementById('submit-btn').disabled = false;\n      \n      // Track error\n      analytics.track('payment_failed', {\n        errorCode: error.code,\n        errorMessage: error.message\n      });\n      \n      // Log for monitoring\n      logError(error);\n      \n      // Handle retryable errors\n      const isNetworkError = error.code === 'SDK0500';\n      const isTimeout = error.message.toLowerCase().includes('timeout');\n      if ((isNetworkError || isTimeout) && retryCount < MAX_RETRIES) {\n        retryCount++;\n        showMessage(\n          `Connection issue (attempt ${retryCount}/${MAX_RETRIES}). Please try again.`,\n          'warning'\n        );\n        return;\n      }\n      \n      retryCount = 0; // Reset\n      \n      // Show user-friendly error\n      let userMessage = 'Payment failed. Please try again.';\n      \n      if (error.code === 'SDK1114') {\n        userMessage = '3D Secure authentication failed.';\n      } else if (error.code === 'SDK1116') {\n        userMessage = 'Card payment failed.';\n      } else if (error.code === 'SDK1117') {\n        userMessage = 'PayPal payment failed.';\n      } else if (error.message.toLowerCase().includes('declined')) {\n        userMessage = 'Card declined. Please try a different card.';\n      } else if (error.message.toLowerCase().includes('insufficient funds')) {\n        userMessage = 'Insufficient funds. Please use a different payment method.';\n      } else if (error.message.toLowerCase().includes('expired')) {\n        userMessage = 'This card has expired.';\n      } else if (error.message.toLowerCase().includes('cvv')) {\n        userMessage = 'Invalid security code.';\n      }\n      \n      showErrorMessage(userMessage);\n      \n      // Offer alternatives for card issues\n      if (error.code === 'SDK1116' || error.message.toLowerCase().includes('card')) {\n        showAlternativePaymentMethods();\n      }\n    },\n    \n    // Method-specific configuration\n    methodConfig: {\n      global: {\n        // Control consent checkbox\n        onGetConsent: (paymentMethod: PaymentMethod) => {\n          // Show consent for cards and PayPal\n          return paymentMethod === PaymentMethod.Card || \n                 paymentMethod === PaymentMethod.Paypal;\n        },\n        \n        // Handle cancellation\n        onCancel: (paymentMethod: PaymentMethod, data: any) => {\n          console.log('Payment cancelled:', paymentMethod);\n          \n          // Clear timeout\n          if (loadingTimeout) clearTimeout(loadingTimeout);\n          \n          // Hide loading\n          document.getElementById('loading-overlay').style.display = 'none';\n          document.getElementById('submit-btn').disabled = false;\n          \n          // Track cancellation\n          analytics.track('payment_cancelled', {\n            paymentMethod: paymentMethod\n          });\n          \n          showMessage('Payment was cancelled. Please try again.', 'info');\n        }\n      }\n    }\n  });\n  \n  // Mount Drop-in\n  checkoutDropIn.create('checkout-drop-in-container');\n}\n\n// Initialise on page load\ninitializeCheckout();\n","lang":"typescript"},"children":[]}]},"headings":[{"value":"Events","id":"events","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Supported events","id":"supported-events","depth":2},{"value":"onGetShopper","id":"ongetshopper","depth":3},{"value":"Event data","id":"event-data","depth":4},{"value":"Return value","id":"return-value","depth":4},{"value":"Example implementation","id":"example-implementation","depth":4},{"value":"onBeforeSubmit","id":"onbeforesubmit","depth":3},{"value":"Event data","id":"event-data-1","depth":4},{"value":"Return value","id":"return-value-1","depth":4},{"value":"Example implementation","id":"example-implementation-1","depth":4},{"value":"onSubmit","id":"onsubmit","depth":3},{"value":"Event data","id":"event-data-2","depth":4},{"value":"Example implementation","id":"example-implementation-2","depth":4},{"value":"onSuccess","id":"onsuccess","depth":3},{"value":"Event data","id":"event-data-3","depth":4},{"value":"Example implementation","id":"example-implementation-3","depth":4},{"value":"onError","id":"onerror","depth":3},{"value":"Event data","id":"event-data-4","depth":4},{"value":"Common error scenarios","id":"common-error-scenarios","depth":4},{"value":"Example implementation","id":"example-implementation-4","depth":4},{"value":"Event data structures","id":"event-data-structures","depth":2},{"value":"PaymentMethod enum","id":"paymentmethod-enum","depth":3},{"value":"BaseSubmitResult interface","id":"basesubmitresult-interface","depth":3},{"value":"BaseSdkException interface","id":"basesdkexception-interface","depth":3},{"value":"Shopper interface","id":"shopper-interface","depth":3},{"value":"Error handling in events","id":"error-handling-in-events","depth":2},{"value":"Advanced event usage","id":"advanced-event-usage","depth":2},{"value":"Payment method-specific callbacks","id":"payment-method-specific-callbacks","depth":3},{"value":"Callback execution order","id":"callback-execution-order","depth":2},{"value":"Execution flow diagram","id":"execution-flow-diagram","depth":3},{"value":"Complete integration example","id":"complete-integration-example","depth":2}],"frontmatter":{"seo":{"title":"Events"}},"lastModified":"2026-05-06T10:44:47.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/drop-in/web/events","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}