BR-DGE Hosted Fields

Fully outsource all your cardholder data functions to BR-DGE so that your platform qualifies for the simplest PCI-DSS SAQ level.

This is achieved by collecting the most sensitive cardholder data via inline frames (iframes) hosted by BR-DGE domains. BR-DGE PCI-DSS SAQ-D compliant systems can then translate the data into a single-use token that can be safely handled by your PCI-DSS SAQ-A platform. The token can be used by your back-end services to generate a payment via the BR-DGE REST API.

Add BR-DGE Hosted Fields Module to your App

After you have set up the Comcarde JavaScript Client, you can add a hosted-fields module to your website source.

<script src="https://sandbox-assets.comcarde.com/web/v2/js/hosted-fields.min.js"></script>
<script src="https://assets.comcarde.com/web/v2/js/hosted-fields.min.js"></script>

Insert placeholder elements with special IDs into your website. These can be positioned to fit in with your website/app design. The hosted-fields module will find the elements based on their ID, and replace them with <iframe> elements.

Hosted Field element IDs

  • card-number
  • cvv
  • expiration-date

Example:

<div id="card-number"></div>
<div id="cvv"></div>
<div id="expiration-date"></div>

You can also provide labels for the hosted fields, the same as if it were a field hosted by the parent website/app.

<label for="expiration-date">Expiration Date</label>
<div id="expiration-date"></div>

Finally, add hosted fields functionality to your Comcarde JavaScript Client:

comcarde.client.create(
  {
    authorization: client - api - key, // your client API Key
  },
  function (clientErr, clientInstance) {
    // optionally configure other plugin modules...

    /*
     * Create BR-DGE Hosted Fields Plugin Module Component
     */
    comcarde.hostedFields.create(
      {
        client: clientInstance,
        styles: {
          // Style all elements
          input: {
            'font-size': '16px',
            color: '#3A3A3A',
            'font-family': 'monospace',
          },

          // Styling element state
          ':focus': {
            color: 'blue',
          },
          '.valid': {
            color: 'green',
          },
          '.invalid': {
            color: 'red',
          },

          // Media queries
          // Note that these apply to the iframe, not the root window.
          '@media screen and (max-width: 700px)': {
            input: {
              'font-size': '16px',
            },
          },
        },
        fields: {
          number: {
            selector: '#card-number',
            placeholder: 'xxxx xxxx xxxx xxxx',
          },
          cvv: {
            selector: '#cvv',
            placeholder: 'xxx',
          },
          expirationDate: {
            selector: '#expiration-date',
            placeholder: 'MM/YYYY',
          },
        },
      },
      function (hostedFieldsErr, hostedFieldsInstance) {
        if (hostedFieldsErr) {
          console.error(hostedFieldsErr)
          return
        }

        hostedFieldsInstance.on('validityChange', function (event) {
          var field = event.fields[event.emittedBy]
          if (field.isValid) {
            // handle valid case
          } else if (field.isPotentiallyValid) {
            // handle potentially valid case
          } else {
            // handle invalid case
          }
        })

        /*
         * Hosted Fields can also listen on the following events
         */

        form.addEventListener(
          'submit',
          function (event) {
            event.preventDefault()

            /*
             * Cardholder name, issue number, and start date can optionally also be
             * passed to the tokenize operation. This data can safely be collected
             * via fields hosted by merchants without requiring more than PCI DSS SAQ A
             * accreditation.
             *
             * This can be useful if your BR-DGE account is configured with Payment
             * Service Provider connections that require cardholder names etc.
             */
            hostedFieldsInstance.tokenize(
              {
                cardholderName: 'X Ample',
                issueNumber: '01',
                startDate: '01/19',
              },
              function (tokenizeErr, payload) {
                if (tokenizeErr) {
                  console.error(tokenizeErr)
                  return
                }

                // send payload.token to your server to be used as a tokenized payment
                // instrument in a payment request.

                // If BR-DGE is able to provide metadata about the card then
                // payload.metadata will be provided. This field will be returned as
                // null if no card information is available.
                //
                // Note: All text field values will be UPPERCASE, and any field could
                // be returned as null if its value could not be determined.
                if (payload.metadata) {
                  var metadata = payload.metadata
                  /*
                   * metadata.cardBrand: MASTERCARD, VISA, etc (free text)
                   * metadata.issuer: Name of issuing bank (free text)
                   * metadata.type: DEBIT, CREDIT or CHARGE_CARD (enum)
                   * metadata.category: CLASSIC, BUSINESS, MIXED_PRODUCT, etc
                   *                    (free text)
                   * metadata.countryIsoA2: ISO 3166 Alpha-2 country code
                   * metadata.commercial: indicates if card is corporate or retail
                   *                      (Boolean)
                   */
                }
              }
            )
          },
          false
        )
      }
    )
  }
)

To can customise your Hosted Fields, please see the Hosted Fields Styling documentation.

Hosted Fields Events

