Skip to main content

Tokenize Payment Method

Overview

Component to render an entire form including a switch to use a credit card or bank account, a submit button and all fields required for proper use. This component can be used standalone or as part of the modular checkout system.

Props, Events & Methods

NameTypeRequiredDefaultDescription
account-idstringNo
auth-tokenstringNo
disable-bank-accountbooleanNo
disable-credit-cardbooleanNo
hide-bank-account-billing-formbooleanNo
hide-card-billing-formbooleanNo
hide-submit-buttonbooleanNo
payment-method-group-idstringNo
save-payment-method-labelstringNo
submit-button-textstringNo'Submit'

Events

  • submit-event: fires when a payment token is created; payload includes payment_method_token and metadata.
  • error-event: fires if tokenization fails; payload includes code, message, and validation hints.

Public methods

  1. tokenizePaymentMethod() – programmatically trigger submission (returns a promise that resolves to a token payload).
  2. fillBillingForm(partialBillingDetails) – prefill customers' billing information from saved data.
  3. validate() – validate the form fields and return validation result.

Authorization


Authorization is performed by passing a web component token as auth-token.

  • Web Component Token: These tokens are generated by your backend services using the Web Component Tokens API. Each token can be scoped to perform a set number of actions and is active for 60 minutes. When creating a web component token for this specific component you'll need to use the role: write:tokenize:account_id. Make sure the value for account_id matches the prop you also pass separately.

Security


The api endpoint associated with this component has the following security measures in place:

  1. Rate Limiting: POST requests to are limited to 2 requests per 10 seconds.
  2. Token-based Request Limiting: POST requests using web component token authentication are limited to 10 attempts per token.

These measures are in place to prevent abuse and ensure the security of the payment processing system.

Note: While client-id is still supported, we now recommend using web component tokens (auth-token) for enhanced security and flexibility.

Usage Patterns


Standalone Usage

When used standalone, the component provides its own submit button and handles all tokenization internally:

<justifi-tokenize-payment-method
account-id="acc_123"
auth-token="authToken"
payment-method-group-id="pmg_123"
/>

External Control

Hide the built-in submit button and control tokenization externally:

<justifi-tokenize-payment-method
account-id="acc_123"
auth-token="authToken"
hide-submit-button="true"
/>

<button id="external-submit">Submit Payment</button>

<script>
const tokenizer = document.querySelector('justifi-tokenize-payment-method');
const submitBtn = document.getElementById('external-submit');

submitBtn.addEventListener('click', async () => {
await tokenizer.tokenizePaymentMethod();
});
</script>

Pre-filling Billing Information

You can programmatically fill the billing form:

const tokenizer = document.querySelector('justifi-tokenize-payment-method');

tokenizer.fillBillingForm({
name: 'John Doe',
address_line1: '123 Main St',
address_city: 'Anytown',
address_state: 'NY',
address_postal_code: '12345',
});

Integration with Modular Checkout


When used within the justifi-modular-checkout wrapper component, this component automatically adapts its behavior:

  • Auto-detection: The component automatically detects if it's slotted within a modular checkout
  • Submit button hiding: The submit button is automatically hidden when inside modular checkout
  • Shared authentication: Uses authentication tokens from the parent modular checkout component
  • Coordinated validation: Validation is coordinated by the modular checkout wrapper
<justifi-modular-checkout
auth-token="authToken"
account-id="acc_123"
checkout-id="cho_123"
>
<justifi-tokenize-payment-method />
<!-- Other modular checkout components -->
</justifi-modular-checkout>

Example Usage



<!DOCTYPE html>
<html dir="ltr" lang="en">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0" />
<title>justifi-tokenize-payment-method</title>

<script type="module" src="https://cdn.jsdelivr.net/npm/@justifi/webcomponents@6.7.3/dist/webcomponents/webcomponents.esm.js"></script>

<script
nomodule
src="https://cdn.jsdelivr.net/npm/@justifi/webcomponents@6.7.3/dist/webcomponents/webcomponents.js"
></script>

