{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["sub-heading","br","details","admonition","endpoint"]},"type":"markdown"},"seo":{"title":"Card","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":"card","__idx":0},"children":["Card"]},{"$$mdtype":"Tag","name":"SubHeading","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Accept credit and debit cards with automatic 3DS authentication, PCI-compliant tokenisation, and built-in fraud prevention."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"overview","__idx":1},"children":["Overview"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Card payments are automatically included in the drop-in and appear as the default expanded payment method. The drop-in handles all card input fields, validation, tokenisation, and 3D Secure authentication automatically."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"key-benefits","__idx":2},"children":["Key benefits"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["New card entry"]},": Secure card number, expiry, and CVV input"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Card-on-file"]},": Stored cards for returning customers (requires ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]},")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["3D Secure"]},": Automatic 3DS authentication when required"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Address verification"]},": Optional AVS for fraud prevention"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Validation"]},": Automatic validation of card number (Luhn), expiry date, and CVV"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"how-it-works","__idx":3},"children":["How it works"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a customer pays with a card:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer enters their card details (number, expiry, CVV, name). Real-time validation provides instant feedback."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer clicks submit."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The card is securely tokenised (never touches your server)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The system evaluates whether 3DS is required."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If needed, 3DS authentication occurs."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The transaction is processed."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback fires."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Drop-in handles tokenisation, 3DS, and all card field configuration automatically."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"configuration","__idx":4},"children":["Configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Card payments inherit all settings from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global"]},". There are no card-specific configuration options - the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["card"]}," object remains empty."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"global-settings-that-affect-card","__idx":5},"children":["Global settings that affect card"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following properties are available in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig.global"]}," and apply to card payments:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"width":"40%","data-label":"Property"},"children":["Property "]},{"$$mdtype":"Tag","name":"th","attributes":{"width":"60%","data-label":"Description"},"children":["Description "]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["acceptedCardNetworks"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["string[]"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Which card brands to accept (Visa, Mastercard, etc.). Falls back to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["session.allowedFundingTypes.cardSchemes"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedCardFundingSource"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["string[]"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Which funding types to accept (Credit, Debit, Prepaid)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedIssuerCountryCodes"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["string[]"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Restrict cards to specific issuer countries (ISO country codes)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetConsent"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["(paymentMethod) => boolean"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Controls whether to show consent checkbox for saving cards"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onCancel"]},{"$$mdtype":"Tag","name":"Break","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Details","attributes":{},"children":["(paymentMethod, data) => void"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Called when user cancels card payment (e.g., closes 3DS window)"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"card-specific-configuration","__idx":6},"children":["Card-specific configuration"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Card payments use an empty ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["card"]}," object in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["methodConfig"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"methodConfig: {\n  global: {\n    // Card settings go here\n  },\n  card: {\n    // Empty - all configuration is in global\n  }\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"complete-example","__idx":7},"children":["Complete example"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This example shows a full card configuration using global settings:"]},{"$$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\nmethodConfig: {\n  global: {\n    // Card settings\n    acceptedCardNetworks: ['Visa', 'Mastercard', 'American Express'],\n    allowedCardFundingSource: ['CREDIT', 'DEBIT'],\n    allowedIssuerCountryCodes: ['US', 'GB', 'CA'],\n    \n    // Show consent checkbox for card to enable card-on-file\n    onGetConsent: (paymentMethod: PaymentMethod) => {\n      return paymentMethod === PaymentMethod.Card || paymentMethod === PaymentMethod.Paypal;\n    },\n    \n    // Handle 3DS window cancellation\n    onCancel: (paymentMethod: PaymentMethod, data: any) => {\n      if (paymentMethod === PaymentMethod.Card) {\n        console.log('Card payment cancelled', data);\n        // Track analytics\n        trackEvent('card_cancelled', {\n          timestamp: Date.now()\n        });\n      }\n    }\n  },\n  card: {\n    // Empty - inherits from global\n  }\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"common-scenarios","__idx":8},"children":["Common scenarios"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"payment-intents","__idx":9},"children":["Payment intents"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Choose the appropriate intent for your use case:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import IntentType from '@pxpio/web-components-sdk/src/basePxpCheckout/types/IntentType';\n\n// Physical goods (authorise now, capture later)\ntransactionData: {\n  intent: { card: IntentType.Authorisation }  // Capture when shipped\n}\n\n// Digital goods (immediate capture)\ntransactionData: {\n  intent: { card: IntentType.Purchase }\n}\n\n// Card verification (no charge)\ntransactionData: {\n  amount: 0.00,\n  intent: { card: IntentType.Verification }\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"implementation","__idx":10},"children":["Implementation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Card payments work through the standard Drop-in implementation:"]},{"$$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';\n\n// Get session from backend\nconst response = await fetch('/api/create-session', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' }\n});\n\nconst result = await response.json();\n\nif (!result.success || !result.data) {\n  console.error('Failed to create session:', result.error);\n  throw new Error('Session creation failed');\n}\n\nconst sessionData = result.data;\n\n// Initialise Drop-in\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  environment: 'test',\n  session: sessionData,\n  ownerId: 'MERCHANT-1',\n  ownerType: 'MerchantGroup',\n  transactionData: {\n    currency: 'USD',\n    amount: 99.99,\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  onGetShopper: () => Promise.resolve({ id: 'shopper-123' }),\n  onSuccess: async (result: BaseSubmitResult) => {\n    // CRITICAL: Verify on backend\n    await verifyPaymentOnBackend(result);\n  },\n  onError: (error: BaseSdkException) => {\n    console.error('Card payment failed:', error);\n    alert(`Payment failed: ${error.message}`);\n  }\n});\n\n// Mount the drop-in\ncheckoutDropIn.create('checkout-drop-in-container');\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"session-configuration-backend","__idx":11},"children":["Session configuration (backend)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a session with card payments enabled:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// BACKEND: Create session with card enabled\nconst sessionRequest = {\n  merchant: \"MERCHANT-1\",\n  site: \"SITE-1\",\n  sessionTimeout: 120,\n  merchantTransactionId: crypto.randomUUID(),\n  transactionMethod: {\n    intent: {\n      card: \"Authorisation\"\n    }\n  },\n  amounts: {\n    currencyCode: \"USD\",\n    transactionValue: 99.99\n  },\n  allowedFundingTypes: {\n    card: true  // Enable card payments\n  },\n  allowTransaction: true,\n  serviceType: \"CheckoutDropIn\"\n};\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"handling-responses","__idx":12},"children":["Handling responses"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"card-callback-data","__idx":13},"children":["Card callback data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a card payment succeeds, your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback receives the standard result:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"onSuccess: (result: BaseSubmitResult) => {\n  console.log('Payment Details:');\n  console.log('- System Transaction ID:', result.systemTransactionId);\n  console.log('- Merchant Transaction ID:', result.merchantTransactionId);\n  console.log('- Payment Method:', result.paymentMethod); // \"Card\"\n  \n  // Note: authenticationId is NOT included in the callback for card payments\n  // Amount, currency, and other transaction details must be retrieved from backend\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Unlike Google Pay and Apple Pay, card payments don't include ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authenticationId"]}," in the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback, even when 3DS authentication was used. You must retrieve all transaction details (including authentication data, amount, currency, etc.) from your backend by querying the PXP API with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["systemTransactionId"]},"."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"error-handling","__idx":14},"children":["Error handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Handle card-specific errors:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import BaseSdkException from '@pxpio/web-components-sdk/src/types/sdkExceptions/BaseSdkException';\n\nonError: (error: BaseSdkException) => {\n  // Check SDK error codes\n  if (error.code === 'SDK1114') {\n    alert('Card verification failed.');\n  } else if (error.code === 'SDK1116') {\n    // Card payment failed - check message for specifics\n    if (error.message.toLowerCase().includes('declined')) {\n      alert('Card declined. Try a different card.');\n    } else if (error.message.toLowerCase().includes('insufficient funds')) {\n      alert('Insufficient funds.');\n    } else if (error.message.toLowerCase().includes('expired')) {\n      alert('Card expired.');\n    } else if (error.message.toLowerCase().includes('cvv') || \n               error.message.toLowerCase().includes('cvc') ||\n               error.message.toLowerCase().includes('security code')) {\n      alert('Invalid security code.');\n    } else if (error.message.toLowerCase().includes('card number')) {\n      alert('Invalid card number.');\n    } else if (error.message.toLowerCase().includes('expiry') ||\n               error.message.toLowerCase().includes('expiration')) {\n      alert('Invalid expiry date.');\n    } else {\n      alert('Card payment failed. Please check your details.');\n    }\n  } else if (error.code === 'SDK0500') {\n    alert('Connection error. Check your internet.');\n  } else if (error.message.toLowerCase().includes('session') || \n             error.message.toLowerCase().includes('expired')) {\n    alert('Session expired. Refresh the page.');\n  } else if (error.message.toLowerCase().includes('timeout')) {\n    alert('Verification timed out.');\n  } else {\n    alert(`Payment failed: ${error.message}`);\n  }\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"backend-verification","__idx":15},"children":["Backend verification"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Always verify card payments on your backend to ensure payment success before fulfilling orders:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"typescript","header":{"controls":{"copy":{}}},"source":"import { BaseSubmitResult } from '@pxpio/web-components-sdk/src/checkoutDropIn/types/BaseSubmitResult';\n\n// FRONTEND: Send to backend\nonSuccess: async (result: BaseSubmitResult) => {\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    window.location.href = `/success?orderId=${verified.orderId}`;\n  } else {\n    alert('Payment verification failed');\n  }\n}\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"backend-verification-code","__idx":16},"children":["Backend verification code"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the following backend code to verify card transactions via the PXP API:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// BACKEND: Complete verification\napp.post('/api/verify-payment', async (req, res) => {\n  const { systemTransactionId, merchantTransactionId } = req.body;\n  \n  // 1. Verify transaction\n  const txnPath = `api/v1/transactions/${systemTransactionId}`;\n  const { authHeader: txnAuthHeader, requestId: txnRequestId } = createAuthHeader(\n    txnPath,\n    '',\n    process.env.PXP_TOKEN_ID,\n    process.env.PXP_TOKEN_VALUE\n  );\n  \n  const transaction = await fetch(\n    `https://api-services.pxp.io/${txnPath}`,\n    {\n      headers: {\n        'X-Client-Id': process.env.PXP_CLIENT_ID,\n        'X-Request-Id': txnRequestId,\n        'Authorization': txnAuthHeader\n      }\n    }\n  ).then(r => r.json());\n  \n  if (transaction.state !== 'Authorised' && transaction.state !== 'Captured') {\n    return res.json({ success: false, error: 'Transaction not authorised' });\n  }\n  \n  // Verify amount matches expected amount from your order records\n  const order = await getOrderByMerchantTransactionId(merchantTransactionId);\n  const txnAmount = transaction.amounts?.transactionValue || transaction.amount || 0;\n  if (Math.abs(txnAmount - order.amount) > 0.01) {\n    return res.json({ success: false, error: 'Amount mismatch' });\n  }\n  \n  // 2. Verify 3DS if used\n  if (transaction.authentication?.authenticationId) {\n    const authPath = `api/v1/threedsecure/integrated/authentications/${transaction.authentication.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 auth = 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    ).then(r => r.json());\n    \n    if (auth.transactionStatus !== 'Y' && auth.transactionStatus !== 'A') {\n      return res.json({ success: false, error: '3DS verification failed' });\n    }\n  }\n  \n  // 3. Check idempotency\n  if (await checkOrderFulfilled(merchantTransactionId)) {\n    return res.json({ success: false, error: 'Already processed' });\n  }\n  \n  // 4. Fulfill order\n  const orderId = await fulfillOrder(merchantTransactionId, transaction);\n  return res.json({ success: true, orderId });\n});\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"verification-checklist","__idx":17},"children":["Verification checklist"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your backend should verify that:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The transaction exists and its state is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Authorised"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Captured"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The amount and currency match the expected values  ."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The transaction is 3DS authenticated (if ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authenticationId"]}," present in transaction response)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["CVV/AVS were checked (for non-3DS)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The transaction wasn't previously processed ."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["There are no replay attacks (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authenticationId"]}," not reused)."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"advanced-card-flows","__idx":18},"children":["Advanced card flows"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3d-secure-authentication","__idx":19},"children":["3D Secure authentication"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Drop-in automatically handles 3DS authentication when required. The payment flow works as follows:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer enters their card details and clicks submit."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The card is tokenised securely."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The system evaluates whether 3DS is required:",{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If 3DS is needed: Device fingerprinting → Authentication (frictionless or challenge)."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If 3DS isn't needed: Direct authorisation with CVV/AVS checks."]}]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The transaction is processed"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSuccess"]}," callback fires."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Drop-in automatically uses 3DS authentication when:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The amount exceeds the risk thresholds configured in the Unity Portal."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Strong Customer Authentication (SCA) is required."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["High-risk indicators are present."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The card issuer requires it."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To check if 3DS was used, query the transaction from your backend using the PXP API. The response includes 3DS authentication data when used."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"controlling-3ds-behaviour","__idx":20},"children":["Controlling 3DS behaviour"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can't directly control whether Drop-in uses 3DS in your code. Configure rules in the Unity Portal under ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Merchant setup > Merchant groups > Services > Card service"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"recurring-payments","__idx":21},"children":["Recurring payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Drop-in supports recurring payments for subscription-based services and merchant-initiated transactions (MITs). Configure the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["recurring"]}," object in your transaction data to set up the initial payment, then use the stored ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gatewayTokenId"]}," for subsequent charges."]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["PXP doesn't provide an automatic payment scheduler. You must implement your own scheduling system to initiate subsequent recurring charges via the Transactions API."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"how-recurring-payments-work","__idx":22},"children":["How recurring payments work"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The recurring payment flow involves two phases:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 1: Initial setup (via Drop-in)"]}]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Configure the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["recurring"]}," object in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["transactionData"]}," with frequency and expiration."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer enters their card details and completes payment."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Drop-in automatically sets ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["processingModel"]}," to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MerchantInitiatedInitialRecurring"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The backend stores the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gatewayTokenId"]}," from the transaction response."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When you include the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["recurring"]}," object in your transaction data, Drop-in automatically sets the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["processingModel"]}," to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MerchantInitiatedInitialRecurring"]}," for the initial transaction."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Phase 2: Subsequent charges (via backend API)"]}]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your scheduling system triggers a charge based on the frequency."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your backend calls the Transactions API using the stored ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gatewayTokenId"]},"."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["processingModel"]}," to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MerchantInitiatedSubsequentRecurring"]}," for subsequent charges."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The payment processes without customer interaction."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"initial-recurring-payment-setup","__idx":23},"children":["Initial recurring payment setup"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure recurring payment frequency in your Drop-in initialisation:"]},{"$$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';\n\n// Get session from backend\nconst response = await fetch('/api/create-session', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' }\n});\n\nconst result = await response.json();\n\nif (!result.success || !result.data) {\n  console.error('Failed to create session:', result.error);\n  throw new Error('Session creation failed');\n}\n\nconst sessionData = result.data;\n\n// Initialize Drop-in with recurring configuration\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  environment: 'test',\n  session: sessionData,\n  ownerId: 'MERCHANT-1',\n  ownerType: 'MerchantGroup',\n  transactionData: {\n    currency: 'USD',\n    amount: 9.99,\n    entryType: 'Ecom',\n    intent: { card: IntentType.Authorisation },\n    merchantTransactionId: crypto.randomUUID(),\n    merchantTransactionDate: () => new Date().toISOString(),\n    // Recurring payment configuration\n    recurring: {\n      frequencyInDays: 30,           // Bill every 30 days\n      frequencyExpiration: '2025-12-31' // Token expires on this date\n    }\n  },\n  onGetShopper: () => Promise.resolve({ id: 'customer-123' }),\n  onSuccess: async (result: BaseSubmitResult) => {\n    console.log('Initial recurring payment setup completed');\n    \n    // Verify payment and store gatewayTokenId on backend\n    const response = await fetch('/api/verify-and-setup-recurring', {\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 (response.success) {\n      window.location.href = `/subscription-success?subscriptionId=${response.subscriptionId}`;\n    }\n  },\n  onError: (error: BaseSdkException) => {\n    console.error('Recurring payment setup failed:', error);\n    alert(`Subscription setup failed: ${error.message}`);\n  }\n});\n\ncheckoutDropIn.create('checkout-drop-in-container');\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"backend-store-recurring-payment-token","__idx":24},"children":["Backend: Store recurring payment token"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After the initial payment, extract and store the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gatewayTokenId"]}," for future charges:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// BACKEND: Verify initial payment and set up recurring subscription\napp.post('/api/verify-and-setup-recurring', async (req, res) => {\n  const { systemTransactionId, merchantTransactionId } = req.body;\n  \n  try {\n    // 1. Query PXP API to get transaction details\n    const txnPath = `api/v1/transactions/${systemTransactionId}`;\n    const { authHeader, requestId } = createAuthHeader(\n      txnPath,\n      '',\n      process.env.PXP_TOKEN_ID,\n      process.env.PXP_TOKEN_VALUE\n    );\n    \n    const transaction = await fetch(\n      `https://api-services.pxp.io/${txnPath}`,\n      {\n        headers: {\n          'X-Client-Id': process.env.PXP_CLIENT_ID,\n          'X-Request-Id': requestId,\n          'Authorization': authHeader\n        }\n      }\n    ).then(r => r.json());\n    \n    // 2. Verify transaction is successful\n    if (transaction.state !== 'Authorised' && transaction.state !== 'Captured') {\n      return res.json({ success: false, error: 'Transaction not successful' });\n    }\n    \n    // 3. Store gatewayTokenId for recurring charges\n    if (transaction.fundingData?.gatewayTokenId) {\n      const subscription = await database.subscriptions.insert({\n        shopperId: req.user.shopperId,\n        gatewayTokenId: transaction.fundingData.gatewayTokenId,\n        amount: transaction.amounts?.transactionValue || 0,\n        currency: transaction.amounts?.currencyCode || 'USD',\n        frequencyInDays: 30,\n        nextChargeDate: calculateNextChargeDate(30),\n        status: 'active',\n        createdAt: new Date()\n      });\n      \n      return res.json({ success: true, subscriptionId: subscription.id });\n    }\n    \n    return res.json({ success: false, error: 'No gateway token found' });\n    \n  } catch (error) {\n    console.error('Setup error:', error);\n    return res.json({ success: false, error: 'Setup failed' });\n  }\n});\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"charging-subsequent-recurring-payments","__idx":25},"children":["Charging subsequent recurring payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the Transactions API to charge subsequent payments from your backend scheduler:"]},{"$$mdtype":"Tag","name":"Endpoint","attributes":{"method":"POST"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["/v1/transactions"]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// BACKEND: Charge subsequent recurring payment\nasync function chargeRecurringPayment(subscription) {\n  const requestBody = {\n    merchant: \"MERCHANT-1\",\n    site: \"SITE-1\",\n    merchantTransactionId: `recurring-${Date.now()}`,\n    merchantTransactionDate: new Date().toISOString(),\n    transactionMethod: {\n      intent: \"Purchase\",\n      entryType: \"Ecom\",\n      fundingType: \"Card\"\n    },\n    fundingData: {\n      card: {\n        gatewayTokenId: subscription.gatewayTokenId\n      }\n    },\n    amounts: {\n      transaction: subscription.amount,\n      currencyCode: subscription.currency\n    },\n    recurring: {\n      processingModel: \"MerchantInitiatedSubsequentRecurring\"\n    }\n  };\n  \n  const path = 'api/v1/transactions';\n  const { authHeader, requestId } = createAuthHeader(\n    path,\n    JSON.stringify(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/${path}`,\n    {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'X-Client-Id': process.env.PXP_CLIENT_ID,\n        'X-Request-Id': requestId,\n        'Authorization': authHeader\n      },\n      body: JSON.stringify(requestBody)\n    }\n  );\n  \n  const result = await response.json();\n  \n  if (result.state === 'Captured' || result.state === 'Authorised') {\n    // Update subscription with next charge date\n    await database.subscriptions.update(subscription.id, {\n      lastChargeDate: new Date(),\n      nextChargeDate: calculateNextChargeDate(subscription.frequencyInDays),\n      lastTransactionId: result.systemTransactionId\n    });\n    \n    console.log('Recurring charge successful:', result.systemTransactionId);\n    return { success: true, transactionId: result.systemTransactionId };\n  } else {\n    console.error('Recurring charge failed:', result);\n    return { success: false, error: result.errorReason };\n  }\n}\n","lang":"javascript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/transactions/initiate-transactions"},"children":["Learn more about initiating transactions via API"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"saved-cards-card-on-file","__idx":26},"children":["Saved cards (card-on-file)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Card-on-file allows returning customers to pay faster by selecting from their saved cards. The drop-in automatically displays saved cards when you implement the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," callback."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["How it works:"]}]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer completes initial payment and consents to save their card."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The backend stores the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gatewayTokenId"]}," from the transaction."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["On a return visit, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," provides the shopper ID."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Drop-in displays saved cards for selection."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The customer selects a saved card and pays."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To enable saved cards display, implement the required ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," callback:"]},{"$$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';\n\n// Get session data from backend\nconst response = await fetch('/api/create-session', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' }\n});\n\nconst result = await response.json();\n\nif (!result.success || !result.data) {\n  console.error('Failed to create session:', result.error);\n  throw new Error('Session creation failed');\n}\n\nconst sessionData = result.data;\n\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  environment: 'test',\n  session: sessionData,\n  ownerId: 'MERCHANT-1',\n  ownerType: 'MerchantGroup',\n  transactionData: {\n    currency: 'USD',\n    amount: 99.99,\n    entryType: 'Ecom',\n    intent: { card: IntentType.Purchase },\n    merchantTransactionId: crypto.randomUUID(),\n    merchantTransactionDate: () => new Date().toISOString()\n  },\n  // REQUIRED: Provide shopper ID to enable card-on-file\n  onGetShopper: async () => {\n    // Get authenticated user's shopper ID from your session/auth system\n    const user = await getCurrentUser();\n    return { id: user.shopperId }; // e.g., { id: 'shopper-123' }\n  },\n  onSuccess: async (result: BaseSubmitResult) => {\n    await verifyPaymentOnBackend(result);\n    window.location.href = '/success';\n  },\n  onError: (error: BaseSdkException) => {\n    console.error('Payment failed:', error);\n    alert(`Payment failed: ${error.message}`);\n  }\n});\n\ncheckoutDropIn.create('checkout-drop-in-container');\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," returns a shopper ID, the drop-in automatically:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Fetches saved cards from the PXP API."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Displays them in a \"Saved Cards\" section above the new card form."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Allows customers to select and pay with saved cards."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"save-cards-during-checkout","__idx":27},"children":["Save cards during checkout"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Get customer consent before saving cards:"]},{"$$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\nconst checkoutDropIn = CheckoutDropIn.initialize({\n  // ... other config\n  onBeforeSubmit: async (paymentMethod: PaymentMethod) => {\n    // Only prompt for new card payments\n    if (paymentMethod === PaymentMethod.Card) {\n      const saveCard = confirm('Save this card for faster checkout next time?');\n      if (saveCard) {\n        // Store consent in your database\n        await storeCardConsent(user.id, true);\n      }\n    }\n    return true; // Proceed with payment\n  },\n  onSuccess: async (result: BaseSubmitResult) => {\n    // Verify payment and extract gatewayTokenId on backend\n    const response = await fetch('/api/verify-and-save-card', {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({\n        systemTransactionId: result.systemTransactionId,\n        merchantTransactionId: result.merchantTransactionId,\n        saveCard: true // Pass consent to backend\n      })\n    }).then(r => r.json());\n    \n    if (response.success) {\n      window.location.href = `/success?orderId=${response.orderId}`;\n    }\n  }\n});\n","lang":"typescript"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"backend-extract-and-store-gatewaytokenid","__idx":28},"children":["Backend: Extract and store gatewayTokenId"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After a successful payment, extract the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["gatewayTokenId"]}," from the transaction and store it:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"javascript","header":{"controls":{"copy":{}}},"source":"// BACKEND: Verify payment and save card token\napp.post('/api/verify-and-save-card', async (req, res) => {\n  const { systemTransactionId, merchantTransactionId, saveCard } = req.body;\n  \n  try {\n    // 1. Query PXP API to get transaction details\n    const txnPath = `api/v1/transactions/${systemTransactionId}`;\n    const { authHeader, requestId } = createAuthHeader(\n      txnPath,\n      '',\n      process.env.PXP_TOKEN_ID,\n      process.env.PXP_TOKEN_VALUE\n    );\n    \n    const transaction = await fetch(\n      `https://api-services.pxp.io/${txnPath}`,\n      {\n        headers: {\n          'X-Client-Id': process.env.PXP_CLIENT_ID,\n          'X-Request-Id': requestId,\n          'Authorization': authHeader\n        }\n      }\n    ).then(r => r.json());\n    \n    // 2. Verify transaction is successful\n    if (transaction.state !== 'Authorised' && transaction.state !== 'Captured') {\n      return res.json({ success: false, error: 'Transaction not successful' });\n    }\n    \n    // 3. Save gatewayTokenId if customer consented\n    if (saveCard && transaction.fundingData?.gatewayTokenId) {\n      await database.savedCards.insert({\n        shopperId: req.user.shopperId,\n        gatewayTokenId: transaction.fundingData.gatewayTokenId,\n        last4: transaction.fundingData.cardDetails?.last4Digits,\n        cardScheme: transaction.fundingData.cardScheme,\n        expiryMonth: transaction.fundingData.cardDetails?.expiryMonth,\n        expiryYear: transaction.fundingData.cardDetails?.expiryYear,\n        createdAt: new Date()\n      });\n    }\n    \n    // 4. Fulfill order\n    const orderId = await fulfillOrder(transaction);\n    \n    return res.json({ success: true, orderId });\n    \n  } catch (error) {\n    console.error('Verification error:', error);\n    return res.json({ success: false, error: 'Verification failed' });\n  }\n});\n","lang":"javascript"},"children":[]}]},"headings":[{"value":"Card","id":"card","depth":1},{"value":"Overview","id":"overview","depth":2},{"value":"Key benefits","id":"key-benefits","depth":3},{"value":"How it works","id":"how-it-works","depth":2},{"value":"Configuration","id":"configuration","depth":2},{"value":"Global settings that affect card","id":"global-settings-that-affect-card","depth":3},{"value":"Card-specific configuration","id":"card-specific-configuration","depth":3},{"value":"Complete example","id":"complete-example","depth":3},{"value":"Common scenarios","id":"common-scenarios","depth":2},{"value":"Payment intents","id":"payment-intents","depth":3},{"value":"Implementation","id":"implementation","depth":2},{"value":"Session configuration (backend)","id":"session-configuration-backend","depth":3},{"value":"Handling responses","id":"handling-responses","depth":2},{"value":"Card callback data","id":"card-callback-data","depth":3},{"value":"Error handling","id":"error-handling","depth":3},{"value":"Backend verification","id":"backend-verification","depth":2},{"value":"Backend verification code","id":"backend-verification-code","depth":3},{"value":"Verification checklist","id":"verification-checklist","depth":3},{"value":"Advanced card flows","id":"advanced-card-flows","depth":2},{"value":"3D Secure authentication","id":"3d-secure-authentication","depth":3},{"value":"Controlling 3DS behaviour","id":"controlling-3ds-behaviour","depth":3},{"value":"Recurring payments","id":"recurring-payments","depth":2},{"value":"How recurring payments work","id":"how-recurring-payments-work","depth":3},{"value":"Initial recurring payment setup","id":"initial-recurring-payment-setup","depth":3},{"value":"Backend: Store recurring payment token","id":"backend-store-recurring-payment-token","depth":3},{"value":"Charging subsequent recurring payments","id":"charging-subsequent-recurring-payments","depth":3},{"value":"Saved cards (card-on-file)","id":"saved-cards-card-on-file","depth":3},{"value":"Save cards during checkout","id":"save-cards-during-checkout","depth":3},{"value":"Backend: Extract and store gatewayTokenId","id":"backend-extract-and-store-gatewaytokenid","depth":3}],"frontmatter":{"seo":{"title":"Card"}},"lastModified":"2026-05-06T10:44:47.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/drop-in/web/cards","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}