Skip to main content

Virtual Card Express (VCX) Template

Overview

Virtual Card Express (VCX) is built for fast onboarding and minimal integration. VCX uses a subset of Highnote's issuing and funding capabilities to provide:

  • Mutations that issue a financial account and virtual card together.
  • Per-card spending limits via pseudo balance.
  • Secure card detail display using the Card Viewer SDK.

VCX is designed for issuing single-use virtual cards for invoice or AP payments.

Integration options

You have two ways to get started with VCX:

  • No-code — Contact your Highnote representative for support.
  • Low-code — Follow the steps below to integrate VCX into your application. For custom flows such as multiple card usages, complex routing, or deeply customized spend rules at issuance time, see the AP Automation template.

This guide walks through the low-code path. It explains how to create and configure a VCX card product in your Test environment.

Create a card product

Create an AP Automation card product that VCX uses for issuing virtual cards. Use AP_INVOICE_AUTOMATION as the vertical input variable:

CreateCardProduct
Query
mutation CreateCardProduct($input: CreateCardProductInput!) {
createCardProduct(input: $input) {
__typename
... on CardProduct {
id
name
usage
}
... on UserError {
errors {
errorPath
code
description
}
}
}
}
Variables
{
  "input": {
    "cardProduct": {
      "name": "AP Automation",
      "usage": "SINGLE_USE",
      "vertical": "AP_INVOICE_AUTOMATION"
    }
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"createCardProduct": {
"__typename": "CardProduct",
"id": "Y2FyZHBy",
"name": "Invoice Automation",
"usage": "SINGLE_USE"
}
},
"extensions": {
"requestId": "b85fc1ec-e770-9d06-922f-16b7486a690e"
}
}

Fund your card program

AP Automation card products use a product funding account to send funds to financial accounts. In the Test environment, you can simulate depositing funds into your product funding account without connecting a verified external bank account.

Funding your product funding account requires the following steps:

  1. Retrieve the product funding account ID.
  2. Initiate a wire transfer to the product funding account.

Find product funding account ID

Use the following query to find your product funding account ID:

GetCardProductwithAccounts
Query
query GetCardProductwithAccounts($id: ID!) {
node(id: $id) {
... on CardProduct {
__typename
id
name
usage
accounts {
edges {
node {
id
name
features {
__typename
enabled
}
accountStatus
owner {
__typename
}
}
}
}
}
}
}
Variables
{
"id": "'CARD_PRODUCT_ID"
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"node": {
"id": "<CARD_PRODUCT_ID>",
"accounts": {
"edges": [
{
"node": {
"id": "<FINANCIAL_ACCOUNT_ID>",
"features": [
{
"enabled": true,
"__typename": "ProductFundingFinancialAccountFeature"
}
]
}
}
]
}
}
},
"extensions": {
"requestId": "<REQUEST_ID>",
"rateLimit": {
"cost": 13,
"limit": 60060,
"remaining": 60041
}
}
}

Initiate a wire transfer

Simulate a wire transfer in the Test environment using the product funding account ID as the toFinancialAccountId input variable:

