Events

Implement callbacks to customise your payment flow.

Overview

Components emit events based on user interaction or validation. You can use these to implement callback functions, which allow you to inject your own business logic and user experience customisations into the payment flow at critical moments. They ensure that while the SDK handles the complex technical aspects of payment processing, you retain full control over the customer experience and can seamlessly integrate payments into your broader business workflows and systems.

Callbacks enable you to:

  • Validate business rules before payments proceed.
  • Display custom error, failure, or success messages.
  • Tailor user interfaces to match your brand's look and feel.
  • Integrate with your own systems for fraud detection or customer management.
  • Control exactly how your customers experience both successful and failed transactions.

All events are optional and can be mixed and matched based on your business needs.

Supported events

The following tables lists all events supported by the different pre-built components.

Event

Billing address

Card-on-file

Click-once

New card

onBlur

onCardBrandCannotRecognised

onCardBrandDetected

onChange

onClick

onCollectEnd

onCollectStart

onCvcEntered

onDeleteTokenFailed

onDeleteTokenSuccess

onFocus

onGetFingerprintResult

onOnceCardClick

onPostAuthentication

onPostAuthorisation

onPostInitiateAuthentication

onPostTokenisation

onPreAuthentication

onPreAuthorisation

onPreDeleteToken

onPreInitiateAuthentication

onPreRenderTokens

onPreTokenisation

onRetrieveTokensFailed

onSubmitError

onUpdateTokenFailed

onUpdateTokenSuccess

onValidation

onValidationPassed

onValidationFailed

tokenItemBuilder

tokenLabelBuilder

Callbacks

onBlur

This callback is triggered when the input loses focus.

const component = sdk.create('card-number', {
  onBlur: (event) => {
    console.log('Field blurred:', event.target.value);
  }
});

onCardBrandCannotRecognised

This callback is triggered when the card number input changes, but the entered digits don't match any known card brand patterns.

const cardNumberComponent = sdk.create('card-number', {
  onCardBrandCannotRecognised: (event) => {
    console.log('Card brand could not be recognised');
    // Handle unknown card brand scenario
  }
});

onCardBrandDetected

This callback is triggered when the card number input changes and a recognised card brand (e.g., Visa, MasterCard) is detected from the input value.

const cardNumberComponent = sdk.create('card-number', {
  onCardBrandDetected: (event) => {
    const cardBrand = event.detail.cardBrand;
    const isAccepted = event.detail.isCardBrandAccept;
    console.log(`Card brand detected: ${cardBrand.brand}`, isAccepted);
  }
});

onChange

This callback is triggered when the input value change in one or more fields.

const component = sdk.create('card-number', {
  onChange: (event) => {
    console.log('Value changed:', event.target.value);
  }
});

onClick

This callback is triggered when the submit button is clicked (before processing).

const cardSubmit = sdk.create('card-submit', {
    onClick: (event) => {
        console.log('Submit button clicked');
    }
});

onCollectEnd

This callback is triggered when data collection ends.

const cardSubmit = sdk.create('card-submit', {
  onCollectEnd: (data) => {
    console.log('Data collection completed:', data);
    hideMessage();
  }
});

onCollectStart

This callback is triggered when data collection begins.

const cardSubmit = sdk.create('card-submit', {
  onCollectStart: (data) => {
    console.log('Data collection started:', data);
    showMessage('Collecting device information...', 'info');
  }
});

onCvcEntered

This callback is triggered when a customer enters a CVC value in the click-once component's CVC field.

const clickOnceComponent = sdk.create('click-once', {
  onCvcEntered: () => {
    console.log('CVC has been entered');
    // Enable submit button or perform validation
  }
});

onDeleteTokenFailed

This callback is triggered when a card token deletion request fails, for example due to a network error.

const cardOnFileComponent = sdk.create('card-on-file', {
  onDeleteTokenFailed: (data) => {
    console.log('Token deletion failed:', data.error);
    alert('Failed to delete card. Please try again.');
  }
});

