Secure Fields

Secure Fields provides developers with pre-built form fields to securely collect sensitive data from the client side. These fields are hosted by Payrails and injected into your web page as iFrames. This reduces your PCI compliance scope by not exposing your front-end application to sensitive data. Follow the steps below to collect data securely with Payrails Fields on your web page.

Getting started

Below is a four-step process to start using Secure Fields in your client.

Create a container

First, create a container for the form fields using the collectContainer() method of the Payrails client.

There are 2 types of containers:

  • COMPOSABLE: you call mount() directly on the container, you must define the form's layout, and the number of elements must match the sum of the numbers in the layout.
  • COLLECT: layout is not necessary. Secure fields are mounted separately.
const container = payrailsClient.collectContainer({
  containerType?: 'COMPOSABLE' || 'COLLECT'; // default composable
  layout?: number[]; // required only for composable container type, layout for card form 
});

Create a collectible field

const collectField =  {
   type: Payrails.ElementType,  //Payrails.FieldType enum
   inputStyles: {},             //optional styles that should be applied to the form field
   labelStyles: {},             //optional styles that will be applied to the label of the collect field
   errorTextStyles:{},          //optional styles that will be applied to the errorText of the collect field
   label: "string",             //optional label for the form field
   placeholder: "string",       //optional placeholder for the form field
   required: false,             //optional, indicates whether the field is marked as required. Defaults to 'false'
   enableCardIcon: true,        //optional, indicates whether card icon should be enabled (only applicable for CARD_NUMBER FieldType)
   format: String,              //optional, format for the field (only applicable currently for EXPIRATION_MONTH and EXPIRATION_YEAR FieldType)
}

const field = payrailsContainer.createCollectElement(collectField)

A Payrails CollectField is defined as shown below:

propertytypedescription
typePayrails.FieldType (required)Enum (CARDHOLDER_NAME, CARD_NUMBER, EXPIRATION_DATE, EXPIRATION_MONTH, EXPIRATION_YEAR, CVV).
Each type applies the appropriate regex and validations to the form field.
inputStylesObject (optional)Styles that should be applied to the form field
labelStylesObject (optional)Styles that will be applied to the label of the collect field
errorTextStylesObject (optional)Styles that will be applied to the errorText of the collect field.
labelString (optional)Label for the form field
placeholderString (optional)Placeholder for the form field
requiredBooleanIndicates whether the field is marked as required or not. If not provided, it defaults to false.
enableCardIconBooleanIndicates whether the icon is visible for the CARD_NUMBER field defaults to true
formatStringIndicates the format pattern applicable to the date types:

- EXPIRATION_DATE: MM/YY (default), MM/YYYY, YY/MM, or YYYY/MM.
- EXPIRATION_YEAR: YY (default), or YYYY.
Note: if not specified or an invalid value is passed to the format then it takes a default value.

Mount fields to the DOM

Collect container

To specify where the fields will be rendered on your page, create a placeholder <div> fields with unique id tags. For instance, the form below has 4 empty divs with unique IDs as placeholders for four Payrails fields.

<form>
  <div id="cardNumber" />
  <br />
  <div id="expireDate" />
  <br />
  <div id="cvv" />
  <br />
  <div id="pin" />
  <button type="submit">Submit</button>
</form>

Now, when the mount(domField) method of the Field is called, the Field will be inserted in the specified div. For instance, the call below will insert the Field into the div with the id #cardNumber.

field.mount("#cardNumber");

You can use the unmount method to reset any collect field to its initial state.

field.unmount();

Composable container

A composable container works similarly to a collect container but is mounted as a whole.

<div id="card-form"></div>
container.mount('#card-form')

Extract data from secure fields

Collect raw data

When the form is ready to be submitted, call the container.collect() method on the container object. This will collect the data from all the fields belonging to the container and save it to the vault.

const data = await container.collect();
console.log(data);	// see the id and other details of the entered card

Tokenize the card and create a payment instrument

Alternatively, you can create a payment instrument.

Note: you don't need to use this method in most cases. Instead, call container.collect() and use raw card data to authorize the payment.

Call the container.tokenize({storeIntstrument: true}) method on the container object. This will collect the data from all the fields belonging to the container and save it to the vault. It will also create a payment instrument and return the payment instrument details.

try {
  const response = await container.tokenize({storeInstrument: true});
  console.log(response);	// see the id and other details of your newly tokenized card
} catch (e) {
  console.log(e);	// solve the case when something went wrong
}

Errors and validation

Payrails Web provides two types of validation for collecting fields.

Default validations

Every Collect Field has a set of default validations listed below:

