# Collect Card Data from User

## Collect Card Data with VGS

In an agentic system, card data must be collected in a secure and compliant way **without exposing raw PAN or CVC to your systems or AI agents**. This page shows you how to use `VGS Collect` to securely collect, tokenize, and store card data with full PCI compliance.

This method:

* Uses customizable PCI-compliant hosted fields
* Creates a Card Object along with VGS Aliases for the PAN and CVC fields
* Authenticates via backend-generated JWT (using a minimally-scoped service account)

***

### Step 1: Create a Client-Side Service Account

1. Navigate to the Service Accounts section of the VGS Dashboard: Vault > Organization > Service Accounts.
2. Click on the Create New button.
3. Select your Vault and add the following scopes: `cards:write`  & `network-tokens:write`&#x20;

<figure><img src="/files/zlu4tsUBroHgOdqzmpOo" alt=""><figcaption></figcaption></figure>

#### Reference Documentation

&#x20;[Full Service Account Setup Guide](/cmp/platform/authentication.md)

***

### Step 2: Backend – Generate JWT to be used with Collect Form

Your backend must generate a short-lived JWT signed with your service account's private key. This token will be used by the frontend to authenticate to your account during form submission.

Below is a sample ExpressJS server that can be used to generate the JWT.

{% tabs %}
{% tab title="server.js" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>// sample-agentic-app
</strong><strong>// `npm start` to run
</strong><strong>
</strong><strong>const express = require('express');
</strong><strong>const axios = require('axios');
</strong>const cors = require('cors');
require('dotenv').config();

const app = express();
const PORT = process.env.PORT || 3030;

app.use(cors());
app.use(express.static('public')); // serve frontend

const CLIENT_ID = process.env.VGS_CLIENT_ID;
const CLIENT_SECRET = process.env.VGS_CLIENT_SECRET;
const TOKEN_URL = 'https://auth.verygoodsecurity.com/auth/realms/vgs/protocol/openid-connect/token';

app.get('/get-collect-token', async (req, res) => {
  try {
    const params = new URLSearchParams();
    params.append('client_id', CLIENT_ID);
    params.append('client_secret', CLIENT_SECRET);
    params.append('grant_type', 'client_credentials');

    const response = await axios.post(TOKEN_URL, params);
    res.json({ access_token: response.data.access_token });
  } catch (error) {
    console.error('Error getting VGS token:', error.response?.data || error.message);
    res.status(500).json({ error: 'Failed to get token' });
  }
});

app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
});
</code></pre>

{% endtab %}

{% tab title=".env" %}

```bash
VGS_CLIENT_ID=example-client-id
VGS_CLIENT_SECRET=example-client-secret
```

{% endtab %}

{% tab title="package.json" %}

```json
{
  "name": "sample-agentic-app",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "axios": "^1.6.7",
    "cors": "^2.8.5",
    "dotenv": "^16.4.5",
    "express": "^4.18.2"
  }
}

```

{% endtab %}
{% endtabs %}

### Step 3: Frontend – Instantiate the Form

Load the VGS Collect library and instantiate the form:

```javascript
const VAULT_ID = "tntsample"; // replace with your Vault ID
const ENVIRONMENT = "sandbox";

const form = VGSCollect.create(VAULT_ID, ENVIRONMENT, () => { console.log("Form created") });
```

#### Reference Documentation

* [VGS Collect Overview](/vault/developer-tools/vgs-collect.md)
* [VGS Collect Create Form](/vault/developer-tools/vgs-collect/js/integration.md)

### Step 4: Create Form Fields

Use the built-in card field types to render secure, styled input fields:

{% tabs %}
{% tab title="Front-end JS" %}

```javascript
const VAULT_ID = "tntsample"; // replace with your Vault ID
const ENVIRONMENT = "sandbox";

const form = VGSCollect.create(VAULT_ID, ENVIRONMENT, () => { console.log("Form created") });

const css = {
  "vertical-align": "middle",
  "white-space": "normal",
  "background": "none",
  "font-family": "sofia, arial, sans-serif",
  "font-size": "16px",
  "color": "rgb(34, 25, 36)",
  "line-height": "normal",
  "padding": "0px 1em",
  "box-sizing": "border-box",
  "&::placeholder": {
    "color": "#6A6A6A"
  },
};

form.cardholderNameField('#cardholder-name', { placeholder: 'Jane Doe', css: css });
form.cardNumberField('#card-number', { placeholder: '4111 1111 1111 1111', css: css });
form.cardExpirationDateField('#card-expiration', { placeholder: 'MM / YY', css: css });
form.cardCVCField('#card-cvc', { placeholder: '123', css: css });
```

{% endtab %}

{% tab title="HTML" %}

