Create Virtual Card for Auth User

Create a virtual card on behalf of an authorized user on the caller's account. Pass the authorized user's authUserId (the UAC role assignment ID returned by addAuthorizedUser) to create the card for that user's underlying cardholder record while keeping the card scoped to the caller's account.

The authUserId must belong to the caller's account, must be ACTIVE, and cannot be an OWNER assignment. If addAuthorizedUser returns PENDING, the authorized user must accept the invite before this mutation can use that authUserId.

Virtual card creation can use a saved billing address (userAddressId) or an inline billingAddress. For Highnote-backed offers, providing either address value triggers billing-address registration with the card issuer before the card is issued. If issuer approval is still pending after the server-side wait window, the mutation returns GraphQL error code VC-0020 with extensions.addressId; retry with that value as userAddressId.

🔒 Restricted Access

This mutation requires a Bearer token with the CREATE_VIRTUALCARD scope.

mutation CreateVirtualCard($input: CreateVirtualCardInput!) {
  createVirtualCard(input: $input) {
    virtualCardId
    userId
    cardholderName
    expiryMonth
    expiryYear
    virtualCardLast4
    status
    cardType
    initialAmount
    usedAmount
    createdAt
    authorizationSetting {
      lockDate
      dailySpendLimit
      weeklySpendLimit
      monthlySpendLimit
    }
  }
}

Parameters

ParameterTypeRequiredDescription
inputCreateVirtualCardInput!YesWrapper object for the virtual card creation request.
input.idempotencyKeyUUID!YesUnique client-generated UUID. The same key prevents the same request from being processed more than once.
input.spendLimitFloat!YesMaximum amount that can be charged to the card. Minimum is $5; at most two decimal places are allowed.
input.offerIdUUIDYesVirtual card offer ID. Use getVirtualCardOffers to fetch active offers.
input.authUserIdUUIDNoAuthorized user ID (UAC role assignment ID) to create the card on behalf of. Must be ACTIVE and non-owner.
input.userAddressIdUUIDNoSaved billing address ID for the caller or authorized cardholder. Takes precedence over billingAddress.
input.billingAddressVirtualCardBillingAddressInputNoNew billing address to save and register with the card program before issuing the card.
input.spendLimitDurationVirtualCardSpendLimitDurationNoCard limit duration. Defaults to LIFETIME.
input.lockDateStringNoFuture lock date. Defaults to 47 months from the request date.
input.lockCardNextUseBooleanNoWhether to lock the card after the next use. Defaults to false.
input.cardNicknameStringNoCard nickname. Must be 1-50 characters when provided.
input.primaryFundingSourceVirtualCardFundingSourceNoPrimary funding source. Defaults to FLUZ_BALANCE. If BANK_ACCOUNT, bankAccountId is required.
input.bankAccountIdUUIDNoBank account ID used when primaryFundingSource is BANK_ACCOUNT.
input.userCashBalanceIdUUIDNoSpend account ID to attach to the card.
input.usePrepaymentBalanceBooleanNoWhen false, the card will not draw from prepaid balance. Defaults to true.
input.useRewardsBalanceBooleanNoWhen false, the card will not draw from rewards balance. Defaults to true.
input.memoStringNoOptional note attached to the transaction. Maximum 255 characters.
input.transactionCategoryStringNoOptional category name. A matching category is found or created for the account. Maximum 100 characters.

Response

Success Response

{
  "data": {
    "createVirtualCard": {
      "virtualCardId": "6d9f0d0f-21f0-4ad1-8fc7-2fb7dd58ce11",
      "userId": "f1320ac4-52dc-4c67-9e80-24e506b18450",
      "cardholderName": "Ada Lovelace",
      "expiryMonth": "08",
      "expiryYear": "2029",
      "virtualCardLast4": "4242",
      "status": "ACTIVE",
      "cardType": "MULTI_USE",
      "initialAmount": 100,
      "usedAmount": 0,
      "createdAt": "2026-05-15T15:18:00.000Z",
      "authorizationSetting": {
        "lockDate": "2029-08-15",
        "dailySpendLimit": null,
        "weeklySpendLimit": null,
        "monthlySpendLimit": null
      }
    }
  }
}

