Skip to content

Card-on-file

Learn about how to configure the card-on-file component.

Basic usage

Minimal configuration

At minimum, the card-on-file component can be created with default settings to display all saved card tokens:

import PxpCheckout from '@pxp-io/web-components-sdk';

const pxpCheckout = PxpCheckout.initialize({
  session: {
    sessionId: 'your-session-id',
    hmacKey: 'your-hmac-key',
    encryptionKey: 'your-encryption-key'
  },
  environment: 'production',
  transactionData: {
    amount: 1000,
    currency: 'USD',
    entryType: 'Ecom',
    intent: {
      card: 'Authorisation'
    },
    merchantTransactionId: 'unique-transaction-id',
    merchantTransactionDate: () => new Date().toISOString()
  },
  ownerType: 'MerchantGroup',
  ownerId: 'your-owner-id'
});

// Create card-on-file component
const cardOnFileComponent = pxpCheckout.create('card-on-file', {});

// Mount component
cardOnFileComponent.mount('card-on-file-container');

Advanced configuration

For more complex implementations, you can configure filtering, sorting, and display options:

// Create additional components for card-on-file
const cardCvc = pxpCheckout.create('card-cvc', {
  label: "Security code",
  required: true
});

const cardExpiry = pxpCheckout.create('card-expiry-date', {
  label: "Expiry date"
});

// Create card-on-file with advanced configuration
const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  // Filtering options
  limitTokens: 5,
  filterBy: {
    excludeExpiredTokens: true,
    schemes: ["Visa", "Mastercard"],
    fundingSource: "Credit",
    issuerCountryCode: "USA",
    ownerType: "Consumer"
  },
  
  // Sorting options
  orderBy: {
    expiryDate: { 
      direction: "asc",
      priority: 1
    },
    scheme: { 
      valuesOrder: ["Visa", "Mastercard", "Amex"],
      priority: 2
    },
    fundingSource: { 
      valuesOrder: ["Credit", "Debit"],
      priority: 3
    },
    lastUsageDate: { 
      direction: "desc",
      orderByField: "lastSuccessfulPurchaseDate",
      priority: 4
    }
  },
  
  // UI configuration
  isExpiryDateEditable: true,
  isCvcRequired: true,
  allowDeleteToken: true,
  
  // Nested components
  cvcComponentConfig: {
    required: true,
    label: "Security code",
    applyMask: true,
    showMaskToggle: true
  },
  expiryDateComponentConfig: {
    label: "Expiry date",
    formatOptions: "MM/YY"
  }
});
PropertyDescription
limitTokens
number
The maximum number of tokens to display in the component. For example, if set to 5 then only the first five card tokens are displayed. Defaults to null.
filterBy
object
Details about the filtering options. Defaults to null.
filterBy.excludeExpiredTokens
boolean
Whether to exclude tokens associated with expired cards. Defaults to false.
filterBy.schemes
string[]
The list of card schemes to include. For example, ["Visa", "Mastercard"]. Defaults to null.
filterBy.fundingSource
string
The funding source type to include. For example Credit or Debit. Defaults to null.
filterBy.issuerCountryCode
string
The issuer country code to include. Defaults to null.
filterBy.ownerType
string
The owner type to include. Defaults to null.
orderBy
object
Details about the ordering options. Defaults to null.
orderBy.expiryDate
object
Details for ordering by expiry date. Defaults to null.
orderBy.expiryDate.direction
string
The direction to order by.

Possible values:
  • desc
  • asc
Defaults to null.
orderBy.expiryDate.priority
number
The priority of the ordering option. Defaults to null.
orderBy.scheme
object
Details for ordering by card scheme. Defaults to null.
orderBy.scheme.valuesOrder
string
The card scheme. Defaults to null.
orderBy.scheme.priority
number
The priority of the ordering option. Defaults to null.
orderBy.fundingSource
object
Details for ordering by funding source. Defaults to null.
orderBy.fundingSource.valuesOrder
string
The funding source.