onDeleteTokenSuccess

This callback is triggered when a card token is successfully deleted from the vault.

const cardOnFileComponent = sdk.create('card-on-file', {
  onDeleteTokenSuccess: (data) => {
    console.log('Token deleted successfully:', data.tokenId);
    // Refresh the token list or show success message
  }
});

onFocus

This callback is triggered when the input receives focus.

const component = sdk.create('card-number', {
  onFocus: (event) => {
    console.log('Field focused');
  }
});

onGetFingerPrintResult

This callback is used to retrieve fingerprint data for authentication.

const cardSubmit = sdk.create('card-submit', {
  onGetFingerprintResult: async () => {
    // Return fingerprint data as a string
    return await getDeviceFingerprintData();
  }
});

onOnceCardClick

This callback is triggered when a customer selects a saved card in the click-once component.

const clickOnceComponent = sdk.create('click-once', {
  onOnceCardClick: () => {
    console.log('User clicked on a saved card');
    // Handle card selection logic
  }
});

onPostAuthentication

This callback is triggered after 3DS authentication is completed.

const cardSubmit = sdk.create('card-submit', {
  onPostAuthentication: (authResult) => {
    console.log('3DS authentication completed:', authResult);
    if (authResult.status === 'AUTHENTICATED') {
      showMessage('Authentication successful', 'success');
    }
  }
});

onPostAuthorisation

This callback is triggered after a payment transaction has been processed and authorisation has been completed (successfully or unsuccessfully).

const cardSubmit = sdk.create('card-submit', {
  onPostAuthorisation: (result) => {
    if (result.state === 'Authorised') {
      // Payment successful
      alert('Payment successful!');
      window.location.href = '/success';
    } else {
      // Payment failed
      alert('Payment failed. Please try again.');
    }
  }
});

onPostInitiateAuthentication

This callback is triggered after 3DS authentication is initiated.

const cardSubmit = sdk.create('card-submit', {
  onPostInitiateAuthentication: (authResult) => {
    console.log('3DS authentication initiated:', authResult);
    if (authResult.status === 'CHALLENGE_REQUIRED') {
      showMessage('Please complete 3DS verification', 'info');
    }
  }
});

onPostTokenisation

This callback is triggered after tokenisation completes with the tokenisation result.

const cardSubmit = sdk.create('card-submit', {
  onPostTokenisation: (tokenData) => {
    console.log('Card tokenised:', tokenData);
  }
});

onPreAuthentication

This callback is triggered before 3DS authentication starts.

const cardSubmit = sdk.create('card-submit', {
  onPreAuthentication: async (preInitData) => {
    console.log('Starting 3DS authentication:', preInitData);
    return {
      acquirerProfileId: "your-acquirer-id",
      providerId: "your-provider-id",
      timeout: 30
    };
  }
});

onPreAuthorisation

This callback is triggered before the transaction authorisation. Return the transaction data.

const cardSubmit = sdk.create('card-submit', {
  onPreAuthorisation: (data) => {
    console.log('Pre-authorisation data:', data);
    return Promise.resolve({
      addressVerification: {
        countryCode: "US",
        houseNumberOrName: "123 Main St",
        postalCode: "12345"
      }
    });
  }
});

onPreDeleteToken

This callback is triggered before a token deletion attempt, allowing you to show custom confirmation dialogs.

const cardOnFileComponent = sdk.create('card-on-file', {
  onPreDeleteToken: async (token) => {
    const confirmed = confirm(`Delete card ending in ${token.maskedPrimaryAccountNumber.slice(-4)}?`);
    return confirmed; // Return true to proceed, false to cancel
  }
});

onPreInitiateAuthentication

This callback is triggered before 3DS authentication. Return the authorisation data if you want to proceed with pre-initiating an authentication, null otherwise.

