Unified Fintech Checkout™
Overview
Component to render the necessary fields to enter proper payment method information and process a payment.
You will need to first create a checkout via Checkout API to get the checkout-id required for this component.
Props, events and methods
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
auth-token | string | Yes | — | |
checkout-id | string | Yes | — | |
disable-bank-account | boolean | No | false | |
disable-bnpl | boolean | No | false | |
disable-credit-card | boolean | No | false | |
disable-payment-method-group | boolean | No | false | |
hide-bank-account-billing-form | boolean | No | false | |
hide-card-billing-form | boolean | No | false | |
preCompleteHook | (data: CheckoutState, resolve: (data: CheckoutState) => void, reject: () => void) => void | No | — |
Events
submit-event: Emits when payment succeeds; payload includes the server response.error-event: Fires if payment processing fails; includes error codes for analytics.loaded: Emits when the checkout form is fully loaded.
Public methods
fillBillingForm(fields)– Pre-fill the billing form with the provided fields (name, address, etc.).validate()– Validates all form fields and returns{ isValid: boolean }.
Pre-Complete Hook
You can provide a preCompleteHook function to inspect the checkout state before submission proceeds.
The hook runs after validation and payment method tokenization (including Plaid exchange when applicable), and before the checkout is completed, so the state includes the latest values such as paymentToken when available.
The hook receives three parameters:
state: ACheckoutStateobject containing the current checkout informationresolve: Call to proceed with submissionreject: Call to cancel submission
Example:
<justifi-checkout auth-token="123abc" checkout-id="chk_123"></justifi-checkout>
<script>
const checkout = document.querySelector('justifi-checkout');
checkout.preCompleteHook = (state, resolve, reject) => {
// For example, require confirmation for large payments
if (state.totalAmount > 100000) {
const confirmed = confirm(
`Confirm payment of $${(state.totalAmount / 100).toFixed(2)}?`
);
if (confirmed) {
resolve(state);
} else {
reject();
}
} else {
resolve(state);
}
};
</script>
Important: Assign the hook as a JavaScript property on the element (e.g.,
checkout.preCompleteHook = fn). Do not pass it as an HTML attribute (e.g.,pre-complete-hook="..."); functions must be set on properties, not attributes.
Payment methods
The Unified Checkout automatically displays additional payment method options when they are enabled in your account settings and when device/browser or other eligibility constraints are met:
- Apple Pay: Must be enabled in account settings. It renders automatically only on eligible devices/browsers; otherwise it will not appear.
- Sezzle (BNPL): Must be enabled in account settings. It displays automatically when available for the account.
- Plaid (Bank account verification): Must be enabled in account settings. It displays automatically when bank account payments with Plaid verification are enabled.
No extra component configuration is required beyond enabling these features on the account. When unavailable or ineligible, these options are simply not shown.
Authorization
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 following roles:
write:checkout:checkout_id- use thecheckout_idyou receive when you create a checkout via Checkout APIwrite:tokenize:account_id- use theaccount_idyou pass to the checkout API
Security
The api endpoint associated with this component has the following security measures in place:
- Rate Limiting: POST requests to are limited to 2 requests per 10 seconds.
- 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.
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-checkout</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-checkout
checkout-id="cho_123"
auth-token="authToken"
>
<!-- Optional: add the insurance slot and component -->
<div slot="insurance">
<!-- see the insurance component docs for the full list of props -->
<justifi-season-interruption-insurance checkout-id="abc123"></justifi-season-interruption-insurance>
</div>
</justifi-checkout>
<button id="fill-billing-form-button">Fill Billing Form</button>
</body>
<script>
(function () {
var checkoutForm = document.querySelector("justifi-checkout");
checkoutForm.addEventListener("submit-event", (event) => {
/* this event is raised when the server response is received */
console.log("server response received", event.detail.response);
});
checkoutForm.addEventListener("error-event", (event) => {
// here is where you would handle the error
console.error('error-event', event.detail);
});
// loaded event is raised when the form is fully loaded
checkoutForm.addEventListener("loaded", () => {
console.log("checkout form loaded");
});
// fill billing form button click event
document.getElementById("fill-billing-form-button").addEventListener("click", () => {
checkoutForm.fillBillingForm({
name: "John",
address_line1: "123 Main St",
address_line2: "Apt 1",
address_city: "Anytown",
address_state: "NY", // Use 2-letter state code
address_postal_code: "12345",
});
})();
</script>
</html>
Theming & Layout
| Part | Description | DOM target |
|---|---|---|
::part(checkoutSummary) | — | |
::part(text) | — | |
::part(radioListItem) | — | |
::part(billingForm) | — |