# Integration

## Set up a secure form

Let's start! First and foremost, include the JS file in your application. You can just add `<script>` element to your application or use [npm module](https://www.npmjs.com/package/@vgs/collect-js) to load the script:

> With the introduction of PCI DSS version 4.0, a new requirement has been put forth to ensure the integrity of scripts that run on payment pages. Script Integrity is crucial in maintaining the security and trustworthiness of online payment systems, as any unauthorized modifications to these scripts could potentially lead to data breaches or fraudulent activities. To meet this requirement, organizations must implement mechanisms to verify the integrity of each script utilized on their payment pages. To get a hash of a specific version, visit this [page](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/changelog#ensuring-script-integrity-for-pci-compliance).

```html
<script type="text/javascript" src="https://js.verygoodvault.com/vgs-collect/3.3.0/vgs-collect.js" integrity="sha384-YXvleED0q049Gx5rqUHI/hOTud/jKaLiL757lVq26oVFAd9SjTDHBoOviWw6XmPo" crossorigin="anonymous"></script>
```

Then build a form. In your HTML code, create an empty wrapper element with a unique identifier. This element defines the place where the iframe would be inserted. The identifier doesn't have to be the same as in the example below; you can specify any attribute value that would fit your project naming convention.

*Example:*

```html
<form id="cc-form">
  <div class="form-group">
    <label for="cc-number">Card number</label>
    <span id="cc-number">
      <!--VGS Collect.js iframe for card number field will be here!-->
    </span>
   </div>
 <!--Submit credit card form button-->
 <button type="submit">Submit</button>
</form>
```

> To help you visualize the fields and get more usage and configuration examples check out our [Storybook](https://vgs-collect-storybook.netlify.app/?path=/docs/fields-payment-card-number--cardnumberdocs).

Alternatively, we provide components that can be used ina  React application:

* [Collect.js React Wrapper](https://www.npmjs.com/package/@vgs/collect-js-react)

## Form initialization

Use the following code to initialize the VGS Collect.js form and create the form instance. You can have multiple secure forms on the page. It's required to specify the organization vault id you would like to send data to and the environment of the chosen vault.

*Example*:

```javascript
const form = VGSCollect.create('<VAULT_ID>', '<ENVIRONMENT>', (state) => {});
```

The form state object returned in the callback represents valuable information about each field. You can track validation errors, focus and blur states, and even more.

* [VGSCollect.create()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-vgscollectcreate)
* [Reference Documentation](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/reference-documentation)

## Create and setup form fields

You should initialize each field in a form using the code below. VGS Collect will create the iframe for each initialized field. The library provides multiple built-in types of inputs as well as native HTML types.

Built-in custom secure input types:

* `card-number`
* `card-expiration-date`
* `card-security-code`
* `ssn`
* `zip-code`

Built-in native secure input types: `text`, `checkbox`, `file`, `dropdown`, `password`, `textarea`.

{% tabs %}
{% tab title="Card Number" %}

```javascript
form.field('#space-for-my-field', {
  name: 'cc-number',
  type: 'card-number',
  successColor: '#3c763d',
  errorColor: '#a94442',
  placeholder: 'Card number',
  validations: ['required', 'validCardNumber'],
  autoComplete: 'cc-number',
  css: {
    'color': '#31708f',
    'line-height': '1.5rem',
    'font-size': '24px',
  }
});
```

{% endtab %}

{% tab title="SSN" %}

```javascript
form.field('#space-for-my-field', {
  type: 'ssn',
  name: 'ssn',
  validations: ['required', 'validSSN'],
  placeholder: 'XXX-XX-XXXX'
});
```

{% endtab %}

{% tab title="Dropdown" %}

```javascript
form.field('#space-for-my-field', {
  type: 'dropdown',
  name: 'car.manufacturer',
  placeholder:"Car manufacturer",
  options: [
      {value: 'volvo', text: 'Volvo'},
      {value: 'saab', text: 'Saab'},
      {value: 'opel', text: 'Opel'},
      {value: 'audi', text: 'Audi'}
  ],
  defaultValue: "volvo",
  validations: ['required']
});
```

{% endtab %}

{% tab title="Checkbox" %}

```javascript
form.field('#space-for-my-field', {
  type: 'checkbox',
  name: 'agreement',
  value: 'accept',
  validations: ['required'],
});
```

{% endtab %}

{% tab title="Textarea" %}

```javascript
form.field('#space-for-my-field', {
  type: 'textarea',
  name: 'comments',
  placeholder: 'Leave your comments here',
  validations: ['required']
});
```

{% endtab %}

{% tab title="Radio" %}

```javascript
form.field('#space-for-my-field', {
  type: 'radio',
  name: 'profile-visible',
  value: 'true',
  validations: ['required']
});
```

{% endtab %}

{% tab title="File" %}

```javascript
form.field('#space-for-my-field', {
  type: 'file',
  name: 'images',
  multiple: true,
  validations: ['required'],
  serializers: [{ name: 'toBase64' }],
  accept: ['image/*''],
  capture: 'user',
  maxFileSize: 10000,
  maxFiles: 2
});
```

{% endtab %}
{% endtabs %}

### Handling field loading state

Since Collect.js [version 2.1.0](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/changelog#version-210), you can easily monitor the loading state of each field. We recommend disabling your "submit" button until all fields are loaded; otherwise, a user would be able to make a submit request, and it may lead to unexpected results.

```javascript
const submitButton = document.getElementById('#submit-button');
submitButton.setAttribute('disabled', 'true');
const name = form.field('#space-for-my-field', {
    type: 'text',
    name: 'holder_name',
    validations: ['required'],
});
const code = form.field('#space-for-my-field', {
    type: 'text',
    name: 'code',
    validations: ['required'],
});

Promise.all([name.promise, code.promise]).then(function () {
    submitButton.removeAttribute('disabled');
})
```

You can always get the current loading status of the field using `field.loadingState`. Possible values: `loading`, `loaded`, `failed`.

* [.field()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formfield)
* [Reference Documentation](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/reference-documentation)

## Field validation

You can set up multiple validation rules based on your needs and requirements. Use `errorMessages` key in the form `state` to track down validation error messages for each field.

We **do not** change the error message text, so you can rely on it in order to overwrite the validation message the library provides.

{% tabs %}
{% tab title="Card Validation" %}

```javascript

form.field('#space-for-my-field', {
  name: 'cc-number',
  type: 'card-number',
  validations: ['required', 'validCardNumber'],
});\n
form.field('#space-for-my-field', {
  name: 'cc-cvc',
  type: 'card-security-code',
  validations: ['required', 'validCardSecurityCode']
});\n
form.field('#space-for-my-field', {
  name: 'cc-exp',
  type: 'card-expiration-date',
  validations: ['required', 'validCardExpirationDate']
});

```

{% endtab %}

{% tab title="Postal Code Validation" %}

```javascript

form.field('#space-for-my-field', {
  name: 'postal-code',
  type: 'text',
  validations: ['required', 'postal_code/us,uk'], // will check if the value is a valid US or UK zip code
});

```

{% endtab %}

{% tab title="Custom validation" %}

```javascript

form.field('#space-for-my-field', {
  type: 'card-security-code',
  name: 'card-cvc',
  validations: ['required', '/\\d{4}/'],
});

```

{% endtab %}

{% tab title="Compare two values" %}

```javascript

const ssn = form.field('#ssn', {
  type: 'ssn',
  name: 'ssn',
  validations: ['required', 'validSSN'],
});\n
const ssn2 = form.field('#ssn-confirm', {
  type: 'ssn',
  name: 'ssn-confirmation',
  validations: ['required', 'validSSN', {
    type: 'compareValue',
    params: {
      field: 'ssn',
      function: 'match',
    },
  }],
});

```

{% endtab %}
{% endtabs %}

* [.field()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formfield)
* [Reference Documentation](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/reference-documentation)

## Field update

You might need to dynamically change the configuration of an existing `Field` instance. For this use case, in Collect.js 2.5.0, we added `Field.update` method. `Field.update` accepts an object with the properties that should be updated.

List of properties that can be updated: `validations` `placeholder` `ariaLabel` `options` `css` `hideValue` `autoComplete` `disabled` `readOnly` `showCardIcon`

```javascript
const cvvField = form.field("#cc-cvv", {
  type: 'card-security-code',
  name: 'cvc',
  hideValue: true
})

onCvvVisibilityChange((isVisible) => {
  cvvField.update({
    hideValue: !isVisible
  })
});
```

* [.update()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formcardcvcfield-13)
* [Reference Documentation](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/reference-documentation)

### Events

The library provides the following event handling methods: `.on()`, `.off()`, `.once()`.

Form event example:

```typescript
const form = VGSCollect.create('<VAULT_ID>','<ENVIRONMENT>', function () {})

form.on('enterPress', (info: EnterPressData) => { submitForm(); })
```

Field event examples:

```typescript
const field = form.field('#ssn', {
  type: 'ssn',
  name: 'ssn',
  validations: ['required', 'validSSN'],
});

field.on('focus', (event) => { console.log(event) });
field.off('focus', (event) => { console.log(event) });

field.on('blur', (event) => { console.log(event) });
field.off('blur', (event) => { console.log(event) });
```

* [form.on()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formcardcvcfield-4)
* [form.off()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formcardcvcfield-5)
* [field.on()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formcardcvcfield-11)
* [field.off()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formcardcvcfield-12)
* [Reference Documentation](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/reference-documentation)

### Form submit

{% tabs %}
{% tab title="Send request to your server" %}

```javascript
form.submit('/', {
  data: {
    customerEmail: 'joe@example.com',
  },
  headers: {
  'x-application': 'MyApplication 2.8.3',
  },
  }, function(status, response) {
    console.log("Response has been received", status, response);
  }, function(errors) {
      // errors object:
      //{
      //  <invalid field name>: {
      //    <field state>
      //  },
      //}
  }
);
```

{% endtab %}

{% tab title="Send data to the Vault API" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>form.tokenize(function(status, response) {
</strong>    console.log("Response has been received", status, response);
  }, function(errors) {});
</code></pre>

{% endtab %}
{% endtabs %}

#### VGS Collect.js and Cookies

If you would like to pass cookies to your server along with the request made from the Collect.js form, make sure you've done all the steps from the list below:

* You can't share cookies across domains. You may share across subdomains. Matching rules for the domain require the cookie `Domain` to match the host to which the request is being made. Configure and use [CNAME](#vgs-collect-with-cname) in your integration with Collect.js. Your application and API must have the same origin; otherwise, the browser will not attach them to the request. Custom Hostnames allow making a Vault accessible at a non-VGS domain name (for example, [www.customdomain.com](http://www.customdomain.com)). So any requests made through VGS will now reflect your domain alias.\
  \
  Example:\
  `.myawesomesite.com` - your application domain.\
  `.vgs.myawesomesite.com` - CNAME configured and used as a request URL domain.

* Add additional `withCredentials: true` property in the `form.submit()`configuration object which will indicate that the request should be made using credentials such as cookies or authorization headers:\
  `form.submit('/my-endpoint', { ..., withCredentials: true}, callback, errorCallback)`

* Make sure you have added `SameSite=None` and `Secure` attributes to the `Set-Cookie` header:\
  `Set-Cookie: flavor=choco; Domain=.myawesomesite.com; Secure; HttpOnly; SameSite=None`

* Please also check that the server responds with the `Access-Control-Allow-Credentials` header. Responding with this header  `true` means that the server allows cookies (or other user credentials) to be included on cross-origin requests.

* [.submit()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formcardcvcfield-8)

* [Reference Documentation](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/reference-documentation)

#### Custom request body

Let's assume you have configured a Collect.js form with two fields: `card-number` and `card-cvv`, but you want them to be nested under the `card.details` property in your request, and additionally send the cardholder's name. Here's how you can do it:

```javascript
form.submit('/post', {
  data: (formValues) => {
    return {
      card: {
        cardholder: 'John',
        details: {
          card_number: formValues['card-number'],
          card_cvv: formValues['card-cvv'],
        }
      }
    }
  }
});
// JSON request body generated on the form submission:
// card: {
//  cardholder: 'John',
//  details: {
//    card_number: '4111111111111111',
//    card_cvv: '123'
//  }
//}
```

The argument in the callback has the following structure:

```javascript
{
  <field_name_1>: { __type: 'vgs-key', key: '<filed_name_1>'},
  <field_name_2>: { __type: 'vgs-key', key: '<filed_name_2>'},
}
```

By indicating `__type: 'vgs-key'` library knows that we should replace this placeholder with a real form value.

> Please use `.index(i: number)` method to access nth element of an array. Example: `formValues.images.index(0)`

* [.submit()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formcardcvcfield-8)
* [Reference Documentation](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/reference-documentation)

### Setup inbound route

To secure data via the VGS Collect.js form, you should create an inbound [route](https://docs.verygoodsecurity.com/vault/http-proxy#inbound-and-outbound-routes-definition) for the fields you want to secure. You can follow our [Getting Started](https://docs.verygoodsecurity.com/vault/http-proxy/inbound-connection) guide to find information about how to set up an inbound route properly or add a new filter to an existing route.

### VGS Collect with CNAME

Go to the `Vault Settings` on the [Dashboard](https://dashboard.verygoodsecurity.com/dashboard/v/current/settings/custom-hostnames) and add a Custom Hostname, then click on the `Activate for SDKs` button.

![Custom hostnames](https://2096104711-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUreALQAfVnRMQEz110rC%2Fuploads%2Fgit-blob-7bd079ec8b48117ab5258117bda7c038d002b748%2Fcustom_hostnames.png?alt=media)

Once the CNAME is turned on, specify the custom hostname domain using `.useCname()`  the method, and you're all set. Now, traffic will go through the defined CNAME.

**Example:**

```javascript

const form = VGSCollect.create('<VAULT_ID>', '<ENVIRONMENT>', (state) => {})
                       .useCname('my-cname.com');
  
```

* [.useCname()](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/reference-documentation#api-formcardcvcfield-2)
* [Reference Documentation](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/reference-documentation)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/js/integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
