Add your own fields

You can add your own HTML fields to capture additional information about the customer or the transaction, for example, address information for the address verification service (AVS). After you capture the customer’s address information, you can send it in the payment request.

Important: If you add your own HTML fields, you are responsible for handling the additional information that you capture.

To help you understand how to add your own fields, we have created a worked example that you can follow. In our example, we capture billing details from the customer and then use the billing details in the payment request.

In our example, we complete the following actions:

  1. Add our own HTML fields.
  2. Validate the data in the fields.
  3. Handle the response.
  4. Retrieve the data from the fields.
  5. Create a payment request.

Step 1. Add your own HTML fields

In the following code block, we created a <div> to capture the customer’s billing details and an error message for each required field.

1 <div class="billing-details">
2 <!-- First Name and Last Name -->
3 <div class="row" style="margin-bottom: -13px;">
4 <div>
5 <label for="firstName">First Name</label>
6 <input class="input-box" type="text" id="firstName" required="">
7 <div class="error" id="firstName-error">*Required</div>
8 </div>
9 <div>
10 <label for="lastName">Last Name</label>
11 <input class="input-box" type="text" id="lastName" required="">
12 <div class="error" id="lastName-error">*Required</div>
13 </div>
14 </div>
15 <!-- Street Address 1 -->
16 <div>
17 <label for="address1">Street Address</label>
18 <input class="input-box" type="text" id="address1" required="">
19 <div class="error" id="address1-error">*Required</div>
20 </div>
21 <!-- Street Address 2 -->
22 <div>
23 <label for="address2">Street Address 2</label>
24 <input class="input-box" type="text" id="address2">
25 <div></div>
26 </div>
27 <!-- City and Postal Code -->
28 <div class="row" style="margin-bottom: -13px;">
29 <div>
30 <label for="city">City</label>
31 <input class="input-box" type="text" id="city" required="">
32 <div class="error" id="city-error">*Required</div>
33 </div>
34 <div>
35 <label for="postalCode">Post Code</label>
36 <input class="input-box" type="text" id="postalCode" required="">
37 <div class="error" id="postalCode-error">*Required</div>
38 </div>
39 </div>
40 <!-- Country-->
41 <div class="container">
42 <label for="country">Country</label>
43 <select class="input-box" id="country">
44 <option value="GB">Great Britain (GB)</option>
45 <option value="IE">Republic of Ireland (IE)</option>
46 <option value="US">United States (US)</option>
47 <option value="CA">Canada (CA)</option>
48 <option value="BR">Brazil (BR)</option>
49 </select>
50 </div>
51 </div>

Step 2. Validate the data in the fields

We use the onPreSubmit function to validate the data that the customer provides in our fields. If the field is empty or if the data doesn’t match the format that we specify, the JS library doesn’t submit the form to our gateway.

To use the onPreSubmit function in our worked example, we complete the following actions:

Step 2a. Add the onPreSubmit function.
Step 2b. Define the onPreSubmit function.

Step 2a. Add the onPreSubmit function

To delay the submission of the form until we validate the data the customer provides, we add the onPreSubmit function.

In the following code block, we add the onPreSubmit function.

1 this.form = new Payroc.hostedFields({
2 sessionToken: sessionRequest['token'],
3 mode: scenario,
4 fields: fields,
5 // Add the onPreSubmit function to validate the data in the fields before the JS Library sends the request to our gateway.
6 onPreSubmit: () => this.validateCustomerDetails(),
7 });

Step 2b. Define the onPreSubmit function

We define the onPreSubmit function to specify the format and rules for the values that the customer must enter into the fields. If the field is missing a value, we call a displayMissingFieldsError function to display the error.

In the following code block, we check if the customer provides a value for each field.

1 async validateCustomerDetails() {
2 // Check if the .billing-details is present, and returns false if there are no values in any of the fields.
3 const customerDetails = document.querySelector(".billing-details");
4 if (!customerDetails) return false;
5
6 let validation = true;
7 // Retrieve all values from inside the .billing-details div
8 const requiredFields = customerDetails.querySelectorAll("input[required]");
9 for (const field of requiredFields) {
10 // Check that the customer has provided a value for each field and that the value is in the correct format.
11 if (!field.value.trim()) {
12 // Call a function to display any errors.
13 displayMissingFieldsError(field.id);
14 validation = false;
15 }
16 }
17 // If the values are present and in the correct format, the JS Library sends the request to our gateway.
18 return validation;
19 }

displayMissingFieldsError function

If the customer doesn’t enter a value in a field, the displayMissingFieldsError function displays an error for five seconds.

1 function displayMissingFieldsError(id) {
2 const input = document.getElementById(id);
3 // Locate the element that contains the error.
4 const errorMessage = document.getElementById(id + "-error");
5 input.classList.add('invalid');
6
7 errorMessage.style.visibility = 'visible'; // Show the error message.
8 setTimeout(() => {
9 input.classList.remove('invalid');
10 errorMessage.style.visibility = 'hidden'; // Hide the error message after five seconds.
11 }, 5000); // 5000 ms = 5 seconds
12 }

Step 3. Handle the response

If the onPreSubmit function validates the values that the customer provides the JS library sends the request to our gateway, which returns a single-use token in the response.

In the following code block, we handle the response and close the Hosted Fields session.

1 this.form.on("submissionSuccess", async ({ token, expiresAt }) => {
2 // Get the customer object using the data that the customer provided.
3 const customer = this._getCustomerObject();
4 // Forward all the required data to the server to create a payment request.
5 const response = scenario === "payment"
6 ? await yourServer.createPayment(customer, token)
7 : await yourServer.createSecureToken(customer, token);
8
9 // Close the Hosted Fields session and display a response.
10 document.querySelector('.billing-details').style.display = "none";
11 document.querySelector(".pyrc-hosted-fields").style.display = "none";
12 this._renderJSONResponse(response);
13 });

Step 4. Retrieve the data from the fields

After we sent the request and received the single-use token, we use the information from the form to create a payment request.

In the following code block, we retrieve the billing details that the customer provides and organize them into a billingAddress object.

1 // Retrieve the data from the fields and organize them into a billingDetails object within a customer object.
2 _getCustomerObject() {
3 let data = {};
4 const billingAddress = this._getCustomFieldValues();
5 if (Object.keys(billingAddress).length > 0) data['billingAddress'] = billingAddress;
6 return data;
7 }
8
9 _getCustomFieldValues() {
10 const fields = document.querySelectorAll(".billing-details input, .billing-details select");
11 const values = {};
12
13 fields.forEach(field => {
14 const value = field.value;
15 if (value) values[field.id] = value.trim();
16 });
17
18 return values;
19 }

Step 5. Create payment request

We add the information that we received from the customer and the single-use token to a payment request, and then send the payment request to our gateway. For more information about how to create a payment request, go to Run a card sale.

In the following code block, we create a payment request using the billing details that the customer provides and the single-use token that we receive from the gateway.

1{
2 "channel": "web",
3 "processingTerminalId": "{TerminalID}",
4 "order": {
5 "orderId": "{OrderId}",
6 "amount": 4999,
7 "currency": "USD"
8 },
9 "customer": {
10 "firstName": "Joe",
11 "lastName": "Bloggs",
12 "billingAddress": data['billingAddress']
13 },
14 "paymentMethod": {
15 "secCode": "web",
16 "token": "{single use token}",
17 "type": "singleUseToken"
18 }
19}