# Create a Card using VGS Collect

To create a Card object in the Card Management Platform (CMP), you can use [VGS Collect](https://app.gitbook.com/s/UreALQAfVnRMQEz110rC/developer-tools/vgs-collect), a PCI-compliant form with hosted fields that securely captures card details in your web or mobile UI. Sensitive payment info such as PAN and CVC never touches your systems. Instead, VGS Collect sends the data directly to VGS, and CMP creates the card and returns a Card Object with both basic identifiers (aliases, expiration, last4) and optional enriched attributes (issuer details, card type, regulatory status).

This method:

* Uses customizable PCI-compliant hosted fields (web, iOS, Android) to securely collect card details from the end user
* Passes them through VGS Collect to create a Card Object in CMP and return PAN/CVC aliases
* Can return [enriched card attributes](https://docs.verygoodsecurity.com/cmp/products-and-services/card-attributes) in the same response if enabled in your account

### Step 1: Create a Client-Side Service Account <a href="#step-1-create-a-client-side-service-account" id="step-1-create-a-client-side-service-account"></a>

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`\
   ![](https://236204706-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fg1pA9re6lCmtaiQAnvjh%2Fuploads%2F111vPG9wjQgetkI5UMrI%2Fimage.png?alt=media\&token=60f7dba8-d8f9-4cd5-8de7-e0c2fc082c16)

#### Reference Documentation

&#x20;[Full Service Account Setup Guide](https://app.gitbook.com/s/UreALQAfVnRMQEz110rC/developer-tools/vgs-cli/service-account#using-service-accounts-via-dashboard)

### 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](https://app.gitbook.com/s/UreALQAfVnRMQEz110rC/developer-tools/vgs-collect)
* [VGS Collect Create Form](https://app.gitbook.com/s/UreALQAfVnRMQEz110rC/developer-tools/vgs-collect/js/reference-documentation#api-vgscollectcreate)

### 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](https://app.gitbook.com/s/UreALQAfVnRMQEz110rC/developer-tools/vgs-collect/js/reference-documentation#api-formfield)
* [Card Number Field](https://app.gitbook.com/s/UreALQAfVnRMQEz110rC/developer-tools/vgs-collect/js/reference-documentation#api-formfield)
* [Card Expiration Field](https://app.gitbook.com/s/UreALQAfVnRMQEz110rC/developer-tools/vgs-collect/js/reference-documentation#api-formfield)
* [CVC Field](https://app.gitbook.com/s/UreALQAfVnRMQEz110rC/developer-tools/vgs-collect/js/reference-documentation#api-formfield)

### 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.');
  }
}); 
```

### Card Object JSON Example&#x20;

```json
{
  "data": {
    "id": "CRDvM4kR5YUo3Zn8c1ZyY2vZ9",
    "type": "cards",
    "attributes": {
      "pan_alias": "tok_sandbox_918ZFABetAL717AUBzhMSx",
      "cvc_alias": "tok_sandbox_hURL8gt26jAgZhzPNgWCQi",
      "exp_month": 8,
      "exp_year": 30,
      "cardholder": {
        "name": "John Wick"
      },
      "token_type": "pan",
      "bin": "411111",
      "first8": "41111111",
      "last4": "1111",
      "card_fingerprint": "dZ9bao6fa6YWWHZSYXY7kU7UGFstmQke6hgWgCL7s6Vz",
      "capabilities": [
        "network-tokens",
        "card-updates"
      ],
      "created_at": "2025-08-27T20:09:05.456411",
      "updated_at": "2025-08-27T20:09:05.456417",
      "enriched_attributes": {
        "card_properties": {
          "card_number_length": 16,
          "card_brand": "VISA",
          "card_type": "DEBIT",
          "card_segment_type": "PERSONAL",
          "virtual_card": false,
          "prepaid_card": false,
          "product_name": "CLASSIC",
          "issuer_bin": "411111",
          "country_name": "POLAND",
          "country_numeric": 616
        },
        "card_capabilities": {
          "reloadable": false,
          "hsa": false,
          "fsa": false,
          "ebt": false
        },
        "bank": {
          "issuer_name": "CONOTOXIA SP. Z O.O"
        },
        "interchange": {
          "regulated": "N"
        }
      }
    }
  }
}
```

### 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>

### Read More

* [How to sign up on VGS to get comprehensive card attributes](https://docs.verygoodsecurity.com/cmp/products-and-services/card-attributes)
* [Account Management on the Card Management Platform](https://docs.verygoodsecurity.com/cmp/platform/cmp-account)