Possible values:
  • Credit
  • Debit
Defaults to null.
orderBy.fundingSource.priority
number
The priority of the ordering option. Defaults to null.
orderBy.ownerType
object
Details for ordering by owner type. Defaults to null.
orderBy.ownerType.valuesOrder
string
The owner type.

Possible values:
  • Consumer
  • Commercial
Defaults to null.
orderBy.ownerType.priority
number
The priority of the ordering option. Defaults to null.
orderBy.issuerCountryCode
object
Details for ordering by issuer country code. Defaults to null.
orderBy.issuerCountryCode.direction
string
The direction to order by.

Possible values:
  • desc
  • asc
Defaults to null.
orderBy.issuerCountryCode.priority
number
The priority of the ordering option. Defaults to null.
orderBy.lastUsageDate
object
Details for ordering by last usage date. Defaults to null.
orderBy.lastUsageDate.direction
string
The direction to order by.

Possible values:
  • desc
  • asc
Defaults to null.
orderBy.lastUsageDate.orderByField
string
The field to order by.

Possible values:
  • lastSuccessfulPurchaseDate
  • lastSuccessfulPayoutDate
Defaults to null.
orderBy.lastUsageDate.priority
number
The priority of the ordering option. Defaults to null.
transactionInitiatorType
TransactionInitiatorType
Transaction initiator type. Defaults to null.
isExpiryDateEditable
boolean
Whether the expiry date field can be edited by the cardholder. Defaults to false.
isCvcRequired
boolean
Whether CVC is required when selecting a token. This applies to all tokens. Defaults to false.
allowDeleteToken
boolean
Whether to allow cardholders to delete a token (previously saved card). Defaults to false.
cvcComponentConfig
CardCvcComponentConfig
Configuration for the standalone card CVC component. See Card CVC. Defaults to null.
expiryDateComponentConfig
CardExpiryDateComponentConfig
Configuration for the standalone card expiry date component. See Card expiry date. Defaults to null.

Styling

Default styling

The card-on-file component renders saved cards with these default styles:

const defaultCardOnFileStyles = {
  container: {
    display: 'flex',
    flexDirection: 'column',
    gap: '12px',
    width: '100%'
  },
  
  tokenItem: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: '16px',
    backgroundColor: '#ffffff',
    border: '1px solid #dee2e6',
    borderRadius: '8px',
    cursor: 'pointer'
  },
  
  cardBrandImage: {
    width: '40px',
    height: 'auto'
  },
  
  cardDetails: {
    display: 'flex',
    flexDirection: 'column',
    gap: '4px'
  },
  
  expiredText: {
    color: '#dc3545',
    fontSize: '12px',
    fontWeight: '500'
  },
  
  validThruText: {
    color: '#6c757d',
    fontSize: '12px'
  }
};
PropertyDescription
id
string
Unique identifier for the component element. Defaults to null.
class
string
CSS class name applied to the component. Defaults to null.
tokenItemClass
string
Custom class for the token item. Defaults to null.

Custom styling

You can override the default appearance by providing custom styles, images, and text labels:

