{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["accordion","code-walkthrough","step","admonition"]},"type":"markdown"},"seo":{"title":"Quickstart","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":"quickstart","__idx":0},"children":["Quickstart"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"span","attributes":{"style":{"display":"inline-block","fontSize":"20px","color":"#3A3D40","borderRadius":"0","fontWeight":"500","verticalAlign":"middle","lineHeight":"1.5","margin":"0 auto 20px auto!important"}},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Follow our walkthrough to get Components for Web running in minutes."]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This quickstart focuses on card payments, but Components for Web also supports Apple Pay, Google Pay, and PayPal. See the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#whats-next"},"children":["What's next?"]}," section for links to other payment methods."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"pre-requisites","__idx":1},"children":["Pre-requisites"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before you start, make sure you have:"]},{"$$mdtype":"Tag","name":"ul","attributes":{"className":"code-walkthrough-list"},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Node.js 22.x or higher installed on your computer"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Your API credentials from the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://portal.pxp.io","target":"_blank"},"children":["Unity Portal"]}]}]},{"$$mdtype":"Tag","name":"Accordion","attributes":{"title":"Where to find your credentials","defaultOpen":false},"children":[{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["In the Unity Portal, go to ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Merchant setup > Merchant groups"]}," and select a merchant group."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Inbound calls"]}," tab. Your client ID is in the top right."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Click ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["+ New token"]}," to create a token, then copy both the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["ID"]}," and the ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Value"]},"."]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"install-the-sdk","__idx":2},"children":["Install the SDK"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To get started, install the latest version of the Web SDK from the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://www.npmjs.com/package/@pxpio/web-components-sdk","target":"_blank"},"children":["npm public registry"]},". You'll need to have Node.js 22.x or higher."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"shell","header":{"controls":{"copy":{}}},"source":"npm i @pxpio/web-components-sdk\n","lang":"shell"},"children":[]},{"$$mdtype":"Tag","name":"CodeWalkthrough","attributes":{"__idx":1,"filters":{},"filesets":[{"files":[{"path":"guides/checkout/components/web/_filesets/installation/create-session.js","content":["import crypto from 'node:crypto';","",{"start":2,"condition":{"steps":["credentials-setup"]},"children":["// Your API credentials from the Unity Portal","const TOKEN_ID = '9aac6071-38d0-4545-9d2f-15b936af6d7f'; // Replace this with your token ID","const TOKEN_VALUE = 'your-token-value-here'; // Replace this with your token value","const CLIENT_ID = 'f47ac10b-58cc-4372-a567-0e02b2c3d479'; // Replace this with your client ID"]},"","const REQUEST_PATH = 'api/v1/sessions';","",{"start":11,"condition":{"steps":["create-signature-function"]},"children":["/**"," * Creates an HMAC signature for authenticating API requests"," */","function createHmacSignature(","  timestamp,","  requestId,","  requestPath,","  requestBody,","  tokenValue,",") {","  const stringToHash = `${timestamp}${requestId}${requestPath}${requestBody}`;","  const hmac = crypto.createHmac('sha256', tokenValue);","","  hmac.update(stringToHash);","","  return hmac.digest('hex').toUpperCase();","}"]},"","/**"," * This function is a helper to create a new checkout session from merchant backend."," */","export async function createSession({","  merchantId,","  siteId,","  amount,","  currency,","}) {","  // Generate unique IDs for this request","  const timestamp = Math.floor(Date.now() / 1000);","  const requestId = crypto.randomUUID();","  const merchantTransactionId = crypto.randomUUID();","",{"start":45,"condition":{"steps":["build-request-body"]},"children":["  // Build the request body","  const requestBody = {","    merchant: merchantId,","    site: siteId,","    sessionTimeout: 120,","    merchantTransactionId,","    transactionMethod: {","      intent: {","        card: 'Authorisation',","      },","    },","    amounts: {","      currencyCode: currency,","      transactionValue: amount,","    },","    allowTransaction: true,","  };","","  const requestBodyString = JSON.stringify(requestBody);"]},"  ",{"start":67,"condition":{"steps":["generate-signature"]},"children":["  const signature = createHmacSignature(","    timestamp,","    requestId,","    REQUEST_PATH,","    requestBodyString,","    TOKEN_VALUE,","  );"]},"",{"start":77,"condition":{"steps":["send-session-request"]},"children":["  const response = await fetch(`https://api-services.dev.pxp.io/${REQUEST_PATH}`, {","    method: 'POST',","    headers: {","      'Authorization': `PXP-UST1 ${TOKEN_ID}:${timestamp}:${signature}`,","      'X-Request-Id': requestId,","      'X-Client-Id': CLIENT_ID,","      'Content-Type': 'application/json',","    },","    body: requestBodyString,","  });"]},"",{"start":90,"condition":{"steps":["handle-response"]},"children":["  if (!response.ok) {","    const errorText = await response.text();","    throw new Error(","      `Session creation failed (${response.status}): ${errorText || response.statusText}`,","    );","  }","","  const sessionData = await response.json();","","  return {","    ...sessionData,","    merchantTransactionId,","  };"]},"}",""],"metadata":{"steps":["credentials-setup","create-signature-function","build-request-body","generate-signature","send-session-request","handle-response"]},"basename":"create-session.js","language":"javascript"}],"downloadAssociatedFiles":[{"path":"guides/checkout/components/web/_filesets/installation/create-session.js","content":["import crypto from 'node:crypto';","",{"start":2,"condition":{"steps":["credentials-setup"]},"children":["// Your API credentials from the Unity Portal","const TOKEN_ID = '9aac6071-38d0-4545-9d2f-15b936af6d7f'; // Replace this with your token ID","const TOKEN_VALUE = 'your-token-value-here'; // Replace this with your token value","const CLIENT_ID = 'f47ac10b-58cc-4372-a567-0e02b2c3d479'; // Replace this with your client ID"]},"","const REQUEST_PATH = 'api/v1/sessions';","",{"start":11,"condition":{"steps":["create-signature-function"]},"children":["/**"," * Creates an HMAC signature for authenticating API requests"," */","function createHmacSignature(","  timestamp,","  requestId,","  requestPath,","  requestBody,","  tokenValue,",") {","  const stringToHash = `${timestamp}${requestId}${requestPath}${requestBody}`;","  const hmac = crypto.createHmac('sha256', tokenValue);","","  hmac.update(stringToHash);","","  return hmac.digest('hex').toUpperCase();","}"]},"","/**"," * This function is a helper to create a new checkout session from merchant backend."," */","export async function createSession({","  merchantId,","  siteId,","  amount,","  currency,","}) {","  // Generate unique IDs for this request","  const timestamp = Math.floor(Date.now() / 1000);","  const requestId = crypto.randomUUID();","  const merchantTransactionId = crypto.randomUUID();","",{"start":45,"condition":{"steps":["build-request-body"]},"children":["  // Build the request body","  const requestBody = {","    merchant: merchantId,","    site: siteId,","    sessionTimeout: 120,","    merchantTransactionId,","    transactionMethod: {","      intent: {","        card: 'Authorisation',","      },","    },","    amounts: {","      currencyCode: currency,","      transactionValue: amount,","    },","    allowTransaction: true,","  };","","  const requestBodyString = JSON.stringify(requestBody);"]},"  ",{"start":67,"condition":{"steps":["generate-signature"]},"children":["  const signature = createHmacSignature(","    timestamp,","    requestId,","    REQUEST_PATH,","    requestBodyString,","    TOKEN_VALUE,","  );"]},"",{"start":77,"condition":{"steps":["send-session-request"]},"children":["  const response = await fetch(`https://api-services.dev.pxp.io/${REQUEST_PATH}`, {","    method: 'POST',","    headers: {","      'Authorization': `PXP-UST1 ${TOKEN_ID}:${timestamp}:${signature}`,","      'X-Request-Id': requestId,","      'X-Client-Id': CLIENT_ID,","      'Content-Type': 'application/json',","    },","    body: requestBodyString,","  });"]},"",{"start":90,"condition":{"steps":["handle-response"]},"children":["  if (!response.ok) {","    const errorText = await response.text();","    throw new Error(","      `Session creation failed (${response.status}): ${errorText || response.statusText}`,","    );","  }","","  const sessionData = await response.json();","","  return {","    ...sessionData,","    merchantTransactionId,","  };"]},"}",""],"metadata":{"steps":["credentials-setup","create-signature-function","build-request-body","generate-signature","send-session-request","handle-response"]},"basename":"create-session.js","language":"javascript"}]}],"steps":[{"id":"credentials-setup","heading":"Store your credentials securely"},{"id":"create-signature-function","heading":"Create the HMAC signature function"},{"id":"build-request-body","heading":"Build the session request body"},{"id":"generate-signature","heading":"Generate the HMAC signature"},{"id":"send-session-request","heading":"Send the session creation request"},{"id":"handle-response","heading":"Return the session data to your frontend"}],"inputs":{},"toggles":{}},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"create-a-session-on-your-backend","__idx":3},"children":["Create a session on your backend"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Components for Web needs a session from the PXP API. This must happen on your backend using HMAC authentication."]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"credentials-setup","heading":"Store your credentials securely"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set up your API credentials as environment variables — never hardcode them in your application."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"create-signature-function","heading":"Create the HMAC signature function"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This function generates a secure authentication hash by combining timestamp, request ID, request path, and request body, then hashing with your token value using HMAC SHA256."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"build-request-body","heading":"Build the session request body"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a request with your merchant details and transaction information. The request body must be minified (no whitespace) for the HMAC signature."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"generate-signature","heading":"Generate the HMAC signature"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Call the signature function with your credentials and request details."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"send-session-request","heading":"Send the session creation request"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["POST to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://api-services.dev.pxp.io/api/v1/sessions"]}," with your authentication headers and request body."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"handle-response","heading":"Return the session data to your frontend"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The API returns ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sessionId"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["hmacKey"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["encryptionKey"]},", and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["allowedFundingTypes"]},". Pass this entire response to your frontend."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you want to use 3DS, call the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://developer.pxp.io/apis/session/other/modify-session"},"children":["Modify session API"]}," to set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authentication = true"]},". If you want to skip 3DS, set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authentication = false"]},"."]}]}]},{"$$mdtype":"Tag","name":"CodeWalkthrough","attributes":{"__idx":2,"filters":{},"filesets":[{"files":[{"path":"guides/checkout/components/web/_filesets/installation/CheckoutPage.tsx","content":[{"start":0,"condition":{"steps":["import-dependencies"]},"children":["import { PxpCheckout, IntentType } from '@pxpio/web-components-sdk';","import { useEffect, useState } from 'react';"]},"",{"start":5,"condition":{"steps":["setup-component"]},"children":["export default function CheckoutPage() {",{"start":7,"condition":{"steps":["fetch-session"]},"children":["  const [sessionData, setSessionData] = useState<any>(null);","  const createSession = async () => {","    const sessionData = await fetch('/api/sessions', {","      method: 'POST',","      headers: { 'Content-Type': 'application/json' },","      body: JSON.stringify({","        merchantId: MERCHANT_ID, // Replace with your merchant ID","        siteId: SITE_ID, // Replace with your site ID","        amount: 25,","        currency: 'USD'","      }),","    }).then(response => response.json());","    setSessionData(sessionData);","  };","","  useEffect(() => {","    //1. Create a new session","    createSession();","  }, []);"]},"","  useEffect(() => {","    if (sessionData) {",{"start":31,"condition":{"steps":["initialize-sdk"]},"children":["      // 2. Initialise the SDK","      const pxpSdk = PxpCheckout.initialize({","        environment: 'test',","        session: sessionData,","        ownerId: MERCHANT_GROUP_ID // Replace width your merchant group id,","        ownerType: 'MerchantGroup',",{"start":38,"condition":{"steps":["configure-transaction"]},"children":["        transactionData: {","          currency: 'USD',","          amount: 25,","          entryType: 'Ecom',","          intent: {","            card: IntentType.Authorisation","          },","          merchantTransactionId: sessionData.merchantTransactionId,","          merchantTransactionDate: () => new Date().toISOString()","        },"]},{"start":50,"condition":{"steps":["setup-shopper"]},"children":["        onGetShopper: async () => {","          // Option 1: Fetch from your API","          // const shopper = await fetch('/api/get-shopper').then(r => r.json());","          // return shopper;","          ","          // Option 2: Return hardcoded values","          return { ","            id: 'shopper-123', // Required for COF and one-click","            email: 'customer@example.com',","            firstName: 'John',","            lastName: 'Doe'","          };","        }"]},"      });"]},"",{"start":68,"condition":{"steps":["create-component"]},"children":["      // 3. Create the new card component","      const newCard = pxpSdk.create('new-card', {",{"start":71,"condition":{"steps":["configure-fields"]},"children":["        fields: {","          cardNumber: {","            required: true,","            placeholder: '1234 5678 9012 3456',","            acceptedCardBrands: ['visa', 'mastercard', 'cup', 'diners', 'discover', 'jcb'],","          },","          expiryDate: {","            required: true,","            placeholder: 'MM/YY'","          },","          cvc: {","            required: true,","            placeholder: '123'","          },","          holderName: {","            required: true,","            placeholder: 'John Doe'","          }","        },"]},{"start":92,"condition":{"steps":["configure-submit-button"]},"children":["        submit: {","          submitText: 'Pay $25.00',","          styles: {","            backgroundColor: '#4CAF50',","            color: 'white',","            padding: '15px',","            borderRadius: '6px',","            fontSize: '16px',","            fontWeight: 'bold',","            width: '100%'","          },"]},"",{"start":106,"condition":{"steps":["3ds-callbacks"]},"children":["          // Only include onPreInitiateAuthentication, onPostInitiateAuthentication, onPreAuthentication, onPostAuthentication if backend set authentication = true","          onPreInitiateAuthentication: () => {","            return {","              providerId: 'pxpfinancial',","              timeout: 12","            };","          },","          onPostInitiateAuthentication: (data: any) => {","            console.log('3DS authentication initiated:', data);","          },","          onPreAuthentication: async () => {","            return {","              merchantCountryNumericCode: '100',","              merchantLegalName: 'TestMerchant_10',","              challengeWindowSize: 1,","              requestorChallengeIndicator: '02'","            };","          },","          onPostAuthentication: (data: any) => {","            console.log('3DS authentication completed:', data);","            // Optional: Retrieve authentication details from backend","            // and update session decision if needed","          },"]},"",{"start":132,"condition":{"steps":["authorisation-decision"]},"children":["          onPreAuthorisation: () => {","            return {};","          },"]},{"start":137,"condition":{"steps":["success-callback"]},"children":["          onPostAuthorisation: async (data: any) => {","            // CRITICAL: Do NOT fulfill order here!","            // Frontend callbacks can be manipulated by malicious users.","            // Always verify payment on your backend first.","            ","            console.log('Transaction completed:', data.systemTransactionId, data.merchantTransactionId);","            ","            // Verify payment on your backend","            const verified = await fetch('/api/verify-payment', {","              method: 'POST',","              headers: { 'Content-Type': 'application/json' },","              body: JSON.stringify({","                systemTransactionId: data.systemTransactionId,","                merchantTransactionId: data.merchantTransactionId,","                amount: 25","              })","            }).then(r => r.json());","            ","            if (verified.success) {","              globalThis.location.href = `/success?orderId=${verified.orderId}`;","            } else {","              alert('Payment verification failed. Please contact support.');","            }","          },"]},{"start":163,"condition":{"steps":["error-callback"]},"children":["          onSubmitError: (error: any) => {","            console.error('Payment failed:', error);","            alert('Payment failed. Please check your card details and try again.');","          },"]},"        }","      });"]},"",{"start":173,"condition":{"steps":["mount-component"]},"children":["      // 4. Mount the component to your page","      newCard.mount('new-card-container');","","      return () => {","        // 5. Unmount the component","        newCard.unmount();","      };"]},"    }","  }, [sessionData]);","",{"start":185,"condition":{"steps":["render-container"]},"children":["  return (","    <div>","      <h1>Complete Your Purchase</h1>","      <div id=\"new-card-container\"></div>","    </div>","  );"]},"}"]},""],"metadata":{"steps":["import-dependencies","setup-component","fetch-session","initialize-sdk","configure-transaction","setup-shopper","create-component","configure-fields","configure-submit-button","3ds-callbacks","authorisation-decision","success-callback","error-callback","mount-component","render-container"]},"basename":"CheckoutPage.tsx","language":"tsx"}],"downloadAssociatedFiles":[{"path":"guides/checkout/components/web/_filesets/installation/CheckoutPage.tsx","content":[{"start":0,"condition":{"steps":["import-dependencies"]},"children":["import { PxpCheckout, IntentType } from '@pxpio/web-components-sdk';","import { useEffect, useState } from 'react';"]},"",{"start":5,"condition":{"steps":["setup-component"]},"children":["export default function CheckoutPage() {",{"start":7,"condition":{"steps":["fetch-session"]},"children":["  const [sessionData, setSessionData] = useState<any>(null);","  const createSession = async () => {","    const sessionData = await fetch('/api/sessions', {","      method: 'POST',","      headers: { 'Content-Type': 'application/json' },","      body: JSON.stringify({","        merchantId: MERCHANT_ID, // Replace with your merchant ID","        siteId: SITE_ID, // Replace with your site ID","        amount: 25,","        currency: 'USD'","      }),","    }).then(response => response.json());","    setSessionData(sessionData);","  };","","  useEffect(() => {","    //1. Create a new session","    createSession();","  }, []);"]},"","  useEffect(() => {","    if (sessionData) {",{"start":31,"condition":{"steps":["initialize-sdk"]},"children":["      // 2. Initialise the SDK","      const pxpSdk = PxpCheckout.initialize({","        environment: 'test',","        session: sessionData,","        ownerId: MERCHANT_GROUP_ID // Replace width your merchant group id,","        ownerType: 'MerchantGroup',",{"start":38,"condition":{"steps":["configure-transaction"]},"children":["        transactionData: {","          currency: 'USD',","          amount: 25,","          entryType: 'Ecom',","          intent: {","            card: IntentType.Authorisation","          },","          merchantTransactionId: sessionData.merchantTransactionId,","          merchantTransactionDate: () => new Date().toISOString()","        },"]},{"start":50,"condition":{"steps":["setup-shopper"]},"children":["        onGetShopper: async () => {","          // Option 1: Fetch from your API","          // const shopper = await fetch('/api/get-shopper').then(r => r.json());","          // return shopper;","          ","          // Option 2: Return hardcoded values","          return { ","            id: 'shopper-123', // Required for COF and one-click","            email: 'customer@example.com',","            firstName: 'John',","            lastName: 'Doe'","          };","        }"]},"      });"]},"",{"start":68,"condition":{"steps":["create-component"]},"children":["      // 3. Create the new card component","      const newCard = pxpSdk.create('new-card', {",{"start":71,"condition":{"steps":["configure-fields"]},"children":["        fields: {","          cardNumber: {","            required: true,","            placeholder: '1234 5678 9012 3456',","            acceptedCardBrands: ['visa', 'mastercard', 'cup', 'diners', 'discover', 'jcb'],","          },","          expiryDate: {","            required: true,","            placeholder: 'MM/YY'","          },","          cvc: {","            required: true,","            placeholder: '123'","          },","          holderName: {","            required: true,","            placeholder: 'John Doe'","          }","        },"]},{"start":92,"condition":{"steps":["configure-submit-button"]},"children":["        submit: {","          submitText: 'Pay $25.00',","          styles: {","            backgroundColor: '#4CAF50',","            color: 'white',","            padding: '15px',","            borderRadius: '6px',","            fontSize: '16px',","            fontWeight: 'bold',","            width: '100%'","          },"]},"",{"start":106,"condition":{"steps":["3ds-callbacks"]},"children":["          // Only include onPreInitiateAuthentication, onPostInitiateAuthentication, onPreAuthentication, onPostAuthentication if backend set authentication = true","          onPreInitiateAuthentication: () => {","            return {","              providerId: 'pxpfinancial',","              timeout: 12","            };","          },","          onPostInitiateAuthentication: (data: any) => {","            console.log('3DS authentication initiated:', data);","          },","          onPreAuthentication: async () => {","            return {","              merchantCountryNumericCode: '100',","              merchantLegalName: 'TestMerchant_10',","              challengeWindowSize: 1,","              requestorChallengeIndicator: '02'","            };","          },","          onPostAuthentication: (data: any) => {","            console.log('3DS authentication completed:', data);","            // Optional: Retrieve authentication details from backend","            // and update session decision if needed","          },"]},"",{"start":132,"condition":{"steps":["authorisation-decision"]},"children":["          onPreAuthorisation: () => {","            return {};","          },"]},{"start":137,"condition":{"steps":["success-callback"]},"children":["          onPostAuthorisation: async (data: any) => {","            // CRITICAL: Do NOT fulfill order here!","            // Frontend callbacks can be manipulated by malicious users.","            // Always verify payment on your backend first.","            ","            console.log('Transaction completed:', data.systemTransactionId, data.merchantTransactionId);","            ","            // Verify payment on your backend","            const verified = await fetch('/api/verify-payment', {","              method: 'POST',","              headers: { 'Content-Type': 'application/json' },","              body: JSON.stringify({","                systemTransactionId: data.systemTransactionId,","                merchantTransactionId: data.merchantTransactionId,","                amount: 25","              })","            }).then(r => r.json());","            ","            if (verified.success) {","              globalThis.location.href = `/success?orderId=${verified.orderId}`;","            } else {","              alert('Payment verification failed. Please contact support.');","            }","          },"]},{"start":163,"condition":{"steps":["error-callback"]},"children":["          onSubmitError: (error: any) => {","            console.error('Payment failed:', error);","            alert('Payment failed. Please check your card details and try again.');","          },"]},"        }","      });"]},"",{"start":173,"condition":{"steps":["mount-component"]},"children":["      // 4. Mount the component to your page","      newCard.mount('new-card-container');","","      return () => {","        // 5. Unmount the component","        newCard.unmount();","      };"]},"    }","  }, [sessionData]);","",{"start":185,"condition":{"steps":["render-container"]},"children":["  return (","    <div>","      <h1>Complete Your Purchase</h1>","      <div id=\"new-card-container\"></div>","    </div>","  );"]},"}"]},""],"metadata":{"steps":["import-dependencies","setup-component","fetch-session","initialize-sdk","configure-transaction","setup-shopper","create-component","configure-fields","configure-submit-button","3ds-callbacks","authorisation-decision","success-callback","error-callback","mount-component","render-container"]},"basename":"CheckoutPage.tsx","language":"tsx"},{"path":"guides/checkout/components/web/_filesets/installation/package.json","content":["{","  \"name\": \"checkout-integration\",","  \"version\": \"1.0.0\",","  \"description\": \"PXP Components for Web integration example\",","  \"type\": \"module\",","  \"scripts\": {","    \"dev\": \"vite\",","    \"build\": \"vite build\"","  },","  \"dependencies\": {","    \"@pxpio/web-components-sdk\": \"^latest\",","    \"react\": \"^18.2.0\",","    \"react-dom\": \"^18.2.0\"","  },","  \"devDependencies\": {","    \"@vitejs/plugin-react\": \"^4.0.0\",","    \"vite\": \"^4.0.0\"","  }","}",""],"metadata":{"steps":[]},"basename":"package.json","language":"text"}]}],"steps":[{"id":"import-dependencies","heading":"Import the required dependencies"},{"id":"setup-component","heading":"Set up your React component"},{"id":"fetch-session","heading":"Fetch the session data from your backend"},{"id":"initialize-sdk","heading":"Initialise the SDK"},{"id":"configure-transaction","heading":"Configure the transaction data"},{"id":"setup-shopper","heading":"Provide shopper information"},{"id":"create-component","heading":"Create the new card component"},{"id":"configure-fields","heading":"Configure the card input fields"},{"id":"configure-submit-button","heading":"Configure the submit button"},{"id":"success-callback","heading":"Handle successful payments"},{"id":"error-callback","heading":"Handle payment errors"},{"id":"3ds-callbacks","heading":"Implement 3DS callbacks (if using 3DS)"},{"id":"authorisation-decision","heading":"Implement pre-authorisation callback"},{"id":"mount-component","heading":"Mount the component to the page"},{"id":"render-container","heading":"Add a container element to your page"}],"inputs":{},"toggles":{}},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"initialise-the-card-component-on-your-frontend","__idx":4},"children":["Initialise the card component on your frontend"]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"import-dependencies","heading":"Import the required dependencies"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Import ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["PxpCheckout"]}," and necessary types from the Web SDK."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"setup-component","heading":"Set up your React component"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create a React component that will host the card payment interface."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"fetch-session","heading":"Fetch the session data from your backend"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Call your backend endpoint to get the session data you created in the previous steps."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"initialize-sdk","heading":"Initialise the SDK"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure the SDK with your environment, session data, owner details, and transaction information."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"configure-transaction","heading":"Configure the transaction data"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Specify the currency, amount, entry type, and payment intent for card transactions."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"setup-shopper","heading":"Provide shopper information"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onGetShopper"]}," callback to provide shopper details. This callback is called whenever the SDK needs shopper data during the payment flow."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The shopper ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]}," is particularly important because it enables card-on-file (COF), one-click payments, and the consent tickbox for storing cards. You can fetch shopper data from your API or return hardcoded values."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["If you don't provide a shopper ID:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Card-on-file components won't be able to retrieve saved cards"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["One-click payment functionality won't work"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["The consent tickbox for storing cards will not appear"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["If you do provide a shopper ID:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Card-on-file and one-click components will retrieve cards from the Token Vault for that shopper"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["When the shopper ticks the consent checkbox during payment, their card will be stored in the Token Vault under that shopper ID for future use"]}]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"create-component","heading":"Create the new card component"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use the SDK's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["create()"]}," method to create a new card component with your desired configuration."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"configure-fields","heading":"Configure the card input fields"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set up the card number, expiry date, CVC, and cardholder name fields with placeholders and validation rules."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"configure-submit-button","heading":"Configure the submit button"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Customise the submit button text and styling to match your brand."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"success-callback","heading":"Handle successful payments"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostAuthorisation"]}," callback to handle successful payments. Always verify payments on your backend before fulfilling orders — frontend callbacks can be manipulated."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"error-callback","heading":"Handle payment errors"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onSubmitError"]}," callback to handle payment failures and display error messages to the user."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"3ds-callbacks","heading":"Implement 3DS callbacks (if using 3DS)"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you want to use 3DS authentication, implement the required ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreInitiateAuthentication"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreAuthentication"]}," callbacks. You can optionally add ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostInitiateAuthentication"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostAuthentication"]}," for monitoring."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your backend must set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authentication = true"]}," in the session if you include these callbacks, or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["false"]}," if you omit them. If they don't match, you'll see ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["CAD4005: Authentication decision is required but not provided"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To skip 3DS, set ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["authentication = false"]}," in your backend session via the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"https://developer.pxp.io/apis/session/other/modify-session"},"children":["Modify session API"]},", and omit the 3DS callbacks from your component configuration."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"authorisation-decision","heading":"Implement pre-authorisation callback"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPreAuthorisation"]}," callback. Return an empty object ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{}"]}," to proceed, or optionally include AVS or risk screening data."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"mount-component","heading":"Mount the component to the page"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Call the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["mount()"]}," method with your container element ID to render the payment form."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"render-container","heading":"Add a container element to your page"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Return JSX that includes a container div where the card component will mount itself."]}]}]},{"$$mdtype":"Tag","name":"CodeWalkthrough","attributes":{"__idx":3,"filters":{},"filesets":[{"files":[{"path":"guides/checkout/components/web/_filesets/installation/webhook-handler.js","content":[{"start":0,"condition":{"steps":["webhook-endpoint"]},"children":["// Webhook endpoint to receive payment notifications","// Configure this URL in the Unity Portal under Webhooks","app.post('/webhooks/pxp', async (req, res) => {"]},{"start":5,"condition":{"steps":["process-events"]},"children":["  const events = req.body;","  ","  // Process each webhook event","  for (const event of events) {","    if (event.eventCategory === 'Transaction') {","      const txn = event.eventData;"]},"      ",{"start":14,"condition":{"steps":["check-state"]},"children":["      // Check if payment was successful","      if (txn.state === 'Authorised' || txn.state === 'Captured') {"]},{"start":18,"condition":{"steps":["prevent-duplicates"]},"children":["        // Prevent duplicate processing","        const alreadyProcessed = await isTransactionProcessed(txn.systemTransactionId);","        if (alreadyProcessed) {","          continue;","        }"]},"        ",{"start":26,"condition":{"steps":["verify-details"]},"children":["        // Verify transaction details match your records","        const expectedOrder = await getOrderByMerchantTransactionId(txn.merchantTransactionId);","        ","        if (expectedOrder && ","            txn.amounts.transactionValue === expectedOrder.amount &&","            txn.amounts.currencyCode === expectedOrder.currency) {"]},"          ",{"start":35,"condition":{"steps":["fulfill-order"]},"children":["          // Payment verified - fulfill the order","          await fulfillOrder(txn.merchantTransactionId);","          ","          // Mark as processed to prevent duplicates","          await markTransactionProcessed(txn.systemTransactionId);","          ","          console.log(`Order ${txn.merchantTransactionId} fulfilled successfully`);"]},"        } else {","          console.error('Transaction verification failed - amount or currency mismatch');","        }","      }","    }","  }","  ",{"start":51,"condition":{"steps":["respond"]},"children":["  // Always return success to acknowledge receipt","  res.json({ state: 'Success' });"]},"});",""],"metadata":{"steps":["webhook-endpoint","process-events","check-state","prevent-duplicates","verify-details","fulfill-order","respond"]},"basename":"webhook-handler.js","language":"javascript"}],"downloadAssociatedFiles":[{"path":"guides/checkout/components/web/_filesets/installation/webhook-handler.js","content":[{"start":0,"condition":{"steps":["webhook-endpoint"]},"children":["// Webhook endpoint to receive payment notifications","// Configure this URL in the Unity Portal under Webhooks","app.post('/webhooks/pxp', async (req, res) => {"]},{"start":5,"condition":{"steps":["process-events"]},"children":["  const events = req.body;","  ","  // Process each webhook event","  for (const event of events) {","    if (event.eventCategory === 'Transaction') {","      const txn = event.eventData;"]},"      ",{"start":14,"condition":{"steps":["check-state"]},"children":["      // Check if payment was successful","      if (txn.state === 'Authorised' || txn.state === 'Captured') {"]},{"start":18,"condition":{"steps":["prevent-duplicates"]},"children":["        // Prevent duplicate processing","        const alreadyProcessed = await isTransactionProcessed(txn.systemTransactionId);","        if (alreadyProcessed) {","          continue;","        }"]},"        ",{"start":26,"condition":{"steps":["verify-details"]},"children":["        // Verify transaction details match your records","        const expectedOrder = await getOrderByMerchantTransactionId(txn.merchantTransactionId);","        ","        if (expectedOrder && ","            txn.amounts.transactionValue === expectedOrder.amount &&","            txn.amounts.currencyCode === expectedOrder.currency) {"]},"          ",{"start":35,"condition":{"steps":["fulfill-order"]},"children":["          // Payment verified - fulfill the order","          await fulfillOrder(txn.merchantTransactionId);","          ","          // Mark as processed to prevent duplicates","          await markTransactionProcessed(txn.systemTransactionId);","          ","          console.log(`Order ${txn.merchantTransactionId} fulfilled successfully`);"]},"        } else {","          console.error('Transaction verification failed - amount or currency mismatch');","        }","      }","    }","  }","  ",{"start":51,"condition":{"steps":["respond"]},"children":["  // Always return success to acknowledge receipt","  res.json({ state: 'Success' });"]},"});",""],"metadata":{"steps":["webhook-endpoint","process-events","check-state","prevent-duplicates","verify-details","fulfill-order","respond"]},"basename":"webhook-handler.js","language":"javascript"}]}],"steps":[{"id":"webhook-endpoint","heading":"Create the webhook endpoint"},{"id":"process-events","heading":"Process webhook events"},{"id":"check-state","heading":"Check payment state"},{"id":"prevent-duplicates","heading":"Prevent duplicate processing"},{"id":"verify-details","heading":"Verify transaction details"},{"id":"fulfill-order","heading":"Fulfill the order"},{"id":"respond","heading":"Respond to webhook"}],"inputs":{},"toggles":{}},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"verify-payments","__idx":5},"children":["Verify payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a payment succeeds, the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["onPostAuthorisation"]}," callback fires with transaction details. However, you must ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["always verify the payment on your backend"]}," before fulfilling orders."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Configure webhooks in the Unity Portal to receive real-time payment notifications on your backend."]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"webhook-endpoint","heading":"Create the webhook endpoint"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Set up an endpoint at ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/webhooks/pxp"]}," to receive payment notifications from Unity."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"process-events","heading":"Process webhook events"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Loop through the events array and filter for Transaction events."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"check-state","heading":"Check payment state"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Verify the transaction state is ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Authorised"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Captured"]}," before processing."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"prevent-duplicates","heading":"Prevent duplicate processing"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check if you've already processed this transaction using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["systemTransactionId"]},"."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"verify-details","heading":"Verify transaction details"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Match the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["merchantTransactionId"]},", amount, and currency against your order records."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"fulfill-order","heading":"Fulfill the order"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If verification passes, fulfill the order and mark the transaction as processed."]}]},{"$$mdtype":"Tag","name":"CodeStep","attributes":{"id":"respond","heading":"Respond to webhook"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Always return ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{ state: 'Success' }"]}," to acknowledge receipt, even if processing failed."]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You can also verify payments using the Transactions API to query transaction status directly. See the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/checkout/components/web/card/implementation#backend-verification"},"children":["Integration guide"]}," for details."]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["That's it! You now have a working card payment integration with Components for Web."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"whats-next","__idx":6},"children":["What's next?"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Now that you have card components running, here are the recommended next steps:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Explore other payment methods:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{"className":"code-walkthrough-list"},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/apple-pay/how-it-works"},"children":["Apple Pay"]}]}," - Accept payments with Apple Pay"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/google-pay/how-it-works"},"children":["Google Pay"]}]}," - Accept payments with Google Pay"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/paypal/how-it-works"},"children":["PayPal"]}]}," - Accept payments with PayPal"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Enhance your card integration:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{"className":"code-walkthrough-list"},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/card/about-customisation"},"children":["Customise the look and feel"]}]}," to match your brand"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/card/implementation"},"children":["Explore additional components"]}]}," like billing address, ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/card/card-on-file"},"children":["card-on-file"]},", and ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/card/click-once"},"children":["one-click payments"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/card/events"},"children":["Add event callbacks"]}]}," to enhance the user experience with validation and loading states"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/checkout/components/web/card/3ds"},"children":["Enable 3D Secure"]}]}," for enhanced security and liability shift"]}]}]},"headings":[{"value":"Quickstart","id":"quickstart","depth":1},{"value":"Pre-requisites","id":"pre-requisites","depth":2},{"value":"Install the SDK","id":"install-the-sdk","depth":2},{"value":"Create a session on your backend","id":"create-a-session-on-your-backend","depth":2},{"value":"Initialise the card component on your frontend","id":"initialise-the-card-component-on-your-frontend","depth":2},{"value":"Verify payments","id":"verify-payments","depth":2},{"value":"What's next?","id":"whats-next","depth":2}],"frontmatter":{"markdown":{"toc":{"hide":true}},"footer":{"hide":true},"seo":{"title":"Quickstart"}},"lastModified":"2026-05-13T12:13:18.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/checkout/components/web/quickstart","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}