SimulateDeposit
Query
mutation SimulateDeposit($input: SimulateDepositInput!) {
simulateDeposit(input: $input) {
__typename
... on Transfer {
id
status
statusReason
amount {
value
currencyCode
}
createdAt
updatedAt
ledgers {
name
}
}
... on UserError {
errors {
code
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{
  "input": {
    "amount": {
      "value": 10000000,
      "currencyCode": "USD"
    },
    "source": "WIRE",
    "toFinancialAccountId": "<PRODUCT_FUNDING_ACCOUNT_ID>",
    "memo": "Consumer Credit product funding wire deposit"
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"simulateDeposit": {
"__typename": "Transfer",
"id": "<WIRE_TRANSFER_ID>",
"status": "PENDING",
"statusReason": null,
"amount": {
"value": 10000000,
"currencyCode": "USD"
},
"createdAt": "2023-09-01T22:26:43.629Z",
"updatedAt": "2023-09-01T22:26:43.629Z",
"ledgers": null
}
},
"extensions": {
"requestId": "<REQUEST_ID>",
"rateLimit": {
"cost": 12,
"limit": 60060,
"remaining": 60040
}
}
}

Enable on-demand funding

AP Automation card products use on-demand funding to fund account holder financial accounts. When you create an AP Automation card product, your product funding account is used as the source account for on-demand funding.

On-demand funding has an optional feature called pseudo balance. Pseudo balance lets you set a spending limit on a financial account to ensure account holders cannot spend over a specific amount. When a transaction is initiated for a financial account with a pseudo balance, Highnote checks the PSEUDO_BALANCE ledger to approve or decline the authorization. If the pseudo balance feature is not enabled, Highnote checks the balance of your product funding account during authorization.

Use the following mutation to enable on-demand funding with pseudo balance:

EnableOnDemandFundingFeature
Query
mutation EnableOnDemandFundingFeature(
$input: EnableOnDemandFundingFeatureInput!
) {
enableOnDemandFundingFeature(input: $input) {
__typename
... on CardProduct {
id
features {
__typename
enabled
... on OnDemandFundingCardProductFeature {
pseudoBalanceEnabled
}
}
}
... on UserError {
errors {
errorPath
code
description
}
}
}
}
Variables
{
  "input": {
    "cardProductId": "<CARD_PRODUCT_ID>",
    "pseudoBalanceEnabled": true
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"enableOnDemandFundingFeature": {
"__typename": "CardProduct",
"id": "<CARD_PRODUCT_ID>",
"features": [
{
"__typename": "CollaborativeAuthorizationCardProductFeature",
"enabled": true
},
{
"__typename": "DisputeChargebackCardProductFeature",
"enabled": true
},
{
"__typename": "OnDemandFundingCardProductFeature",
"enabled": true,
"pseudoBalanceEnabled": true
},
{
"__typename": "AuthorizedUserCardProductFeature",
"enabled": false
}
]
}
},
"extensions": {
"requestId": "f332c811-82e7-965d-b0e6-17519a7bd4b1",
"rateLimit": {
"cost": 11,
"limit": 2500,
"remaining": 2484,
"asOf": "2025-06-06T16:06:09.019Z",
"complexity": {
"limit": 2500,
"remaining": 2484,
"cost": 11
},
"count": {
"limit": 100,
"remaining": 94,
"cost": 1
}
}
}
}

Issue payment card (VCX quick start)

With VCX, you have two options when issuing a payment card:

  • VCX quick start (recommended) – one mutation to issue a financial account and a virtual payment card together.
  • Standard AP Automation flow – issue the financial account first, then issue a card for that account.

The VCX quick start mutation issues a financial account and virtual payment card in a single step from an approved application. This is the recommended approach for VCX integrations.

IssuePaymentCardForApplicationWithOnDemandFundingSource
Query
mutation IssuePaymentCardForApplicationWithOnDemandFundingSource(
$input: IssuePaymentCardForApplicationWithOnDemandFundingSourceInput!
) {
issuePaymentCardForApplicationWithOnDemandFundingSource(input: $input) {
__typename
... on PaymentCard {
id
bin
last4
expirationDate
network
status
financialAccounts {
id
}
}
... on UserError {
errors {
errorPath
code
description
}
}
}
}
Variables
{
  "input": {
    "applicationId": "<APPLICATION_ID>",
    "externalId": "INVOICE_12345",
    "options": {
      "activateOnCreate": true
    }
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"issuePaymentCardForApplicationWithOnDemandFundingSource": {
"__typename": "PaymentCard",
"id": "<PAYMENT_CARD_ID>",
"bin": "444433",
"last4": "1234",
"expirationDate": "2028-12-31T23:59:59Z",
"network": "MASTERCARD",
"status": "ACTIVE",
"financialAccounts": [
{
"id": "<FINANCIAL_ACCOUNT_ID>"
}
]
}
},
"extensions": {
"requestId": "<REQUEST_ID>"
}
}
Standard card issuing flow

To issue the financial account and card independently, use IssueFinancialAccountForApplicationWithOnDemandFundingSource followed by IssuePaymentCardForFinancialAccount. See the AP Automation template for that flow.

Initiate pseudo balance update

After issuing a card, set the pseudo balance (spending limit) for the associated financial account. This controls how much the cardholder can spend on the card.

InitiateFinancialAccountPseudoBalanceUpdate
Query
mutation InitiateFinancialAccountPseudoBalanceUpdate(
$input: InitiateFinancialAccountPseudoBalanceUpdateInput!
) {
initiateFinancialAccountPseudoBalanceUpdate(input: $input) {
__typename
... on FinancialAccountPseudoBalanceUpdate {
id
status
statusReason
createdAt
updatedAt
memo
amount {
value
currencyCode
}
}
... on UserError {
errors {
code
description
errorPath
}
}
... on AccessDeniedError {
message
}
}
}
Variables
{
  "input": {
    "financialAccountId": "<FINANCIAL_ACCOUNT_ID>",
    "amount": {
      "currencyCode": "USD",
      "value": 500000
    },
    "memo": "Set pseudo balance for INV-12345"
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"initiateFinancialAccountPseudoBalanceUpdate": {
"__typename": "FinancialAccountPseudoBalanceUpdate",
"id": "<PSEUDO_BALANCE_UPDATE_ID>",
"status": "COMPLETED",
"statusReason": null,
"createdAt": "2026-03-01T12:00:00.000Z",
"updatedAt": "2026-03-01T12:00:00.000Z",
"memo": "Set pseudo balance for INV-12345",
"amount": {
"value": 500000,
"currencyCode": "USD"
}
}
},
"extensions": {
"requestId": "<REQUEST_ID>"
}
}

For more information on managing pseudo balance limits, see On-demand Funding.

Display payment card data

With VCX, there are two methods for displaying payment card data on your website or application:

  • Use the Card Viewer SDK (recommended) - VCX low‑code pattern.
  • Fetch payment card data directly from the Highnote API - for PCI‑compliant environments only.
secure displays

Highnote recommends using the Card Viewer SDK to securely display payment card data and reduce PCI non-compliance risk.

Generate a client token

Generate a short-lived client token on your backend, then pass it to your frontend to render card details securely:

GeneratePaymentCardClientToken
Query
mutation GeneratePaymentCardClientToken(
$input: GeneratePaymentCardClientTokenInput!
) {
generatePaymentCardClientToken(input: $input) {
... on ClientToken {
value
expirationDate
}
}
}
Variables
{
  "input": {
    "paymentCardId": "<PAYMENT_CARD_ID>",
    "permissions": [
      "READ_RESTRICTED_DETAILS"
    ]
  }
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"generatePaymentCardClientToken": {
"value": "TOKEN",
"expirationDate": "2022-02-07T20:04:50.633Z"
}
},
"extensions": {
"requestId": "<REQUEST_ID>"
}
}

Integrate the Card Viewer SDK

Install the SDK:

npm install @highnote/card-viewer-sdk

Add container elements to your HTML:

<div id="card-number"></div>
<div id="card-expiration"></div>
<div id="card-cvv"></div>

Initialize the SDK with your client token:

import { renderFields } from "@highnote/card-viewer-sdk";

async function showCardDetails(clientToken) {
const viewer = await renderFields({
clientToken,
fields: {
number: {
element: document.getElementById("card-number"),
style: { fontFamily: "sans-serif", fontSize: "16px" },
},
expirationDate: {
element: document.getElementById("card-expiration"),
},
cvv: {
element: document.getElementById("card-cvv"),
},
},
onError: (error) => {
console.error("Card Viewer error", error);
},
});
}

For full configuration options, see the Card Viewer SDK documentation.

Fetch payment card data from the API

If your environment is PCI-compliant, you can fetch payment card data directly from the API:

FindPaymentCard
Query
query FindPaymentCard($id: ID!) {
node(id: $id) {
... on PaymentCard {
bin
last4
expirationDate
restrictedDetails {
... on PaymentCardRestrictedDetails {
cvv
number
}
}
}
}
}
Variables
{
"id": "<PAYMENT_CARD_ID>"
}
⚠️ Please login to execute queries. Visit the dashboard to authenticate.
Result
{
"data": {
"node": {
"bin": "BIN",
"last4": "LAST_4",
"expirationDate": "<EXPIRATION_DATE>",
"restrictedDetails": {
"cvv": "CVV",
"number": "<NUMBER>"
}
}
}
}

Simulate transactions

After configuring your card product and issuing VCX virtual cards, simulate transactions to test your card program's configuration, including on-demand funding behavior, pseudo balance enforcement, and card authorization flows.

For more information on simulating transactions, see Simulate Transactions.

Expand your integration

After configuring your card product and simulating transactions, you can use the following features to further expand your VCX integration:

  • Create spend rules to manage spending by merchant category, geography, and more.
  • Set up notifications to automate your integration and alert internal teams about card activity.
  • For a more robust solution, see the AP Automation template.