const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  // Custom text labels
  expiredText: "Card expired",
  validThruText: "Valid until",
  deleteErrorMessage: "Unable to delete card. Please try again.",
  deleteSuccessMessage: "Card has been removed successfully.",
  updateErrorMessage: "Unable to update card information. Please try again.",
  updateSuccessMessage: "Card information updated successfully.",
  
  // Custom styling
  styles: {
    backgroundColor: '#f8f9fa',
    border: '1px solid #dee2e6',
    borderRadius: '8px',
    padding: '20px'
  },
  
  inputStyles: {
    borderRadius: '5px',
    backgroundColor: '#ffffff'
  },
  
  tokenItemClass: "custom-token-item-class",
  
  // Custom icons
  iconDeleteSrc: "https://example.com/icons/delete.svg",
  iconSaveSrc: "https://example.com/icons/save.svg",
  iconCancelSrc: "https://example.com/icons/cancel.svg",
  iconEditSrc: "https://example.com/icons/edit.svg",
  
  // Custom card brand images
  cardBrandImages: {
    visaSrc: "https://example.com/brands/visa-logo.png",
    mastercardSrc: "https://example.com/brands/mastercard-logo.png",
    amexSrc: "https://example.com/brands/amex-logo.png",
    cupSrc: "https://example.com/brands/cup-logo.png",
    dinersSrc: "https://example.com/brands/diners-logo.png",
    discoverSrc: "https://example.com/brands/discover-logo.png",
    jcbSrc: "https://example.com/brands/jcb-logo.png"
  },
  
  useTransparentCardBrandImage: true,
  
  // Accessibility labels
  editCardInformationAriaLabel: "Edit card information button",
  saveCardInformationAriaLabel: "Save card information button",
  cancelEditCardInformationAriaLabel: "Cancel edit card information button",
  deleteCardButtonAriaLabel: "Delete card button",
  cardNumberAriaLabel: "Card number",
  cardExpiryDateAriaLabel: "Card expiry date",
  
  // Delete modal configuration
  deleteModal: {
    dialogAriaLabel: "Delete card dialog",
    bodyText: "Are you sure you want to delete this payment method?",
    cancelButtonText: "No, keep it",
    deleteButtonText: 'Yes, delete it',
    class: "custom-modal-class"
  },
  
  // Message styling
  successMessageClass: "alert alert-success",
  errorMessageClass: "alert alert-danger"
});
PropertyDescription
styles
CSSProperties
Custom styling for the component container. Defaults to null.
inputStyles
CSSProperties
Custom input styles. Defaults to null.
tokenItemClass
string
Custom class for the token item. Defaults to null.
cardBrandImages
object
Details about the card brand images. Defaults to null.
cardBrandImages.visaSrc
string
The URL for the Visa card brand image. Defaults to null.
cardBrandImages.mastercardSrc
string
The URL for the Mastercard card brand image. Defaults to null.
cardBrandImages.amexSrc
string
The URL for the Amex card brand image. Defaults to null.
cardBrandImages.cupSrc
string
The URL for the CUP card brand image. Defaults to null.
cardBrandImages.dinersSrc
string
The URL for the Diners card brand image. Defaults to null.
cardBrandImages.discoverSrc
string
The URL for the Discover card brand image. Defaults to null.
cardBrandImages.jcbSrc
string
The URL for the JCB card brand image. Defaults to null.
iconDeleteSrc
string
The URL for your custom delete icon. Defaults to null.
iconSaveSrc
string
The URL for your custom save icon. Defaults to null.
iconCancelSrc
string
The URL for your custom cancel icon. Defaults to null.
iconEditSrc
string
The URL for your custom edit icon. Defaults to null.
useTransparentCardBrandImage
boolean
Whether to use transparent card brand images. Defaults to true.
expiredText
string
The text to display for expired cards. Defaults to "Expired".
validThruText
string
The text to display for the "valid thru" label. Defaults to "Valid thru".
deleteModal
object
Configuration for the deletion modal. Defaults to null.
deleteModal.dialogAriaLabel
string
The aria label for the deletion modal. Defaults to null.
deleteModal.bodyText
string
The body text for the deletion modal. Defaults to null.
deleteModal.cancelButtonText
string
The cancel button text for the deletion modal. Defaults to null.
deleteModal.deleteButtonText
string
The delete button text for the deletion modal. Defaults to null.
deleteModal.class
string
The name of the class associated with the deletion modal. Defaults to null.
deleteErrorMessage
string
The error message to display when a card deletion fails. Defaults to null.
deleteSuccessMessage
string
The success message to display when a card deletion is successful. Defaults to null.
updateErrorMessage
string
The error message to display when a card update fails. Defaults to null.
updateSuccessMessage
string
The success message to display when a card update is successful. Defaults to null.
successMessageClass
string
The name of the CSS class to apply to success messages. Defaults to null.
errorMessageClass
string
The name of the CSS class to apply to error messages. Defaults to null.
editCardInformationAriaLabel
string
The aria label for the edit card information button. Defaults to null.
saveCardInformationAriaLabel
string
The aria label for the save card information button. Defaults to null.
cancelEditCardInformationAriaLabel
string
The aria label for the cancel edit information button. Defaults to null.
deleteCardButtonAriaLabel
string
The aria label for the delete card button. Defaults to null.
cardNumberAriaLabel
string
The aria label for the card number. Defaults to null.
cardExpiryDateAriaLabel
string
The aria label for the card expiry date. Defaults to null.