You can subscribe to Hosted Fields events using an event listener. This allows you to update the UI of your form based on the state of the fields. These events include:

Event NameDescription
focusEmitted when a field gains focus.
blurEmitted when a field loses focus.
emptyEmitted when a field transitions from having data to being empty.
notEmptyEmitted when a field transitions from being empty to having data.
cardTypeChangeEmitted when the possible card type has changed.
validityChangeEmitted when the validity of a field changes.

Example:

hostedFieldsInstance.on('validityChange', function (event) {
  console.log(event.emittedBy, 'validity')
})

hostedFieldsInstance.on('focus', function (event) {
  console.log(event.emittedBy, 'has been focused')
})

hostedFieldsInstance.on('blur', function (event) {
  console.log(event.emittedBy, 'has been burred')
})

BIN/IIN Lookup

The Hosted Fields module supports on-the-fly Bank/Issuer Identification Number lookup when the first nine digits of a card PAN are entered into BR-DGE Hosted Fields. The information returned will match the CardMetadata schema of the BR-DGE REST API.

This feature can be enabled via the binLookup flag when configuring the Hosted Fields module:

comcarde.hostedFields.create({
  ...
  binLookup: true, // enable BIN/IIN lookup
  ...
});

A callback can then be configured which will be provided with a card metadata object every time a PAN is entered into BR-DGE Hosted Fields:

hostedFieldsInstance.on('binLookup', (cardMetadata) => {
  // cardMetadata will contain information about the card
  var cardType = cardMetadata.type
})

πŸ‘

Navigate to our API Docs and search for CardMetadata for information on the payload.

Card on File

Card on File can further streamline your online checkout experience. We recommend reading about the BR-DGE Vault before continuing.

Creating a Card on File

Once Credentials On File Mandate requirements relating to cardholder consent has been met, the tokenize method can be configured to create a Card on File.

hostedFieldsInstance.tokenize({
   'customerAgreedToSaveCard': true,
   'customerId': ..., // optional identifier for customer
   ...
}, function(tokenizeErr, payload) {
   /*
    * payload.token contains a single-use token associated with a CVV if collected
    * payload.savedCard.token: multi-use token that can be used to represent the
    *                          card in future payments
    * payload.savedCard.cardType: E.g. VISA/MASTERCARD
    * payload.savedCard.nameOnCard: "John F Doe",
    * payload.savedCard.pan: Obfuscated card PAN to help shoppers identify cards
    *                        e.g. "**** **** **** 1111"
    * payload.savedCard.expiryDate: E.g. "06-30",
    * payload.savedCard.startDate: If available, e.g. "01-20"
    * payload.savedCard.issueNumber: if available, e.g. 1
    */
  }
});

Using a Card on File

When using a Card on File in payments we recommend exchanging the multi-use token for the Card on File for a single-use token in your client application, then using the single-use token in payment requests.

Multi-Use Token to Single-Use Token

Call tokenizeSavedCard with the multi-use token for the saved card your customer selects.

