Hosted Fields
Quick Start
The Forter Hosted Fields SDK allows merchants to securely collect sensitive data directly from their frontend forms, alleviating the need to apply stricter measures of PCI compliance.
Form controls created using the Forter Hosted Fields SDK can be customized to blend in seamlessly with the merchant’s design language and styles.
After securely collecting the sensitive data, it is sent over an encrypted SSL connection to the Forter secure card data Vault, where it is tokenized, encrypted and stored for later use.
Installation and setup
- Copy and paste the following snippet into your checkout page:
<script type="text/javascript" data-site-id="XXXXXXX" id="checkoutTools__script" src="https://sdk.checkouttools.com/v1.2/collect.js"> </script>
- If you use CSP, please add the following CSP directives:
connect-src <https://sdk.checkouttools.com>
frame-src <https://sdk.checkouttools.com>
script-src <https://sdk.checkouttools.com>
- Initiate the SDK instance
const forterCollect = await window.checkoutTools.collect.init(
{
environment: 'sandbox',
authToken: 'TOKEN.VALUE'
}
);
And you’re good to go. Follow the API reference or one of the examples below to create your secure and customized payment form.
Authentication
Before using the Forter Hosted Fields SDK, you will need to generate a temporary auth token.
- Before rendering your checkout page, use the /client-key endpoint in the Tokenization API to receive a JWT authentication token.
- Pass this token to your frontend, and initialize the SDK using the
authToken
argument.
NOTE: When creating the token server-side, you are able to control its TTL. It is recommended to use the smallest TTL value necessary for the end-user to successfully complete the transaction in the frontend, in order to reduce the chance of abuse.
Creating and Updating fields
First, create “container” elements in your HTML form:
After configuring the SDK, within each container will be rendered a secure Hosted Field iframe. Make sure to set a meaningful id per each container element.
<form>
<label>
Name on card
<div id="card-holder-name"></div>
</label>
<label>
Card
<div id="card-full-pan"></div>
</label>
<label>
CVC
<div id="card-cvc"></div>
</label>
<label>
Expiration date
<div id="card-expiration"></div>
</label>
<label>
Example text field
<div id="text-field"></div>
</label>
</form>
Calling forterCollect.addFields
will render the Hosted Fields iframes. Each HTML container element in the form will be assigned with a specific behavior and configuration:
In this example we are adding a field with id card-full-pan
of type CARD_NUMBER
.
forterCollect.addFields({
"card-full-pan": {
type: "CARD_NUMBER"
});
Note: In order to successfully tokenize payment details, fields of type CARD_NUMBER
, CARD_HOLDER_NAME
and CARD_EXPIRATION_DATE
must all be added.
Note: Field ids must be unique in the scope of a single SDK initialization, and must match the ids given to their respective HTML elements described earlier.
Hosted fields can also be updated dynamically using the updateFields
method:
Note: The type configuration option can not be updated using this method.
forterCollect.updateFields({
"card-cvc": {
visible: false
});
Waiting until the form is ready
While the addFields
method is working, the Hosted Fields UI will be briefly non-interactive. It is recommended to display a loading state (e.g. a loading spinner, disabling the checkout button, or both) while this is happening.
You can do it in one of three ways:
- Bind the form's loading state to the the promise returned by
addFields
, so that the loading state is turned off after the promise is done. Alternatively, you can pass a callback to the function to achieve the same result. - Add a callback to the
onLoad
option when creating the SDK instance (see instructions below). This callback will be triggered after the first call toaddFields
is completed. - Query the form's
isReady
field periodically. (Not recommended)
Submitting the form
Once the form has been completed, we’ll want to submit it.
You can use the submit()
method to perform this action. If the form is still in an invalid state when submitting, the validation errors will be returned. The onError callback can also be used to receive validation errors when submitting.
// Invalid form
const result = await forterCollect.submit();
console.log(result)
/**
{
"success": false,
"errors": {
"cc-number": {
"errorCode": "CREDIT_CARD_FORMAT_INVALID",
"message": "Credit card number is in an invalid format"
}
}
}
*/
// Valid form
const result = await forterCollect.submit();
console.log(result)
/**
{
"success": true,
"token": "ftr12d4e830283b647d4b3b2a3d65f02b8ab"
}
*/
API
Hosted Field SDK Object API
init(options: Options, cb ?:(err), eventHandlers ?: {}) => Promise
: Initialize the Forter Collection SDK.
init(options: Options, cb ?:(err), eventHandlers ?: {}) => Promise
: Initialize the Forter Collection SDK.This method returns a Promise object that can be awaited and returns any possible errors.
Alternatively, this method accepts an optional callback function which is invoked asynchronously once the action is completed.
See the options section below for more information about available configuration options.
addFields(fieldsDefinition,[cb: (err, results)]) => Promise
- Add one or more Hosted Fields to the form (See field definition explanation above).
addFields(fieldsDefinition,[cb: (err, results)]) => Promise
- Add one or more Hosted Fields to the form (See field definition explanation above).This method returns a promise that resolves when all Hosted Fields have finished loading and are ready for use. (See also: onLoad()
event below).
Alternatively, this method accepts an optional callback function which is invoked asynchronously once the action is completed.
updateFields(fieldsDefinition,[cb: (err, results)]): Promise
- Update one or more Hosted Fields in the form (See field definition explanation above).
updateFields(fieldsDefinition,[cb: (err, results)]): Promise
- Update one or more Hosted Fields in the form (See field definition explanation above).This method returns a promise that resolves when all Hosted Fields have finished updating and are ready for use.
Alternatively, this method accepts an optional callback function which is invoked asynchronously once the action is completed.
submit(cb: (err, results)): Promise<{status: boolean, token:string, errors?: Array<{message: string, errorCode:string}>}>
- Once the user finishes entering all the relevant fields in the payment form, this method will submit them securely to be stored by Forter.
submit(cb: (err, results)): Promise<{status: boolean, token:string, errors?: Array<{message: string, errorCode:string}>}>
- Once the user finishes entering all the relevant fields in the payment form, this method will submit them securely to be stored by Forter.This method returns a Promise object that can be awaited to receive the tokenized fields.
It will return the tokenized payload if successful, or the field errors if the form is still in an invalid state.
Alternatively, this method accepts an optional callback function which is invoked asynchronously once the action is completed.
Either way, the asynchronous result of this function is a single token string, that can later be unpacked in the server side to the individual fields, or sent as is to a third party using the Forter Secure Proxy. Please note, a successful tokenization does not execute a transaction or validation. In order to verify the payment method, you will need to invoke a purchase or authorization from your secure, server-side environment.
reset(fieldName?: string, cb?: (err, results)): Promise
- Reset all fields or a specific field in the form. If a field name is not provided, all of the fields will be reset.
reset(fieldName?: string, cb?: (err, results)): Promise
- Reset all fields or a specific field in the form. If a field name is not provided, all of the fields will be reset.This method returns a Promise object that can be awaited.
Alternatively, this method accepts an optional callback function which is invoked asynchronously once the action is completed.
focus(fieldName?: string): Promise
- Focus on a specific field in the form.
focus(fieldName?: string): Promise
- Focus on a specific field in the form.Form state
The Forter Collection SDK instance contains useful properties about the current state of the form:
fields
: an object containing per-field state properties: isValid, error, isEmpty, isDirty, isTouched, isReadyisReady
: boolean - Indicates whether all configured Hosted Fields have finished loadingisValid
: boolean - Indicates whether all fields are in a valid state, and the form is ready to be submitted.isSubmitting
: boolean - Indicates Whether the form is currently submitting the data to Forter.cardBrand
: string | null - The current card brand of PAN.
Options / events
The Forter Collection SDK instance can be configured using a configuration object passed to “checkoutTools.collect.init()” .
environment
- sandbox | production - (default: sandbox) - The tokenization environment to use.authToken
(REQUIRED) - An auth token retrieved from the PCI Tokenization API in the server-side.validationTrigger
- ON_BLUR | ON_CHANGE (default: ON_BLUR ) - When should each input be validated, potentially triggering error styling.onLoad()
- Triggered when all Hosted Fields are successfully loaded. It’s recommended to disable the submit button until after this event is triggered.
NOTE: This is only triggered the first time you add new fields to the form.onError(errors: {[fieldName: string]: {message: string, errorCode:string} })
- Triggered after the form is submitted in an invalid state. This handler receives a single argument - an object containing error messages, keyed by their relevant field name.onEnterPress()
- Triggered when the Enter button is pressed inside one of the Hosted Field inputs. This is typically used to invoke the submit API method on the SDK object.onEscapePress()
- Triggered when the Escape button is pressed inside one of the Hosted Field inputs.onSuccess()
- Triggered once the submit method was successfully completed. It’s recommended to show a loading indicator from the moment the form is submitted and until this event is triggered.onValidityChange(fieldId:string, isValid:boolean, error?: {message: string, errorCode:string})
- Triggered when the Field’s validity state has changed. In case the field is invalid, an error message code and default message text will be provided.onCardBrandChange(cardBrand: string)
- Triggered when a card brand is resolved from the card number
Example
let formLoading = false;
const forterCollect = window.checkoutTools.collect.init({
onLoad() {
formLoading = true;
},
async onEnterPress() {
const tokenizeResult = await forterCollect.submit();
if (tokenizeResult.success) {
console.log('Form successfully submitted', tokenizeResult);
}
},
onError(errors){
console.log('Form submit error:', errors)
}
});
Field API
Configuration options
Required options are marked with an asterisk.
- type* - The field’s ‘type’ dictates its appearance, behavior, and allowed values of the underlying input element. Forter Hosted Fields support these common payment field types:
TEXT
- General purpose string field. Custom regex validation can be applied using thevalidation
configuration optionCARD_HOLDER_NAME
- The name of the card’s owner. Custom regex validation can be applied using thevalidation
configuration option.CARD_NUMBER
- A credit card number. Luhn check validation is automatically applied.CARD_CVC
- A credit card security code (aka CVV). Length requirements are automatically derived from the brand of a ‘card-number’ field, if one exists.CARD_EXPIRATION_DATE
- Credit card expiration date.
- placeholder - The input’s field placeholder text. A sensible default is defined for each field type.
- initialValue - Specifies the starting value that the field.
- style - An object with css rules allowing customization of the Field’s style. See the ‘styling’ section below.
- validation - a RegEx pattern that will be used to validate the input’s value. This is only relevant for the
TEXT
andCARD_HOLDER_NAME
field type.forterCollect.addFields({ "card-holder-name": { type: "CARD_HOLDER_NAME", placeholder: "Name on card", validation: /^[a-z ,.'-]+$/i } });
Events
Every Forter Hosted Field triggers multiple events during its lifecycle. Event handlers can be attached using the configuration object passed to “addFields()” and “updateFields()”
onFocus()
- Triggered when the input element inside the Hosted Field receives focusonBlur()
- Triggered when the input element inside the Hosted Field loses focus
Error Codes
FIELD_INVALID_FORMAT
- Field is in an invalid format.CREDIT_CARD_FORMAT_INVALID
- Credit card number is in an invalid format.CREDIT_CARD_NUMBER_INVALID
- Credit card number is incorrect.CREDIT_CARD_EXPIRED
- Credit card is expired.GENERAL_ERROR
- An unknown error occurred.
Styling
Forter Hosted Fields can mostly be styled using standard CSS rules and techniques. When customizing your field's styles, the required techniques will differ when styling the container element itself (i.e. the form control), or the input element. This separation is required because the wrapping container element is hosted on your page, and the input in another, secured, web app.
Container elements
Simply target the container elements you’ve created in HTML using the same CSS rules you apply to your other, non hosted, form controls. This applies to macro layout like width, height, and spacing, and styling like border and box-shadow.
-
<form> <label> Name on card <div id="card-holder-name" style="border: solid 1px red; height: 40px" /> </label> </form>
Note: Even if your other inputs calculate their own height, Forter Hosted fields require an explicit ‘height’ to be set on the container element.
State classes
The following css rules are automatically added to the container element, which match the internal style “form states” mentioned above.
forter-hosted-fields-focus
forter-hosted-fields-valid
forter-hosted-fields-invalid
forter-hosted-fields-empty
forter-hosted-fields-touched
forter-hosted-fields-empty
forter-hosted-fields-dirty
Simply reference these classes in your stylesheets as normal:
{
.card-holder-name.forter-hosted-fields-focus {
border: solid 2px blue;
}
}
Input elements
In case advanced styling rules are required for the input elements themselves, additional css rules can be passed in to the javascript SDK object using the style configuration option.
Two types of styles can be used:
- A string containing an existing CSS class you may have already defined on your page used to style input elements. All CSS rules will be copied from this existing class and applied to the Hosted Field input element.
await sdk.addFields({ 'card-number': { type: 'CARD_NUMBER', style: '.existing-form-input-class' }, });
- A configuration object containing custom css definitions. Accepted keys in this object are:
- input - Standard css properties that will be applied to the internal input element (See below for supported properties)
- Pseudo-classes (eg. :hover, :focus) - Nest additional rules for every html state
- Form state classes: Specific css classes are automatically applied to every Hosted Field, depending on its state. Every class can be styled using specific css properties.
- Supported state classes:
.invalid - Field has failed validation.
.empty - Field doesn't have a value.
.touched - Applied forever once the field’s first ‘blur’ event has triggered.
.dirty - Applied forever once the field’s value has changed for the first time.
:focus - Field is currently focused
Media queries - (These apply to the iframe dimensions) - define a rule in pixels and nest additional rules of the other formats inside - Allowed CSS Properties (browser specific variants will also work): "appearance", "box-shadow", "color", "direction", "font", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", "font-variant-ligatures", "font-variant-numeric", "font-weight", "letter-spacing", "line-height", "margin", "margin-top", "margin-right", "margin-bottom", "margin-left", "opacity", "outline", "padding", "padding-top", "padding-right", "padding-bottom", "padding-left", "text-align", "text-shadow", "transition", "tap-highlight-color", "tap-highlight-color"
- Supported state classes:
await sdk.addFields({
'card-number': {
type: 'CARD_NUMBER',
style: {
'input': {
'color': 'black',
'padding': '10px 5px',
}
':focus': {
'border-color': 'blue',
},
'.touched': {
'color: 'green',
},
'.touched.error': {
'color: 'orange',
'text-decorations': 'underline',
},
'@media screen and (max-width: 600px)': {
'input': {
'font-size': '10px'
}
},
},
}
});
Example: Full Credit Card Details Form
We’ll create a common form containing fields for collecting a credit card’s number, security code and expiration date, along with the customer’s name.
First create the HTML scaffolding - a form with placeholders elements that will late be replaced with Forter Hosted Fields
<body>
<form id="payment-form">
<label>
Name on card
<div id="card-holder-name" />
</label>
<label>
Card
<div id="card-number" />
</label>
<label>
CVC
<div id="card-cvc" />
</label>
<label>
Expiration date
<div id="card-expiration" />
</label>
</form>
</body>
Next, in a Javascript tag copy and paste the following
const forterCollect = await checkoutTools.collect.init();
const commonStyles = {
":focus": {
color: "orange",
},
".touched": {
color: "green",
},
".touched.error": {
color: "red",
"text-decorations": "underline",
},
};
forterCollect.addFields({
"card-holder-name": {
type: "TEXT",
placeholder: "Name on card",
style: commonStyles,
},
"card-number": {
type: "CARD_NUMBER",
placeholder: "1111-2222-3333-4444",
onFocus() {
// TODO: handle focus
},
style: commonStyles,
},
"card-cvc": {
type: "CARD_CVC",
onError(errorMessage) {
console.error("Error in field card-cvv", errorMessage);
},
style: {
...commonStyles,
display: "inline-box",
},
},
"card-expiration": {
type: "CARD_EXPIRATION_DATE",
style: commonStyles,
},
});
Finally, wire up the form’s ‘submit’ event to Forter’s ‘submit’ method in order to securely store the Form’s state
document
.getElementById("#payment-form")
.addEventListener("submit", function (e) {
e.preventDefault();
// Callback based method:
forterCollect.submit(function (err, results) {
if (err) {
console.error("error submitting payment form", err);
return;
}
console.log("payment form submitted successfully!", results);
// Combine the tokenized fields along with other non-sensitive fields that may exist in the form, and submit them to your backend server for further processing.
backend.submitPaymentForm({ fields: { ...ownFields, ...results } });
});
// or alternatively, ESNext promise based method:
forterCollect
.submit()
.then((results) => {
if (results.success) {
console.log("Form successfully submitted", tokenizeResult);
}
console.log("payment form submitted successfully!", results);
backend.submitPaymentForm({ fields: { ...ownFields, ...results } });
})
.catch((e) => {
console.error("error submitting payment form", e);
});
});
Example: Re-collecting CVC
The Hosted Fields sdk supports the collection of just the CVC. This is useful in repeat transactions, along with a multi-use token in order to reduce the risk of a fraud-decline.
See the Detokenization proxy docs for more information on how to use the resulting token.
const forterCollect = await checkoutTools.collect.init();
forterCollect.addFields({
"card-cvc": {
type: "CARD_CVC",
onError(errorMessage) {
console.error("Error in field card-cvv", errorMessage);
},
},
});
Updated 7 days ago