```html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css"
    integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  <link rel="stylesheet" href="./styles.css">
  <title>VGS Agentic Card Form</title>
</head>

<body>
  <div class="container pt-4">
    <div class="row">
      <div class="col-md">
        <div>
          <div id="cardholder-name" class="field-wrapper"></div>
        </div>
        <div>
          <div id="card-number" class="field-wrapper"></div>
        </div>
        <div>
          <div id="card-expiration" class="field-wrapper"></div>
        </div>
        <div>
          <div id="card-cvc" class="field-wrapper"></div>
        </div>

        <button id="submit-btn" class="submit-btn">Collect Card</button>

      </div>
    </div>
  </div>

  <script type="text/javascript" src="https://js.verygoodvault.com/vgs-collect/3.2.1/vgs-collect.js"></script>
  <script src="script.js"></script>
</body>

</html>
```

{% endtab %}
{% endtabs %}

#### Reference Documentation

* [Cardholder Name Field](/vault/developer-tools/vgs-collect/js/integration.md#create-and-setup-form-fields)
* [Card Number Field](/vault/developer-tools/vgs-collect/js/integration.md#card-number)
* [Card Expiration Field](/vault/developer-tools/vgs-collect/js/integration.md#create-and-setup-form-fields)
* [CVC Field](/vault/developer-tools/vgs-collect/js/integration.md#create-and-setup-form-fields)

### Step 5: Create a Card

When the user submits the form, call `form.createCard(...)` and pass the backend-generated JWT from Step 2 into the createCard function.

```javascript
document.getElementById('submit-btn').addEventListener('click', async () => {
  try {
    const res = await fetch('/get-collect-token');
    const { access_token } = await res.json();

    const response = await form.createCard({
      auth: access_token,
      data: {
        "cardholder": {}
      }
    },
      function (status, card_object) {
        alert('Card created. Check your console for the details.');
        console.log("Card ID: " + card_object.data.id);
        console.log("PAN Alias: " + card_object.data.attributes.pan_alias);
        console.log("CVC Alias: " + card_object.data.attributes.cvc_alias);
        console.log('Card Object: ', card_object.data);
      },
      function (e) {
        alert('Card creation failed. Check your console for the details.');
        console.log("Error", e);
      });
  } catch (err) {
    console.error('Error:', err);
    alert('Card creation failed. Check console.');
  }
}); 
```

### Using the Card Object for Payments

The `createCard` function will provide a card object to your front-end. Below are the key elements of the card object to use for payments and additional services.

<table data-full-width="true"><thead><tr><th width="111.39068603515625">Name</th><th width="258.729248046875"></th><th>JSON Path</th></tr></thead><tbody><tr><td>Card ID</td><td><p>This is the main identifier forthe card object. It can be used to reference the card using the card GET endpoint as-needed in the future.</p><p></p><p>This value will remain constant even if the underlying card details change using card services.</p></td><td><code>card_object.data.id</code></td></tr><tr><td>PAN Alias</td><td><p>This is a unique token that represents the exact value of the card number (PAN). This value can change when VGS receives an update to the card number using the VGS Account Updater service.</p><p></p><p>This value can be used with the VGS Outbound Proxy when you wish to share the original PAN with a third-party.</p></td><td>`<code>card_object.data.attributes.pan_alias</code></td></tr><tr><td>CVC Alias</td><td>This is a unique token that represents the exact value card number (PAN). This value can be used with the VGS Outbound Proxy when you wish to share the original PAN with a third-party PSP or other payment system.<br><br>Because the CVC is considered "SAD" (Sensitive Authentication Data) according to PCI-DSS regulations, this value can only be used as a reference for 1 hour.</td><td>`<code>card_object.data.attributes.cvc_alias</code></td></tr><tr><td>Expiration Date</td><td>The expiration date of the card. This value will be required for issuing PSP tokens and performing payments.</td><td><code>card_object.data.attributes.exp_month</code><br><code>card_object.data.attributes.exp_year</code></td></tr></tbody></table>

<details>

<summary>Card Object JSON Sample</summary>

```json
{
  "data": {
    "id": "CRDecqZp3xRgXU3TFmtcDdzQs",
    "type": "cards",
    "attributes": {
      "pan_alias": "tok_abcdefghijklmnop",
      "cvc_alias": "tok_zbcdefgh",
      "cvc_status": "active",
      "bin": "411111",
      "first8": "41111111",
      "last4": "1111",
      "exp_month": 5,
      "exp_year": 28,
      "card_fingerprint": "6TeSCB16LtyifEAmY2goxYfSk5sALriXpefzzxh29xhu",
      "capabilities": [
        "network-tokens",
        "card-updates"
      ],
      "created_at": "2025-08-01T00:00:00Z",
      "updated_at": "2025-08-01T00:00:00Z"
    },
    "meta": {
      "token_type": "pan"
    }
  }
}
```

</details>


---

# 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/agentic-commerce/collect-card-data-from-user.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.