typevalidation
CARD_NUMBERCard number validation with checksum algorithm (Luhn algorithm).
Available card lengths for defined card types are [12, 13, 14, 15, 16, 17, 18, 19].
A valid 16-digit card number will be in the format XXXX XXXX XXXX XXXX.
CARD_HOLDER_NAMEThe name should be 2 or more symbols, and valid characters should match the pattern: ^([a-zA-Z\\ \\,\\.\\-\\']{2,})$.
CVVCard CVV can have 3-4 digits.
EXPIRATION_DATEAny date starting from the current month. By default, the valid expiration date should be in the short-year format: MM/YY.

UI errors

Helps to display custom error messages on the Payrails Fields through the methods setError and resetError on the fields.

const cardNumber = container.createCollectElement({
  type: ElementType.CARD_NUMBER,
});

//Set custom error
cardNumber.setError("custom error");

//reset custom error
cardNumber.resetError();

setError(error: string) method is used to set the error text for the field. When this method is triggered, all the current errors in the field will be overridden with the custom error message passed. This error will be displayed on the field until resetError() is triggered on the same field.

resetError() method is used to clear the custom error message that is set using setError.

Event Listener

Helps to communicate with Payrails fields by listening to an event:

field.on(eventName: EventName, handler: function)

There are 4 events in EventName:

eventdescription
CHANGEA change event is triggered when the Field's value changes.
READYA ready event is triggered when the Field is fully rendered.
FOCUSA focus event is triggered when the Field gains focus.
BLURA blur event is triggered when the Field loses focus.

The handler function(state) => void is a callback function you provide that will be called when the event is fired with the state object, as shown below.

state: {
  fieldType: ElementType;
  isEmpty: boolean;
  isFocused: boolean;
  isValid: boolean;
  value: string;
}

Here's a sample code snippet for using listeners:

const cardNumber = container.createCollectElement({
  type: ElementType.CARD_NUMBER,
});

cardNumber.mount("#cardNumberContainer");

// Subscribing to CHANGE event, which gets triggered when field changes.
cardNumber.on(EventName.CHANGE, (state) => {
  // Your implementation when Change event occurs.
  console.log(state);
});

Styling

You can configure the style of the Secure Fields as you wish:

const field = container.createCollectElement({
  inputstyles: {},
  labelStyles: {},
  errorTextStyles: {},
  type: ElementType.CARD_NUMBER,
});

The inputStyles field accepts a style object that consists of CSS properties that should be applied to the form field in the following states:

objectdescription
baseAll other variants inherit from these styles.
completeApplied when the Field has valid input.
emptyApplied when the Field has no input.
focusApplied when the Field has focus.
invalidApplied when the Field has invalid input.
cardIconApplied to the card type icon in CARD_NUMBER Field.
copyIconApplied to copy icon in Fields when enableCopy option is true.

Styles are specified with JSS.

An example of a inputStyles object:

inputStyles:{
  base: {
    border: "1px solid #eae8ee",
    padding: "10px 16px",
    borderRadius: "4px",
    color: "#1d1d1d",
  },
  complete: {
    color: "#4caf50",
  },
  empty: {},
  focus: {},
  invalid: {
    color: "#f44336",
  },
  cardIcon:{
    position: "absolute",
    left:"8px",
    bottom:"calc(50% - 12px)"
  },
  copyIcon:{
    position: "absolute",
    right:"8px",
  }
}

The states that are available for labelStyles are base and focus.

An example of a labelStyles object:

labelStyles: {
  base: {
    fontSize: "12px",
    fontWeight: "bold"
  },
  focus: {
    color: "#1d1d1d"
  }
}

The state that is available for errorTextStyles is only the base state, it shows up when there is some error in the collect field.

An example of an errorTextStyles object:

errorTextStyles: {
  base: {
    color: "#f44336";
  }
}

Translations

For the Secure Fields, translations are part of the container's createCollectElement(collectField, options) signature, inside the collectField object:

const field = payrailsContainer.createCollectElement({
   type: ElementType.CARD_NUMBER,    //Payrails.FieldType enum
   label: "localized label for the form field",
   placeholder: "localized placeholder for the form field",
}, {});

End-to-end example

Here's an end-to-end example of card collection with a secure field for a container of COLLECT type.

//Step 1
const container = payrailsClient.collectContainer({
  containerType: 'COLLECT'
});

//Step 2
const field = container.createCollectElement({
  inputstyles: {
    base: {
      color: "#1d1d1d",
    },
    cardIcon: {
      position: "absolute",
      left: "8px",
      bottom: "calc(50% - 12px)",
    },
  },
  labelStyles: {
    base: {
      fontSize: "12px",
      fontWeight: "bold",
    },
  },
  errorTextStyles: {
    base: {
      color: "#f44336",
    },
  },
  placeholder: "Card Number",
  label: "card_number",
  type: ElementType.CARD_NUMBER,
});

// Step 3
field.mount("#cardNumber"); //assumes there is a div with id="#cardNumber" in the webpage

// Step 4
container.collect();