Hosted Fields
Hosted Fields is a solution that lets merchants offer Afterpay at checkout without collecting sensitive information themselves.
The solution involves a special text entry box (or any other standard HTML data entry field) that collects data directly to AfterPay’s servers, from within the merchant’s website/app. The merchant receives only a proprietary unique ID (nonce). This can be used to identify the customer in calls to the AfterPay eCommerce API, but not to resolve the customer’s Personally Identifiable Information. This allows the merchant to avoid the obligations and risks that stem from handling sensitive data.
The solution creates a text entry box in the merchant’s website/app that is an iFrame to AfterPay’s servers. Any data entered into this field by the customer is visible only to AfterPay’s servers, and not to the merchant. The fields are displayed by the merchant’s website/app, but hosted by AfterPay’s servers.
Nonce
Hosted Fields are designed to collect the customer’s Personally Identifiable Information (name, email, national ID number, address, etc.).
The merchant wants to minimize the amount of PII handled by their systems. However, this information is required by AfterPay for its credit/risk checks and to positively identify the customer for invoicing.
The merchant’s customer signup (or checkout) includes a transparently embedded iFrame of a text entry box (or other HTML entry field). The iFrame is hosted on AfterPay’s Hosted Fields Server. When the customer submits the form, the contents of the Hosted Field are sent directly from the customer’s device to AfterPay’s server, and never pass through the merchant’s systems.
Instead, the merchant receives a nonce – a unique string that can be used as a replacement for the customer’s PII in the Authorize call to the AfterPay eCommerce API. The eCommerce API takes the nonce and sends it to the Hosted Fields Server, which provides the original data in response, all over a secure backend connection.
You can use multiple Hosted Fields in one webform. If they are all part of a single Authorize call, the merchant will receive a single nonce in return, and all the collected data will be associated with that nonce.
Integration
The solution includes the following components on AfterPay’s end:
-
ID Service:
- Takes the merchant’s API key
- Issues an authentication token that can be used with the Hosted Fields Server
-
Hosted Fields Server:
- Takes the customer’s authentication token
- Returns the iFrame code (Hosted Fields Client Library) for the PII field
- Takes the data that was entered into the hosted PII field
- Returns the nonce
The nonce can be used for subsequent AfterPay eCommerce API calls, as part of the Checkout Customer block. If the nonce is provided, the identificationNumber is optional.
The nonce can be used only with the same merchant API key as the one that was used to generate it. Otherwise, the eCommerce API will reject the call.
The nonce can be used only for a single Authorize call. Each checkout must be conducted with a new nonce.
Workflow
A Hosted Fields transaction using the nonce consists of the following distinct steps:
- User authentication
- Javascript library initialization
- Saving field contents
- Authorization of transaction