const cardSubmit = sdk.create('card-submit', {
  onPreInitiateAuthentication: () => {
    return {
      threeDSecureVersion: "2.1.0",
      merchantName: "Your Store"
    };
  }
});

onPreTokenisation

This callback is triggered before card tokenisation. To proceed, return true. To cancel, return false.

const cardSubmit = sdk.create('card-submit', {
  onPreTokenisation: () => {
    console.log('About to tokenise card');
      return true; // or false to cancel
  }
});

onPreRenderTokens

This callback is triggered after tokens are retrieved but before they're rendered, allowing filtering and transformation.

const cardOnFileComponent = sdk.create('card-on-file', {
  onPreRenderTokens: (data) => {
    // Filter only Visa cards and mark them as requiring CVC
    return data.gatewayTokens
      .filter(token => token.scheme === 'Visa')
      .map(token => ({
        id: token.gatewayTokenId,
        isCvcRequired: true
      }));
  }
});

onRetrieveTokensFailed

This callback is triggered when the initial request to fetch saved card tokens fails.

const cardOnFileComponent = sdk.create('card-on-file', {
  onRetrieveTokensFailed: (data) => {
    console.log('Failed to retrieve tokens:', data.error);
    // Show fallback UI or error message
  }
});

onSubmitError

This callback is triggered when submission fails.

const cardSubmit = sdk.create('card-submit', {
  onSubmitError: (error) => {
    console.log('Submit error:', error);
  }
});

onUpdateTokenFailed

This callback is triggered when updating card token information (e.g., expiry date) fails.

const cardOnFileComponent = sdk.create('card-on-file', {
  onUpdateTokenFailed: (data) => {
    console.log('Token update failed:', data.error);
    // Show error message to user
  }
});

onUpdateTokenSuccess

This callback is triggered when card token information is successfully updated.

const cardOnFileComponent = sdk.create('card-on-file', {
  onUpdateTokenSuccess: (data) => {
    console.log('Token updated successfully:', data);
    // Refresh display with new information
  }
});

onValidation

This callback is triggered when form validation occurs.

const newCard = sdk.create('new-card', {
  onValidation: (validationResults) => {
    console.log('Card form validation:', validationResults);
    validationResults.forEach(result => {
      if (!result.valid && result.errors) {
        Object.keys(result.errors).forEach(fieldName => {
          const error = result.errors[fieldName];
          console.log(`${fieldName}: ${error.message} (${error.code})`);
        });
      }
    });
  }
});

onValidationFailed

This callback is triggered when validation fails for a single field.

const component = sdk.create('card-number', {
  onValidationFailed: (validationResults) => {
    console.log('Validation failed:', validationResults);
  }
});

onValidationPassed

This callback is triggered when validation is successful for a single field.

const component = sdk.create('card-number', {
  onValidationPassed: (validationResults) => {
    console.log('Validation passed:', validationResults);
  }
});

tokenItemBuilder

This callback is called when each token item's user interface is being constructed, allowing you to customise the HTML layout.

const cardOnFileComponent = sdk.create('card-on-file', {
  tokenItemBuilder: (elementIds) => {
    return `
      <div style="display: flex; align-items: center; padding: 10px;">
        <div id="${elementIds.tokenImageId}"></div>
        <div id="${elementIds.tokenLabelId}" style="flex: 1; margin: 0 10px;"></div>
        <div id="${elementIds.expiryDateId}" style="margin-right: 10px;"></div>
        <div id="${elementIds.editButtonId}" style="margin-right: 5px;"></div>
        <div id="${elementIds.deleteButtonId}"></div>
      </div>
    `;
  }
});

tokenLabelBuilder

This callback is called to generate the display text for each card token. It replaces the default masked card number.

const cardOnFileComponent = sdk.create('card-on-file', {
  tokenLabelBuilder: (token) => {
    return `${token.scheme} •••• ${token.maskedPrimaryAccountNumber.slice(-4)} - ${token.issuerName}`;
  }
});