Event handling

The card-on-file component provides event handlers to manage token retrieval, rendering, updates, and deletions:

const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  onPreRenderTokens: (data: RetrieveCardTokensReponseSuccess) => {
    // Filter tokens before rendering
    return data.gatewayTokens
      .filter(token => token.issuerCountryCode === 'USA')
      .map(token => ({
        id: token.gatewayTokenId,
        isCvcRequired: true
      }));
  },
  
  onRetrieveTokensFailed: (data: RetrieveCardTokensReponseFailed) => {
    console.error('Failed to retrieve tokens:', data.errorMessage);
    showErrorMessage('Unable to load saved cards');
  },
  
  onSelectToken: (token: BaseCardToken) => {
    console.log('Token selected:', token);
    console.log('Selected card:', token.maskedPrimaryAccountNumber);
  },
  
  onPreDeleteToken: (token: BaseCardToken) => {
    return new Promise((resolve) => {
      const confirmed = confirm(
        `Are you sure you want to delete card ending in ${token.maskedPrimaryAccountNumber.slice(-4)}?`
      );
      resolve(confirmed);
    });
  },
  
  onDeleteTokenSuccess: (data: DeleteCardTokenResponseSuccess) => {
    console.log('Token deleted successfully:', data);
    showSuccessMessage('Card removed successfully');
    refreshTokenList();
  },
  
  onDeleteTokenFailed: (data: DeleteCardTokenResponseFailed) => {
    console.error('Delete failed:', data);
    showErrorMessage('Failed to delete card. Please try again.');
  },
  
  onUpdateTokenSuccess: (data: UpdateCardTokenResponseSuccess) => {
    console.log('Token updated successfully:', data);
    showSuccessMessage('Card information updated');
  },
  
  onUpdateTokenFailed: (data: UpdateCardTokenResponseFailed) => {
    console.error('Update failed:', data);
    showErrorMessage('Failed to update card information');
  },
  
  tokenItemBuilder: (elementIds: TokenBuilderElementIds) => {
    return `
      <div class="custom-token-layout">
        <div id="${elementIds.tokenImageId}"></div>
        <div id="${elementIds.tokenLabelId}"></div>
        <div id="${elementIds.editButtonId}"></div>
        <div id="${elementIds.deleteButtonId}"></div>
      </div>
    `;
  },
  
  tokenLabelBuilder: (token: BaseCardToken) => {
    return `${token.maskedPrimaryAccountNumber} - ${token.issuerName}`;
  }
});
CallbackDescription
onPreRenderTokens: (data: RetrieveCardTokensReponseSuccess) => CardTokenMapping[]Event handler for pre-processing tokens before rendering. Allows custom filtering and mapping of token data.
onRetrieveTokensFailed: (data: RetrieveCardTokensReponseFailed) => voidEvent handler for when token retrieval from the API fails.
onSelectToken: (token: BaseCardToken) => voidEvent handler triggered when a token is selected by the user.
onPreDeleteToken: (token: BaseCardToken) => Promise<boolean>Event handler for before token deletion. Return true to proceed, false to cancel.
onDeleteTokenSuccess: (data: DeleteCardTokenResponseSuccess) => voidEvent handler for after a token is successfully deleted.
onDeleteTokenFailed: (data: DeleteCardTokenResponseFailed) => voidEvent handler for when token deletion fails.
onUpdateTokenSuccess: (data: UpdateCardTokenResponseSuccess) => voidEvent handler for after a token is successfully updated.
onUpdateTokenFailed: (data: UpdateCardTokenResponseFailed) => voidEvent handler for when a token update fails.
tokenItemBuilder: (elementIds: TokenBuilderElementIds) => stringCustom HTML builder for token item layout. Returns an HTML string with specific element IDs.
tokenLabelBuilder: (token: BaseCardToken) => stringCustom label builder for token display text.