Response Fields

FieldTypeDescription
virtualCardIdUUIDCreated virtual card ID.
userIdUUIDUser ID of the cardholder. When authUserId is provided, this is the authorized user's user ID.
cardholderNameStringCardholder name shown on the virtual card.
expiryMonthStringVirtual card expiration month.
expiryYearStringVirtual card expiration year.
virtualCardLast4StringLast 4 digits of the virtual card number.
statusStringVirtual card status, such as ACTIVE.
cardTypeStringVirtual card type.
initialAmountFloatInitial spend limit requested for the card.
usedAmountFloatAmount already spent on the card.
createdAtDateTimeTime when the card was created.
authorizationSettingObjectAuthorization settings attached to the virtual card.

Example Requests

Create a card for an authorized user with a saved address:

curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your_access_token>" \
  -d '{
  "query": "mutation CreateVirtualCard($input: CreateVirtualCardInput!) { createVirtualCard(input: $input) { virtualCardId userId cardholderName virtualCardLast4 status cardType initialAmount usedAmount createdAt } }",
  "variables": {
    "input": {
      "idempotencyKey": "931e8841-cf23-4f36-8bf8-169384042ec2",
      "offerId": "09a9c8d1-9c4b-46fa-8a7a-508812a2a0d9",
      "authUserId": "8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d",
      "userAddressId": "1f6b2c3d-4e5f-4a67-9a10-2b3c4d5e6f70",
      "spendLimit": 100,
      "spendLimitDuration": "LIFETIME",
      "cardNickname": "Ada Travel Card",
      "primaryFundingSource": "FLUZ_BALANCE"
    }
  }
}'

Create a card for an authorized user with a new inline billing address:

curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your_access_token>" \
  -d '{
  "query": "mutation CreateVirtualCard($input: CreateVirtualCardInput!) { createVirtualCard(input: $input) { virtualCardId userId cardholderName virtualCardLast4 status cardType initialAmount usedAmount createdAt } }",
  "variables": {
    "input": {
      "idempotencyKey": "c20341f0-47e3-4d52-8361-1d7c37736b65",
      "offerId": "09a9c8d1-9c4b-46fa-8a7a-508812a2a0d9",
      "authUserId": "8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d",
      "spendLimit": 100,
      "billingAddress": {
        "streetAddressLine1": "456 Market St",
        "streetAddressLine2": "Suite 200",
        "country": "United States",
        "city": "San Francisco",
        "state": "CA",
        "postalCode": "94105"
      }
    }
  }
}'
const response = await fetch('https://transactional-graph.staging.fluzapp.com/api/v1/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    query: `
      mutation CreateVirtualCard(
        $input: CreateVirtualCardInput!
      ) {
        createVirtualCard(input: $input) {
          virtualCardId
          userId
          cardholderName
          virtualCardLast4
          status
          cardType
          initialAmount
          usedAmount
          createdAt
        }
      }
    `,
    variables: {
      input: {
        idempotencyKey: '931e8841-cf23-4f36-8bf8-169384042ec2',
        offerId: '09a9c8d1-9c4b-46fa-8a7a-508812a2a0d9',
        authUserId: '8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d',
        userAddressId: '1f6b2c3d-4e5f-4a67-9a10-2b3c4d5e6f70',
        spendLimit: 100,
        spendLimitDuration: 'LIFETIME',
        cardNickname: 'Ada Travel Card',
        primaryFundingSource: 'FLUZ_BALANCE',
      },
    },
  }),
});

const data = await response.json();

if (data.errors?.[0]?.extensions?.code === 'VC-0020') {
  const userAddressId = data.errors[0].extensions.addressId;
  console.log('Billing address pending issuer approval. Retry with userAddressId:', userAddressId);
} else {
  console.log('Virtual card created:', data.data.createVirtualCard);
}

Full Flow: Register User, Add Authorized User, Add Address, Create Card

This flow registers a new Fluz user, adds that user to the caller's account as an authorized user, saves a billing address for that authorized cardholder, then creates a virtual card on their behalf.

Step 1: Register the user. This requires a Bearer token for the developer user of an ACTIVE application with registration enabled.

curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <developer_access_token>" \
  -d '{
  "query": "mutation RegisterUser($firstName: String!, $lastName: String!, $phoneNumber: String!, $regionCode: String!, $emailAddress: String!, $dateOfBirth: String!) { registerUser(firstName: $firstName, lastName: $lastName, phoneNumber: $phoneNumber, regionCode: $regionCode, emailAddress: $emailAddress, dateOfBirth: $dateOfBirth) { success error { code message } } }",
  "variables": {
    "firstName": "Ada",
    "lastName": "Lovelace",
    "phoneNumber": "5555555555",
    "regionCode": "US",
    "emailAddress": "[email protected]",
    "dateOfBirth": "1990-01-31"
  }
}'

Step 2: Add the registered user as an authorized user on the caller's account.

curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <account_owner_access_token>" \
  -d '{
  "query": "mutation AddAuthorizedUser($email: String, $roles: [UACRoleType!]!) { addAuthorizedUser(email: $email, roles: $roles) { success authUserId roles status pendingActionId error { code message } } }",
  "variables": {
    "email": "[email protected]",
    "roles": ["SPENDER"]
  }
}'

Continue only after the returned status is ACTIVE. If the status is PENDING, the authorized user must accept the invite before addVirtualCardAddress or createVirtualCard can use the returned authUserId.

Step 3: Save the authorized user's billing address.

curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <account_owner_access_token>" \
  -d '{
  "query": "mutation AddVirtualCardAddress($input: AddVirtualCardAddressInput!) { addVirtualCardAddress(input: $input) { userAddressId streetAddressLine1 streetAddressLine2 country city state postalCode } }",
  "variables": {
    "input": {
      "authUserId": "8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d",
      "billingAddress": {
        "streetAddressLine1": "456 Market St",
        "streetAddressLine2": "Suite 200",
        "country": "United States",
        "city": "San Francisco",
        "state": "CA",
        "postalCode": "94105"
      }
    }
  }
}'

Step 4: Create the virtual card for the authorized user with the saved address.

curl -X POST https://transactional-graph.staging.fluzapp.com/api/v1/graphql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <account_owner_access_token>" \
  -d '{
  "query": "mutation CreateVirtualCard($input: CreateVirtualCardInput!) { createVirtualCard(input: $input) { virtualCardId userId cardholderName virtualCardLast4 status cardType initialAmount usedAmount createdAt } }",
  "variables": {
    "input": {
      "idempotencyKey": "931e8841-cf23-4f36-8bf8-169384042ec2",
      "offerId": "09a9c8d1-9c4b-46fa-8a7a-508812a2a0d9",
      "authUserId": "8b2c1e0a-7d4f-4a9b-9c2d-1f3e4a5b6c7d",
      "userAddressId": "1f6b2c3d-4e5f-4a67-9a10-2b3c4d5e6f70",
      "spendLimit": 100,
      "spendLimitDuration": "LIFETIME",
      "cardNickname": "Ada Travel Card",
      "primaryFundingSource": "FLUZ_BALANCE"
    }
  }
}'

Error Codes

CodeMessageDescription
ARG-0001Invalid arguments receivedRequired input is missing or invalid, spendLimit is below $5, lockDate is not in the future, offerId is invalid, authUserId is invalid, userAddressId does not belong to the account/cardholder, or BANK_ACCOUNT funding was selected without bankAccountId.
AUTH-0008Invalid user accessThe Bearer token could not be resolved to a caller. Verify the token is valid.
AUTH-0031The requested scopes must be granted by the user first.The token is missing the CREATE_VIRTUALCARD scope required to create virtual cards.
AUTH-0034No authorized user found with this id on the caller's account.The authUserId does not exist on the caller's account, is not ACTIVE, or refers to an OWNER assignment.
VC-0001Please try another payment method. If you continue experiencing issues, please contact our support team.The card could not be created or the issuer rejected the billing address.
VC-0019We are unable to get the virtual card offer. If you continue experiencing issues, please contact our support team.The requested virtual card offer could not be resolved.
VC-0020Virtual card billing address is pending approval. Please retry shortly using the returned addressId.The billing address was submitted to the issuer but was not approved before the server-side wait window ended. Retry using extensions.addressId as userAddressId.