Common scenarios

Handle a declined transaction

The following snippet is an example of how you might handle a declined transaction when using the card submit component.

const cardSubmitComponent = sdk.create('card-submit', {
  onPostAuthorisation: (submitResult) => {
    console.log('Transaction result:', submitResult);
    
    if (submitResult.status === 'Refused') {
      // Transaction was declined by the issuer or payment provider
      const refusedResult = submitResult as RefusedSubmitResult;
      
      // Handle the declined transaction
      handleDeclinedTransaction(refusedResult);
      
    } else if (submitResult.status === 'Authorised') {
      // Transaction was successful
      handleSuccessfulTransaction(submitResult);
      
    } else if (submitResult.status === 'Error') {
      // System error occurred
      handleSystemError(submitResult);
      
    } else if (submitResult.status === 'Pending') {
      // Transaction is pending further processing
      handlePendingTransaction(submitResult);
    }
  }
});

function handleDeclinedTransaction(refusedResult) {
  // Extract decline information
  const stateData = refusedResult.stateData;
  const providerResponse = refusedResult.providerResponse;
  const fundingData = refusedResult.fundingData;
  
  // Log decline details
  console.log('Transaction declined:', {
    stateCode: stateData?.code,
    stateMessage: stateData?.message,
    providerCode: providerResponse?.code,
    providerMessage: providerResponse?.message,
    merchantAdvice: providerResponse?.merchantAdvice
  });
  
  // Show user-friendly error message based on decline reason
  const declineCode = providerResponse?.code;
  let userMessage = 'Your payment was declined. Please try again or use a different payment method.';
  
  switch (declineCode) {
    case 'INSUFFICIENT_FUNDS':
      userMessage = 'Your card has insufficient funds. Please try a different payment method.';
      break;
    case 'EXPIRED_CARD':
      userMessage = 'Your card has expired. Please check your card details or use a different card.';
      break;
    case 'INVALID_CVV':
      userMessage = 'The security code (CVV) is incorrect. Please check and try again.';
      break;
    case 'CARD_BLOCKED':
      userMessage = 'Your card is blocked. Please contact your bank or use a different payment method.';
      break;
    case 'LIMIT_EXCEEDED':
      userMessage = 'Transaction exceeds your card limit. Please try a smaller amount or different card.';
      break;
    default:
      // Use merchant advice if available
      if (providerResponse?.merchantAdvice?.message) {
        userMessage = providerResponse.merchantAdvice.message;
      }
  }
  
  // Display error to user
  showErrorMessage(userMessage);
  
  // Check if retry is recommended
  if (providerResponse?.merchantAdvice?.code === 'RETRY') {
    enableRetryOption();
  } else if (providerResponse?.merchantAdvice?.code === 'DO_NOT_RETRY') {
    disableRetryOption();
    suggestAlternativePayment();
  }
  
  // Log analytics event for declined transaction
  logDeclineAnalytics(declineCode, stateData?.code);
}

Handle an authentication failure

The following snippet is an example of how you might handle authentication problems when using the card submit component.

const cardSubmitComponent = sdk.create('card-submit', {
  onSubmitError: (error) => {
    console.log('Submit error occurred:', error);
    
    // Handle different types of authentication and processing errors
    switch (error.ErrorCode) {
      case 'SDK0503': // Transaction authentication rejected
        showErrorMessage('Authentication was rejected by your bank. Please try again or contact your bank.');
        enableRetryOption();
        break;
        
      case 'SDK0505': // Transaction authentication failed
        showErrorMessage('Authentication failed. Please try again or contact your bank for assistance.');
        enableRetryOption();
        break;
        
      case 'SDK0504': // SCA exemption required
        showErrorMessage('Additional authentication is required. Please complete the verification process.');
        // Handle SCA exemption flow
        break;
        
      default:
        // Generic error handling
        showErrorMessage('Payment processing failed. Please try again.');
        logError(error);
    }
  }
});