BR-DGE Hosted Fields
Hosted Fields enables you to outsource all of your cardholder data handling to BR-DGE, allowing your platform to qualify for the simplest PCI-DSS SAQ level.
Hosted Fields achieves this by collecting the most sensitive cardholder data using iFrames hosted by BR-DGE.
BR-DGE then converts the data into a token that can be safely handled by your servers, allowing you to maintain the simplest levels of PCI qualification. This means your customers' card data will never touch your servers.
The token generated by the hosted fields can then be used by your back-end services to generate a payment using the REST API Payments Endpoint.
Prerequisites
Before following this guide you should first ensure you have setup the main JavaScript client. Please follow the Comcarde JavaScript Client setup before continuing with this guide.
Once this has been completed you can add the Hosted Fields module to your webpage.
Using the Hosted Fields Module
Add the hosted fields module to your page
First, add the correct hosted-fields.min.js
script to your checkout page. Using a HTML <script>
tag.
The Production and Sandbox environments use different scripts. Ensure you source the correct script for each environment
<script src="https://assets.comcarde.com/web/v2/js/hosted-fields.min.js"></script>
<script src="https://sandbox-assets.comcarde.com/web/v2/js/hosted-fields.min.js"></script>
Creating Placeholder HTML Elements
So that the hosted-fields can be injected into your website you need to insert placeholder <div>
elements with a special id
into your checkout page.
You can then position these to fit in with your website design.
The hosted-fields
module will find the elements based on their id
, and inject the relevant <iframe>
.
Hosted Fields will look for the <div>
elements with the following id
.
card-number
cvv
expiration-date
Create the <div>
elements like below.
<div id="card-number"></div>
<div id="cvv"></div>
<div id="expiration-date"></div>
Additionally, you can provide labels for the hosted fields.
<label for="card-number">Card Number</label>
<div id="card-number"></div>
<label for="cvv">CVV</label>
<div id="cvv"></div>
<label for="expiration-date">Exp. Date</label>
<div id="expiration-date"></div>
Adding the Hosted Fields functionality to your page
After setting up your placeholder <div>
and adding the Comcarde JavaScript Client you should have some JavaScript that looks similar to the below:
comcarde.client.create(
{
authorization: yourClientAPIKey, // Your Client API Key generated in the BR-DGE Portal
},
function (clientErr, clientInstance) {
if (clientErr) {
console.error(clientErr)
return
}
// You will add the hosted fields functionality in here
}
)
You now need to add the Hosted Fields specific functionality to the Comcarde JavaScript Client.
The following JavaScript example shows how you can achieve adding this functionality to your checkout page.
comcarde.client.create(
{
authorization: yourClientAPIKey, // Your Client API Key generated in the BR-DGE Portal
},
function (clientErr, clientInstance) {
comcarde.hostedFields.create( // Create an instance of the Hosted Fields
{
client: clientInstance,
styles: {
/*
* Apply your styling options to the hosted fields
* For more information on Hosted Fields styling, and the supported options
* check out https://docs.br-dge.io/docs/hosted-fields-styling
*/
},
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.
*/
hostedFieldsInstance.tokenize(
{
cardholderName: 'John Smith',
issueNumber: '01',
startDate: '01/19',
},
function (tokenizeErr, payload) {
if (tokenizeErr) {
console.error(tokenizeErr)
return
}
/*
* Calling the `tokenize` function will create a multi-use token
* that you can use in place of raw card data when making
* a payment request to the /v1/payments API endpoint
*
* https://docs.br-dge.io/reference/createpaymentusingpost
*
* The `payload` object will match the response schema
* for the /v1/payment-instruments API endpoint
*
* https://docs.br-dge.io/reference/tokenizeinstrument
*
* The multi-use token is the value returned in `payload.token`.
* You pass this token back to your server to make the payment request
*/
if (payload.metadata) {
var metadata = payload.metadata
/*
* When you tokenise a card using hosted fields
* BR-DGE will attempt to return metadata for this card.
*
* The structure of payload.metadata
* will follow the `CardMetadata` schema from the BR-DGE REST API
*
* See the BIN/IIN Lookup section of this guide
* for more information on card metadata, how to extract it,
* and the structure of the metadata response.
*
*/
}
}
)
},
false
)
}
)
}
)
Hosted Fields supports certain styling options. Please see Hosted Fields Styling for more details.
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 Name | Description |
---|---|
focus | Emitted when a field gains focus. |
blur | Emitted when a field loses focus. |
empty | Emitted when a field transitions from having data to being empty. |
notEmpty | Emitted when a field transitions from being empty to having data. |
cardTypeChange | Emitted when the possible card type has changed. |
validityChange | Emitted 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 lost focus')
})
BIN/IIN Lookup
Hosted Fields supports on-the-fly Bank Identification Number (BIN) lookup.
When the first nine digits of a card number are entered into the card-number element, hosted fields will return metadata for the specified BIN.
The information returned follows the CardMetadata
schema of the BR-DGE REST API.
"cardMetadata": {
"cardBrand": "VISA",
"issuer": "ACMEBANK",
"type": "DEBIT",
"category": "CLASSIC",
"countryIsoA2": "GB",
"commercial": true
}
Enable BIN Lookup
To enable BIN Lookup set the binLookup
flag to true
when initialising the Hosted Fields module:
comcarde.hostedFields.create({
...
binLookup: true, // Enable BIN lookup
...
});
How to use the BIN lookup feature
Once enabled, configure a callback that will handle the card metadata object each time the first 9 digits of a card number is entered into the Hosted Fields.
The below example details how to setup the callback, and how you can extract specific values from the cardMetadata
object.
hostedFieldsInstance.on('binLookup', (cardMetadata) => {
var cardIssuer = cardMetadata.issuer
var cardType = cardMetadata.type
var cardCategory = cardMetadata.category
var cardCountry = cardMetadata.countryIsoA2
var isCommercialCard = cardMetadata.commercial
})
For more information on the data returned in the BIN Lookup, please see the CardMetadata schema in the BR-DGE REST API.
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 have been met, the tokenize
method can be configured to create a Card on File.
When calling the tokenize
method with customerAgreedToSaveCard: true
BR-DGE will create a multi-use token that you can store in place of raw card data for use in other transactions.
hostedFieldsInstance.tokenize({
'customerAgreedToSaveCard': true,
'customerId': ..., // Your unique identifier for this customer
...
}, function(tokenizeErr, payload) {
/*
*
* The multi-use token is the value returned in `payload.token`.
* You pass this token back to your server to make the payment request
*
* The full `payload` object will match the response schema
* for the /v1/payment-instruments API endpoint
*
* https://docs.br-dge.io/reference/tokenizeinstrument
*
*/
}
});
Using a Card on File
When using a Card on File in payments we recommend exchanging the multi-use token for a single-use token in your client application, then using the single-use token in payment requests.
This step is entirely optional, and you can make a payment request with a multi-use token if you wish.
Multi-Use Token to Single-Use Token
Call tokenizeSavedCard
with the multi-use token associated to the card your customer selects. This will create a single-use token linked to the multi-use token.
You can then use this single use token in the payment request.
comcarde.client.create({
authorization: yourClientAPIKey, // Your Client API Key generated in the BR-DGE Portal
}, function(clientErr, clientInstance) {
...
comcarde.hostedFields.create({
client: clientInstance,
...
}, function(hostedFieldsErr, hostedFieldsInstance) {
...
form.addEventListener('submit', function(event) {
event.preventDefault();
event.preventDefault();
hostedFieldsInstance.tokenizeSavedCard({
'token': YourCustomersMultiUseToken // The multi-use token associated to your customers card
}, function(tokenizeErr, payload) {
/*
* The single-use token is the value returned in `payload.token`.
* You pass this token back to your server to make the payment request
*
* The full `payload` object will match the response schema
* for the /v1/payment-instruments API endpoint
*
* https://docs.br-dge.io/reference/tokenizeinstrument
*
*/
});
}
})
};
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: yourClientAPIKey, // Your Client API Key generated in the BR-DGE Portal
}, function(clientErr, clientInstance) {
...
comcarde.hostedFields.create({
client: clientInstance,
...
fields: {
...
saveCardCvv: {
selector: '#save-card-cvv',
placeholder: 'xxx'
}
}
}, function(hostedFieldsErr, hostedFieldsInstance) {
...
form.addEventListener('submit', function(event) {
event.preventDefault();
hostedFieldsInstance.tokenizeSavedCard({
'token': YourCustomersMultiUseToken // The multi-use token associated to your customers card
}, function(tokenizeErr, payload) {
/*
* The single-use token is the value returned in `payload.token`.
* You pass this token back to your server to make the payment request
*
* The full `payload` object will match the response schema
* for the /v1/payment-instruments API endpoint
*
* https://docs.br-dge.io/reference/tokenizeinstrument
*
*/
});
}
});
});
Visa Installments
Visa Installments is an optional extension to our hosted fields module that allows issuers to offer installment plans to their cardholders.
Using Visa Installments requires that your retail channels are configured to support it.
Please get in contact with support to enable this feature.
At a high level this works by:
- A customer enters their card details
- 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.
- Please get in contact with support to enable Visa Installments on your account
- Use the data provided within the
visaInstallmentPlans
array to build a UI to display different plan options to their customers. - 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. - You will receive a settlement for the full amount similar to a card payment.
- 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 OpenAPI specification.
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 thetermsAndConditions
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.
}
)
Updated about 1 month ago