User Authentication
Hosted Fields require authentication to prevent abuse, and to link the nonce record to a particular merchant.
Authentication is achieved by calling the AfterPay ID service via REST API, using the merchant’s API key.
The acquisition of the JWT token must be implemented as a server-to-server call. Your API key should never be exposed to the public.
To reduce the load on the ID service, and improve the customer experience, it is recommended to reuse the token between customers. The token is valid for 48 hours (current default, configurable in AfterPay backend).
Parameter | Value | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
URL (test environment) | https://hosted-fields-pt.afterpay.nl/ | |||||||||
URL (production environment) | https://hosted-fields.afterpay.nl/ | |||||||||
HTTP Method | POST | |||||||||
Content type | application/json | |||||||||
Request body |
|
HTTP RESPONSE CODE | DESCRIPTION |
---|---|
OK (200) | JWT token issued |
Unauthorized (401) | Invalid or expired API key |
Bad Request (400) | Invalid request parameters |
Server error (500) | Internal server error, try again |
curl -X POST {{URL}} \
-H 'Content-Type: application/json' \
-d '{
"service": "hosted-fields",
"apiKey": {{YOUR_API_KEY}}
}'
{
"validUntil": "2019-03-09T09:59:21+00:00",
"token": {{TOKEN}}
}
Javascript Library Initialization
Once the merchant has the token, they can initialize the Hosted Fields client library in the customer’s browser/app.
Include javascript library
<script src="https://hosted-fields-pt.afterpay.nl/hosted-fields.js"></script>
Configure hosted fields client library
var config = {
baseAddress: {{URL}},
token: 'JWT_TOKEN',
form: document.getElementsByTagName('form')[0],
fields: [
{
'name': 'customer.identificationNumber',
'element': '#ssn-container',
'bodyStyle': 'background-color: rgb(255, 0, 255);',
'fieldStyle': "border: 1px solid #f0f; color 'green'",
'iframeClassName': 'test-iframe',
'fieldFocusStyle': 'border: 3px solid #f00;',
'fieldHoverStyle': 'background-color: #9f9;',
'iframeTitle': 'iframe__TITLE__SSN',
'placeholder': 'DDMMYYXXXXX',
'validationRegex': /[0-9]{2}[0,1][0-9][0-9]{2}[ ]?[0-9]{5}/,
'numericKeypad': true
}
]
};
PARAMETER | DESCRIPTION | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
baseAddress | Used to determine where the Hosted Fields API is hosted. Only relevant for integration against a dev/test environment. In a production setting, this should be removed. | ||||||||||||||||||||||||
token | JWT Token obtained from the Afterpay ID service | ||||||||||||||||||||||||
form | Reference to form where the hosted nonce field will be added. Useful if the Checkout button will submit the form. Note: When the value of this setting is null, then no hosted field is created, and the nonce can be retrieved from the afterpayFields.save function’s callback. | ||||||||||||||||||||||||
fields[].name | JSON path to the field | ||||||||||||||||||||||||
fields[].element | QuerySelector to the container element where the field iFrame will be created. The element has to be present when afterpayFields.initialize is called. | ||||||||||||||||||||||||
fields[].bodyStyle | CSS style passed to iFrame body style | ||||||||||||||||||||||||
fields[].fieldStyle | CSS style passed to text field style | ||||||||||||||||||||||||
fields[].iframeClassName | CSS class added to created iFrame | ||||||||||||||||||||||||
fields[].fieldFocusStyle | CSS focus style passed to text field style | ||||||||||||||||||||||||
fields[].fieldHoverStyle | CSS hover style passed to text field style | ||||||||||||||||||||||||
fields[].iframeTitle | Value passed to title attribute in iframe tag | ||||||||||||||||||||||||
fields[].placeholder | Value passed to placeholder attribute in iframe input field | ||||||||||||||||||||||||
fields[].validationRegex | Regex used for validate field value | ||||||||||||||||||||||||
fields[].numericKeypad | Boolean type parameter, if TRUE then numeric keypad will be applied on mobile devices | ||||||||||||||||||||||||
fields[].profile |
Unique profile for field type. Profile names consists of three parts, first one is preferred input, second is language and the third country. Supported profiles:
|
||||||||||||||||||||||||
fields[].googleFonts | Font name(-s) that can be fetched from google service (font names separated by |, white-spaces converted to +) |
Initialize library
The Hosted Field is initialized via JavaScript. It is recommended to do this after the page has been loaded in the browser.
The client-side library exposes three methods:
METHOD | SIGNATURE / PARAMETERS | DESCRIPTION |
---|---|---|
afterpayFields.initialize | config | Initializes the solution with the provided configuration |
afterpayFields.onError | callback function | Exposes errors received. It is highly recommended to set up error handling as the first thing in the execution line, since initialization can throw an error. |
afterpayFields.save | callback function | Saves the fields and returns the nonce. |
afterpayFields.validate | callback function |
Checks whether a field(-s) matches a regex in config and returns overall status and invalid field names. |
afterpayFields.onchange | callback function | Checks whether a field(-s) matches a validation rules based on profile name in config and returns overall status. |
document.addEventListener("DOMContentLoaded", function () {
afterpayFields.onError = function (err, message) {
console.error(err, message);
}
afterpayFields.initialize(config);
});
ERROR CODES | VALUE | DESCRIPTION |
---|---|---|
ERROR | 1 | Generic error, check browser console |
NO_FIELDS | 2 | No fields configured, configuration passed to initialization does not have the fields property set. |
NO_TOKEN | 3 | No authentication token passed in configuration |
SAVE_ERROR | 4 | Error saving fields, check browser console |
NO_CONTAINER | 5 | Unable to find the container element where the field is to be created. Check spelling or existence of the container. |
Validate Field Values
Validate function will work only if validationRegex parameter is initialized in config.
afterpayFields.validate(function (isValid, invalidFields) {
...
});
If isValid equals to TRUE: then invalidFields array is empty otherwise invalid field names will be populated.
onChange event
onChange event will return status object.
afterpayFields.onChange = function (status) {
console.log(JSON.stringify(status));
}
Validation errors
ERROR CODES | DESCRIPTION |
---|---|
400.000 | Input invalid |
400.001 | Too short |
400.002 | Too long |
400.003 | Too young |
400.004 | Too old |
400.005 | Checksum incorrect |
400.006 | Bank not found |
Status object will vary on configuration, validationRegex or profile is required to get validation result. Profiles give more options, for example 'maskedInput', 'bic' and 'bankName' for IBAN.
Save Field Contents
Saving of the field contents has to be explicit:
afterpayFields.save(function (nonce) {console.log('saved!', nonce);});
If there are multiple Hosted Fields in a form, their contents are saved in the browser’s local storage before being sent to the Hosted Fields Server.
Authorization of transaction
To complete the transaction, the merchant calls the Afterpay API authorization endpoint with small modifications.
Please refer to official documentation on how to make authorization call (https://developer.afterpay.io/guidelines). The main difference is the addition of a new request field, “nonce”. If this field is present, the customer’s identificationNumber is not required.Authorization request
{
"payment": {
...
},
"customer": {
...
},
"order": {
...
},
"nonce": "abcd1234defg", //ReceivedfromafterpayFields.savecallback
}