For more information about event data structures and usage patterns, see Events.

Methods

The card-on-file component provides methods for lifecycle management:

mount(containerId)

Mounts the component to the DOM:

cardOnFileComponent.mount('card-on-file-container');

Parameters:

  • containerId (string) - The ID of the container element

unmount()

Removes the component from the DOM and cleans up resources:

cardOnFileComponent.unmount();

Examples

Basic saved cards display

A straightforward implementation showing saved payment methods:

const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  limitTokens: 5,
  filterBy: {
    excludeExpiredTokens: true
  },
  
  onSelectToken: (token) => {
    console.log('Card selected:', token.maskedPrimaryAccountNumber);
  },
  
  onRetrieveTokensFailed: (error) => {
    console.error('Failed to load cards:', error);
    showErrorMessage('Unable to load saved cards');
  }
});

cardOnFileComponent.mount('card-on-file-container');

Filtered and sorted cards

Display only specific card types in a custom order:

const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  // Show only Visa and Mastercard credit cards
  filterBy: {
    excludeExpiredTokens: true,
    schemes: ["Visa", "Mastercard"],
    fundingSource: "Credit",
    issuerCountryCode: "USA"
  },
  
  // Sort by most recently used
  orderBy: {
    lastUsageDate: { 
      direction: "desc",
      orderByField: "lastSuccessfulPurchaseDate",
      priority: 1
    },
    scheme: { 
      valuesOrder: ["Visa", "Mastercard"],
      priority: 2
    }
  },
  
  limitTokens: 3,
  
  onPreRenderTokens: (data) => {
    // Additional custom filtering if needed
    return data.gatewayTokens
      .filter(token => token.fundingSource === 'Credit')
      .map(token => ({
        id: token.gatewayTokenId,
        isCvcRequired: true
      }));
  }
});

cardOnFileComponent.mount('card-on-file-container');

Editable cards with CVC requirement

Allow users to edit and delete their saved cards:

const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  isExpiryDateEditable: true,
  isCvcRequired: true,
  allowDeleteToken: true,
  
  cvcComponentConfig: {
    required: true,
    label: "Security code",
    applyMask: true,
    showMaskToggle: true,
    labelPosition: "left",
    errorMessage: "Please enter a valid security code",
    inputStyles: {
      base: {
        color: "#333",
        fontSize: "16px"
      }
    }
  },
  
  expiryDateComponentConfig: {
    label: "Expiry date",
    labelPosition: "left",
    formatOptions: "MM/YY",
    inputStyles: {
      base: {
        color: "#333",
        fontSize: "16px"
      }
    }
  },
  
  onSelectToken: (token) => {
    console.log('Card selected:', token);
    // Validate CVC when card is selected
  },
  
  onPreDeleteToken: (token) => {
    return new Promise((resolve) => {
      const confirmed = confirm(
        `Delete card ending in ${token.maskedPrimaryAccountNumber.slice(-4)}?`
      );
      resolve(confirmed);
    });
  },
  
  onDeleteTokenSuccess: (data) => {
    showSuccessMessage('Card deleted successfully');
  },
  
  onDeleteTokenFailed: (error) => {
    showErrorMessage('Failed to delete card');
  },
  
  onUpdateTokenSuccess: (data) => {
    showSuccessMessage('Card updated successfully');
  },
  
  onUpdateTokenFailed: (error) => {
    showErrorMessage('Failed to update card');
  }
});