comcarde.client.create({
  authorization: client-api-key // your client API Key
}, function(clientErr, clientInstance) {
  ...
  comcarde.hostedFields.create({
    client: clientInstance,
    ...
  }, function(hostedFieldsErr, hostedFieldsInstance) {
    ...
    // for example, using a form to initiate tokenization
    form.addEventListener('submit', function(event) {
      event.preventDefault();
      event.preventDefault();

      hostedFieldsInstance.tokenizeSavedCard({
        'token': multi-use-token // for selected saved card
      }, function(tokenizeErr, payload) {
        // send payload.token to your server to be used as a tokenized payment
        // instrument in a payment request.
      });
    }
  })
};
Multi-Use Token to Single-Use Token with CVV

For security reasons, we do not store card verification values (CVVs), but you can optionally collect CVVs and temporarily associate them with single-use tokens.

If you wish to collect CVVs, first add a div to contain a CVV field hosted by BR-DGE:

<label for="save-card-cvv">CVV</label>
<div id="save-card-cvv"></div>

Then configure the hosted fields module to collect CVVs, and call tokenizeSavedCard with the multi-use token for the saved card your customer selects:

comcarde.client.create({
    authorization: client-api-key // your client API Key
  }, function(clientErr, clientInstance) {
  ...
    comcarde.hostedFields.create({
      client: clientInstance,
      ...
      fields: {
      ...
        saveCardCvv: {
          selector: '#save-card-cvv',
          placeholder: 'xxx'
        }
      }
    }, function(hostedFieldsErr, hostedFieldsInstance) {
      ...
      // for example, using a form to initiate tokenization
      form.addEventListener('submit', function(event) {
      event.preventDefault();

        hostedFieldsInstance.tokenizeSavedCard({
          'token': multi-use-token // for selected Card on File
        }, function(tokenizeErr, payload) {
          // send payload.token to your server to be used as a tokenized payment
          // instrument in a payment request.
        });
      }
    });
  });

Visa Installments

Visa Installments is an optional extension to our hosted fields module that allows issuers to offer installment plans to their cardholders.

At a high level this works by:

  1. A customer enters their card details
  2. If Visa Installments is enabled on your BR-DGE account and your customer uses a Visa card we may return an array of Visa Installment plans you can offer to your customer.
  3. Use the data provided within the visaInstallmentPlans array to build a UI to display different plan options to their customers.
  4. If your customer selects a plan and agrees to the terms and conditions you can call hostedFieldsInstance.tokenizeVisPlan to generate a token that can be used as a payment instrument in payment requests by your server.
  5. You will receive a settlement for the full amount similar to a card payment.
  6. The Installments agreement and the servicing of that agreement are between the issuer and their cardholder and does not involve the merchant.

Enable Visa Installments

Add additional configuration to your hostedFields configuration, comcarde.hostedFields.create should be extended with a visaInstallments object that contains an amount and currencyCode:

// Configure hostedFields
comcarde.hostedFields.create({
  ...
  visaInstallments: {
    amount: "10000", // example of the amount to be paid (in cents)
    currencyCode: "USD" // example of transaction's currency
  }
  ...
});

Tokenize your Customer's card

πŸ“˜

Installment Plans will only be returned for eligible VISA customers

Use our hosted fields tokenize functionality as you would normally. If the card is eligible you may receive an array of visaInstallmentPlans in the response to calling hostedFieldsInstance.tokenize.

Please get in contact with support for information on how to present Visa Installment plans to your customers.

Example array of `visaInstallmentPlans``:

[
  {
    "planId": "3fa...a6",
    "name": "Plan name",
    "type": "ISSUER_PROMOTION",
    "numberOfInstallments": 0,
    "installmentFrequency": "WEEKLY",
    "termsAndConditions": [
      {
        "url": "https://dev...sa.com/support",
        "version": 0,
        "text": "Sample terms and conditions text",
        "languageCode": "eng"
      }
    ],
    "promotionInfo": {
      "promotionCode": "A2",
      "promotionID": "MBANK12"
    },
    "costInfo": {
      "annualPercentageRate": 320,
      "feeInfo": [
        {
          "type": "CONSUMER",
          "ratePercentage": 150,
          "flatFee": 1000
        },
        {
          "type": "UPFRONT_FEES",
          "ratePercentage": 150
        }
      ],
      "totalPlanCost": 61299,
      "totalFees": 500,
      "totalUpfrontFees": 100,
      "totalRecurringFees": 20,
      "firstInstallment": {
        "installmentFee": 123112,
        "amount": 123112,
        "upfrontFee": 123112
      },
      "lastInstallment": {
        "installmentFee": 123112,
        "amount": 123112
      },
      "currency": "USD"
    }
  },
  {
    "planId": "f73676d0-999d-09b7-3581-1963c7c63d02",
    "name": "TestX",
    "type": "ISSUER_DEFAULT",
    "numberOfInstallments": 3,
    "installmentFrequency": "MONTHLY",
    "termsAndConditions": [
      {
        "url": "",
        "version": 6,
        "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "languageCode": "eng"
      }
    ],
    "promotionInfo": {
      "promotionCode": "",
      "promotionID": ""
    },
    "costInfo": {
      "annualPercentageRate": 0,
      "feeInfo": [
        {
          "type": "CONSUMER",
          "ratePercentage": 0,
          "flatFee": 0
        },
        {
          "type": "CONSUMER_UPFRONT",
          "ratePercentage": 200,
          "flatFee": 0
        }
      ],
      "totalPlanCost": 12592,
      "totalFees": 247,
      "totalUpfrontFees": 247,
      "totalRecurringFees": 0,
      "firstInstallment": {
        "installmentFee": 0,
        "amount": 4115,
        "upfrontFee": 247
      },
      "lastInstallment": {
        "installmentFee": 0,
        "amount": 4115
      },
      "currency": "USD"
    }
  }
]

πŸ‘

For more information please see the VisaInstallmentMatchedPlan schema in the BR-DGE REST API reference.

Tokenize Selected Installment Plan

Once the customer has selected and accepted the terms and conditions of an installment plan we then create a new token that can be used as by your server as a [Payment Instrument] in a payment request.

To do this we have extended hosted fields with a tokenizeVisPlan function, this should be called with:

  • The token from the original card tokenization
  • The selected planId
  • The version of the termsAndConditions that the customer has accepted
const token = '95ea954e-e02b-4275-a614-fe4ef55c510e' // Token from card tokenization
const planId = 'f73676d0-999d-09b7-3581-1963c7c63d02' // Visa Installment Plan ID
const termsAndConditionsVersionNumber = 6 // Version of accepted terms and conditions

hostedFieldsInstance.tokenizeVisPlan(
  { token, planId, termsAndConditionsVersionNumber },
  function (tokenizeErr, tokenizePayload) {
    if (tokenizeErr) {
      throw tokenizeErr
    }
    // send tokenizePayload.token to your server to be used as a tokenized payment
    // instrument in a payment request.
  }
)