<style>
  ::part(font-family) {
    font-family: georgia;
  }

  ::part(color) {
    color: darkslategray;
  }

  ::part(background-color) {
    background-color: transparent;
  }

  ::part(button) {
    padding: 0.375rem 0.75rem;
    font-size: 16px;
    box-shadow: none;
    border-radius: 0px;
    line-height: 1.5;
    text-transform: none;
  }

  ::part(button-disabled) {
    opacity: 0.5;
  }

  ::part(input) {
    border-color: #555;
    border-width: 1px;
    border-bottom-width: 1px;
    border-left-width: 1px;
    border-right-width: 1px;
    border-top-width: 1px;
    border-radius: 0;
    border-style: solid;
    box-shadow: none;
    font-size: 1rem;
    font-weight: normal;
    line-height: 1.5;
    padding: 0.375rem 0.75rem;
  }

  ::part(input-focused) {
    border-color: #333;
    box-shadow: 0 0 0 0.25rem rgba(0, 0, 0, 0.25);
  }

  ::part(input-invalid) {
    border-color: #8a2a35;
    box-shadow: 0 0 0 0.25rem rgba(244, 67, 54, 0.25);
  }

  ::part(input-invalid-and-focused) {
    box-shadow: 0 0 0 0.25rem rgba(244, 67, 54, 0.25);
    border-color: #8a2a35;
  }

  ::part(input-radio) {
    background-color: #fff;
    border-color: #333;
  }

  ::part(input-checkbox) {
    border-color: #333;
  }
  
  ::part(input-checkbox-checked) {
    background-color: #000;
    border-color: #333;
  }

  ::part(input-checkbox-checked-focused) {
    background-color: #000;
    box-shadow: 0 0 0 0.25rem rgba(0, 0, 0, 0.25);
  }

  ::part(input-checkbox-focused) {
    background-color: #fff;
    box-shadow: 0 0 0 0.25rem rgba(0, 0, 0, 0.25);
  }

  ::part(button-primary) {
    color: #333;
    background-color: transparent;
    border-color: #333;
  }

  ::part(button-primary):hover {
    background-color: rgba(0, 0, 0, .05);
    border-color: #333;
    color: #333;
  }

  ::part(radio-list-item) {
    border-bottom: 1px solid #ddd;
  }
  
  ::part(radio-list-item):hover {
    background-color: #f9f9f9;
    cursor: pointer;
  }
  </style>

</head>

<body>
<justifi-tokenize-payment-method
  account-id="acc_123"
  auth-token="authToken"
  payment-method-group-id="pmg_123"
  submit-button-text="Tokenize Payment Method"
/>
</body>

<script>
  const justifiTokenizePaymentMethod = document.querySelector("justifi-tokenize-payment-method");

  // Handle successful tokenization
  justifiTokenizePaymentMethod.addEventListener("submit-event", (event) => {
    const response = event.detail.response;
    console.log("Tokenization successful:", response);
    
    if (response.token) {
      console.log("Payment method token:", response.token);
    }
    
    if (response.data) {
      console.log("Full payment method data:", response.data);
    }
  });

  // Handle errors
  justifiTokenizePaymentMethod.addEventListener("error-event", (event) => {
    console.error("Tokenization error:", event.detail);
  });

  // External tokenize button (when built-in submit button is hidden)
  document.getElementById("tokenize-button").addEventListener("click", async () => {
    try {
      const result = await justifiTokenizePaymentMethod.tokenizePaymentMethod();
      console.log("External tokenization result:", result);
    } catch (error) {
      console.error("External tokenization failed:", error);
    }
  });

  // Fill billing form programmatically
  document.getElementById("fill-billing-form").addEventListener("click", async () => {
    await justifiTokenizePaymentMethod.fillBillingForm({
      name: "John Doe",
      address_line1: "123 Main St",
      address_line2: "Apt 1",
      address_city: "Anytown",
      address_state: "NY", // Use 2-letter state code
      address_postal_code: "12345",
    });
    console.log("Billing form filled");
  }); 

  // Validate form
  document.getElementById("validate-form").addEventListener("click", async () => {
    const validation = await justifiTokenizePaymentMethod.validate();
    console.log("Validation result:", validation);
    
    if (validation.isValid) {
      console.log("Form is valid!");
    } else {
      console.log("Form has errors:", validation.errors);
    }
  });

</script>

</html>

Theming & Layout

PartDescriptionDOM target
::part(radioListItem)
::part(billingForm)