cardOnFileComponent.mount('card-on-file-container');

Custom styled cards with branding

Fully customised appearance with branded images and styles:

const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  limitTokens: 5,
  filterBy: {
    excludeExpiredTokens: true
  },
  
  // Custom card brand images
  cardBrandImages: {
    visaSrc: "https://example.com/images/visa-logo.png",
    mastercardSrc: "https://example.com/images/mastercard-logo.png",
    amexSrc: "https://example.com/images/amex-logo.png"
  },
  
  // Custom text labels
  expiredText: "Card expired",
  validThruText: "Valid until",
  deleteSuccessMessage: "Payment method removed",
  updateSuccessMessage: "Card details updated",
  
  // Custom styling
  styles: {
    backgroundColor: '#f8f9fa',
    border: '1px solid #dee2e6',
    borderRadius: '8px',
    padding: '20px'
  },
  
  inputStyles: {
    borderRadius: '5px',
    backgroundColor: '#ffffff'
  },
  
  tokenItemClass: "custom-payment-card",
  
  // Custom icons
  iconDeleteSrc: "https://example.com/icons/delete.svg",
  iconEditSrc: "https://example.com/icons/edit.svg",
  iconSaveSrc: "https://example.com/icons/save.svg",
  iconCancelSrc: "https://example.com/icons/cancel.svg",
  
  useTransparentCardBrandImage: true,
  
  // Custom delete modal
  deleteModal: {
    dialogAriaLabel: "Delete payment method",
    bodyText: "Are you sure you want to remove this payment method?",
    cancelButtonText: "No, keep it",
    deleteButtonText: 'Yes, remove it',
    class: "custom-delete-modal"
  },
  
  successMessageClass: "alert alert-success",
  errorMessageClass: "alert alert-danger",
  
  // Accessibility
  editCardInformationAriaLabel: "Edit payment method",
  saveCardInformationAriaLabel: "Save changes",
  cancelEditCardInformationAriaLabel: "Cancel editing",
  deleteCardButtonAriaLabel: "Remove payment method",
  
  onSelectToken: (token) => {
    console.log('Selected:', token.maskedPrimaryAccountNumber);
  }
});

cardOnFileComponent.mount('card-on-file-container');

Custom token layout

Use custom HTML builders to create a unique token display:

const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  tokenItemBuilder: (elementIds) => {
    return `
      <div class="payment-card-item">
        <div class="card-header">
          <div id="${elementIds.tokenImageId}" class="brand-logo"></div>
          <div id="${elementIds.tokenLabelId}" class="card-info"></div>
        </div>
        <div class="card-actions">
          <div id="${elementIds.editButtonId}" class="edit-btn"></div>
          <div id="${elementIds.deleteButtonId}" class="delete-btn"></div>
        </div>
      </div>
    `;
  },
  
  tokenLabelBuilder: (token) => {
    const lastFour = token.maskedPrimaryAccountNumber.slice(-4);
    const expiryDate = token.expiryDate;
    return `
      <div>
        <strong>${token.scheme}</strong> •••• ${lastFour}
        <br>
        <small>Expires ${expiryDate}</small>
      </div>
    `;
  },
  
  onSelectToken: (token) => {
    console.log('Selected token:', token);
  }
});

cardOnFileComponent.mount('card-on-file-container');

Enterprise implementation with all features

A comprehensive implementation with filtering, sorting, editing, and complete event handling:

const cardOnFileComponent = pxpCheckout.create('card-on-file', {
  // Filtering and limiting
  limitTokens: 10,
  filterBy: {
    excludeExpiredTokens: true,
    schemes: ["Visa", "Mastercard", "Amex"],
    fundingSource: "Credit"
  },
  
  // Multi-level sorting
  orderBy: {
    lastUsageDate: { 
      direction: "desc",
      orderByField: "lastSuccessfulPurchaseDate",
      priority: 1
    },
    expiryDate: { 
      direction: "asc",
      priority: 2
    },
    scheme: { 
      valuesOrder: ["Visa", "Mastercard", "Amex"],
      priority: 3
    }
  },
  
  // Feature flags
  isExpiryDateEditable: true,
  isCvcRequired: true,
  allowDeleteToken: true,
  
  // Nested component configuration
  cvcComponentConfig: {
    required: true,
    label: "CVV/CVC",
    applyMask: true,
    showMaskToggle: true,
    labelPosition: "left",
    inputStyles: {
      base: { fontSize: "16px", color: "#333" }
    }
  },
  
  expiryDateComponentConfig: {
    label: "Expiry",
    formatOptions: "MM/YY",
    labelPosition: "left",
    inputStyles: {
      base: { fontSize: "16px", color: "#333" }
    }
  },
  
  // Comprehensive event handling
  onPreRenderTokens: (data) => {
    console.log('Retrieved tokens:', data.gatewayTokens.length);
    
    // Apply business logic filtering
    return data.gatewayTokens
      .filter(token => {
        // Only show cards from specific issuers
        return ['USA', 'CAN', 'GBR'].includes(token.issuerCountryCode);
      })
      .map(token => ({
        id: token.gatewayTokenId,
        isCvcRequired: token.scheme !== 'Amex' // Amex doesn't require CVC
      }));
  },
  
  onRetrieveTokensFailed: (error) => {
    console.error('Token retrieval failed:', error);
    logErrorToService(error);
    showUserMessage('Unable to load payment methods', 'error');
  },
  
  onSelectToken: (token) => {
    console.log('Token selected:', token);
    trackAnalyticsEvent('payment_method_selected', {
      scheme: token.scheme,
      fundingSource: token.fundingSource
    });
  },
  
  onPreDeleteToken: async (token) => {
    const lastFour = token.maskedPrimaryAccountNumber.slice(-4);
    const confirmed = await showCustomConfirmDialog({
      title: 'Remove Payment Method',
      message: `Remove card ending in ${lastFour}?`,
      confirmText: 'Remove',
      cancelText: 'Keep'
    });
    return confirmed;
  },
  
  onDeleteTokenSuccess: (data) => {
    console.log('Token deleted:', data);
    showUserMessage('Payment method removed', 'success');
    trackAnalyticsEvent('payment_method_deleted');
    refreshPaymentMethods();
  },
  
  onDeleteTokenFailed: (error) => {
    console.error('Delete failed:', error);
    showUserMessage('Unable to remove payment method', 'error');
    logErrorToService(error);
  },
  
  onUpdateTokenSuccess: (data) => {
    console.log('Token updated:', data);
    showUserMessage('Payment method updated', 'success');
    trackAnalyticsEvent('payment_method_updated');
  },
  
  onUpdateTokenFailed: (error) => {
    console.error('Update failed:', error);
    showUserMessage('Unable to update payment method', 'error');
    logErrorToService(error);
  },
  
  // Custom styling
  styles: {
    backgroundColor: '#ffffff',
    border: '1px solid #e5e7eb',
    borderRadius: '12px',
    padding: '24px',
    boxShadow: '0 1px 3px rgba(0,0,0,0.1)'
  },
  
  cardBrandImages: {
    visaSrc: "https://cdn.example.com/brands/visa.svg",
    mastercardSrc: "https://cdn.example.com/brands/mastercard.svg",
    amexSrc: "https://cdn.example.com/brands/amex.svg"
  },
  
  deleteModal: {
    dialogAriaLabel: "Remove payment method confirmation",
    bodyText: "This payment method will be permanently removed.",
    cancelButtonText: "Cancel",
    deleteButtonText: 'Remove',
    class: "enterprise-delete-modal"
  },
  
  successMessageClass: "toast toast-success",
  errorMessageClass: "toast toast-error"
});

cardOnFileComponent.mount('payment-methods-container');

For more information about integration and events, see Events and Data validation.