Virtual Card

Create and manage your Virtual Card.

Virtual Card

Create and manage your Virtual Card.

The Virtual Card API enables businesses and eligible personal accounts — including Personal Use — to apply for a USD Virtual Card, monitor application status, read issued-card balance/details/transactions, fund the card from Wallet or Bank, unload to Wallet, and use the card as a payment funding method. The product root mirrors Virtual Bank Account patterns under /veem/v1.2/virtual-card.

Prerequisites

Before submitting a Virtual Card application, ensure the following conditions are met:

  • The referred customer account is eligible for Virtual Card (supported countries and account types). Business and Personal accounts are supported, including Personal Use. See Virtual Card Supported Countries.
  • Business Ownership Information must be attested when required for the account type
  • Required verification documents should be uploaded through the existing account document APIs (same document model used by Virtual Bank Account). Partners can submit an application before all documents are accepted; missing or rejected documents continue to appear in validationErrors. Documents that are uploaded and pending Veem review do not appear as missing.

Veem performs additional validations before enabling a Virtual Card.

Authorization

OAuth2 token is required in the Authorization header.

📘

Headers

Three headers are required to use this endpoint.

NameTypeRequiredDescription
AuthorizationstringYesBearer token (OAuth 2.0) This header holds the bearer token required to use Veem's public API, and belongs to the owner account. Failure to use a valid bearer token will result in a 404 (Not Found) status code in the response. An example of a valid header value is as follows: Bearer c047594b-082c-4da1-be89-08fe3770f4b3.
See Get Access Token section to generate your Bearer token.
X-Request-IdstringYesThis is a unique string that identifies the current API request, and should follow the UUID format. Reusing this header without changing the value will result in a 409 (Conflict) status code in the response. An example X-request-id is as follows: 48855846-628d-4177-b071-80332a116f0a
Content-TypestringYesThe content type of the request. Must be application/json

Virtual Card Endpoints

Veem's API provides a number of endpoints that can be used to configure Virtual Card scenarios.

Use the following base URL to access the endpoints in sandbox environment.

POST https://sandbox-api.veem.com/veem/

Product root:

/veem/v1.2/virtual-card
MethodPathPurpose
POST/v1.2/virtual-cardSubmit Virtual Card application
PATCH/v1.2/virtual-cardUpdate an Initiated application draft
GET/v1.2/virtual-cardGet application status and issued cards
GET/v1.2/virtual-card/balanceList balances for all issued cards
GET/v1.2/virtual-card/balance/{fundingMethodId}Get balance for one card
GET/v1.2/virtual-card/detailsList details for all issued cards
GET/v1.2/virtual-card/details/{fundingMethodId}Get details for one card
GET/v1.2/virtual-card/transactions/{fundingMethodId}Get card transactions

Money-moving writes reuse existing Payment and Invoice routes (no separate /virtual-card/deposit product route):

MethodPathPurpose
POST/v1.2/payments/wallet/withdrawFund card from Wallet
POST/v1.2/payments/withdrawFund card from Bank, or unload card to Wallet
POST/v1.2/payments / /v1.2/claimless-payments / /v1.2/invoices/claimPay from Virtual Card
POST/v1.2/invoicesCreate invoice settling to Virtual Card

Submit Virtual Card Application

Submits a Virtual Card application for a business or eligible personal account.

POST /v1.2/virtual-card
👍

Partner Notes:

  • A partner account can be configured to make this API request on behalf of their customers. This requires internal configuration for the partner account by Veem. Once the internal configuration is enabled, the API request can be made using partner account bearer token.
  • onBehalfAccountId is an optional parameter in the request body when a partner makes an API request on behalf of their customer. This is the customer Veem account ID.
  • Successful submit creates or advances a Virtual Card regulatory application. It does not mean a Virtual Card funding method exists yet.
  • Partners do not approve applications. Observe progress with GET /v1.2/virtual-card.

Submit Virtual Card Application (Business)

{
  "onBehalfAccountId": 123456,
  "acceptTermsAndConditions": true,
  "virtualCardBusinessInfo": {
    "geographySendingCountries": "US",
    "geographyReceivingCountries": "US",
    "purposeOfAccount": "Business Virtual Card for providers",
    "monthlyExpectedActivity": 9999999.99,
    "annualRevenue": 9999999.99,
    "businessRegistrationNumber": "123",
    "businessIncorporationDate": "2010-01-01",
    "sourceOfFunds": "It Services",
    "businessWebsite": "https://mybusiness.com"
  }
}
{
  "status": "Pending",
  "virtualCardBusinessInfo": {
    "geographySendingCountries": "US",
    "geographyReceivingCountries": "US",
    "purposeOfAccount": "Business Virtual Card for providers",
    "monthlyExpectedActivity": 9999999.99,
    "annualRevenue": 9999999.99,
    "businessRegistrationNumber": "123",
    "businessIncorporationDate": "2010-01-01",
    "sourceOfFunds": "It Services",
    "businessWebsite": "https://mybusiness.com"
  },
  "validationErrors": []
}

Request Parameters

ParameterMandatoryFormat/ValuesSize/Type
onBehalfAccountIdNoReferred account ID where the Virtual Card application is submittedLong
acceptTermsAndConditionsYesMust be true on submitboolean
virtualCardBusinessInfoYes for businessBusiness regulatory information. Field meanings match the Virtual Bank Account business info shape; the wrapper name is virtualCardBusinessInfo.object
.geographySendingCountriesYesISO 3166-1 alpha-2, comma-separatedstring
.geographyReceivingCountriesYesISO 3166-1 alpha-2, comma-separatedstring
.purposeOfAccountYesPurpose of the Virtual Cardstring
.monthlyExpectedActivityYesExpected monthly activity amountBigDecimal
.annualRevenueYesAnnual revenueBigDecimal
.businessRegistrationNumberYesBusiness registration numberstring
.businessIncorporationDateYesYYYY-MM-DDdate
.sourceOfFundsYesSource of fundsstring
.businessWebsiteConditionalBusiness website URL when requiredstring

Submit Virtual Card Application (Individual / Sole Prop)

{
  "onBehalfAccountId": 123456,
  "acceptTermsAndConditions": true,
  "virtualCardIndividualInfo": {
    "geographySendingCountries": "PH",
    "geographyReceivingCountries": "US",
    "purposeOfAccount": "Contractor Virtual Card",
    "monthlyExpectedActivity": 5000.00,
    "sourceOfFunds": "Contracting income",
    "occupation": "Software Engineer"
  }
}
{
  "status": "Initiated",
  "virtualCardIndividualInfo": {
    "geographySendingCountries": "PH",
    "geographyReceivingCountries": "US",
    "purposeOfAccount": "Contractor Virtual Card",
    "monthlyExpectedActivity": 5000.00,
    "sourceOfFunds": "Contracting income",
    "occupation": "Software Engineer"
  },
  "validationErrors": [
    {
      "field": "documents.PhotoIdFront",
      "code": "REQUIRED",
      "message": "Photo ID front is required"
    }
  ]
}

Field requirements differ by account type. Use submit and status responses (validationErrors) as the source of truth for remaining gaps.

Update Virtual Card Application Information

Updates an Initiated Virtual Card application draft. This does not re-run full validation advancement the way submit does; use it to correct stored regulatory fields.

PATCH /v1.2/virtual-card
{
  "onBehalfAccountId": 123456,
  "virtualCardBusinessInfo": {
    "businessWebsite": "https://updated-business.com",
    "monthlyExpectedActivity": 25000.00
  }
}
👍

Partner Notes:

  • Rejected applications are not repaired through PATCH. Start again with a new POST /v1.2/virtual-card.
  • X-Request-Id idempotency applies to POST and PATCH the same way as other partner APIs.

Get Virtual Card Application Status

Returns the partner-facing lifecycle view for the Virtual Card application, including issued-card identifiers after completion.

GET /v1.2/virtual-card
{
  "status": "Completed",
  "virtualCardBusinessInfo": {
    "geographySendingCountries": "US",
    "geographyReceivingCountries": "US",
    "purposeOfAccount": "Business Virtual Card for providers",
    "monthlyExpectedActivity": 9999999.99,
    "annualRevenue": 9999999.99,
    "businessRegistrationNumber": "123",
    "businessIncorporationDate": "2010-01-01",
    "sourceOfFunds": "It Services",
    "businessWebsite": "https://mybusiness.com"
  },
  "validationErrors": [],
  "virtualCards": [
    {
      "accountId": 123456,
      "fundingMethodId": 55182,
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "accountName": "Business Virtual Card",
      "status": "Active",
      "currency": "USD",
      "timeCreated": 1761682203650
    }
  ]
}

Application statuses

StatusMeaning
InitiatedApplication draft exists; may include validationErrors
PendingPending Veem manual review / approval
ApprovedInternally approved; card provisioning may still be in progress
CompletedVirtual Card funding method exists; virtualCards[] is populated
RejectedRejected by Veem review or KYC; submit a new application

Issued card discovery

There is no separate public card-list endpoint. Partners discover issued cards from virtualCards[] on this response.

Use fundingMethodId as the partner card identifier for balance, details, transactions, deposit, withdrawal, payer, and payee invoice operations. Do not use external card tokens, PAN, or other card-network identifiers.

👍

Partner Notes:

  • onBehalfAccountId is an optional query string parameter for partner-on-behalf reads.
  • Responses never include PAN, CVV, or other sensitive card credentials.

Validation Errors

validationErrors may appear on GET/POST/PATCH application responses.

{
  "field": "documents.Address",
  "code": "REQUIRED",
  "message": "Proof of address is required"
}

Document readiness rules for partners:

Document stateAppears in validationErrors?
Never uploadedYes — missing document
Uploaded and pending Veem reviewNo
RejectedYes — missing document with rejection-specific wording
AcceptedNo

Internal card submission still blocks until required documents are accepted. Partner APIs intentionally hide pending-review documents from validationErrors so partners are not asked to re-upload documents that are already in review.

Get Virtual Card Balance

Balance endpoint provides the current spendable balance on the Virtual Card. Check balance before sending payments to avoid insufficient-funds failures.

GET /v1.2/virtual-card/balance
GET /v1.2/virtual-card/balance/{fundingMethodId}
{
  "accountId": 123456,
  "fundingMethodId": 55182,
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "balanceAmount": {
    "number": 950.00,
    "currency": "USD"
  },
  "timeUpdated": 1745448383244
}
👍

Partner Notes:

  • Account-level GET /balance returns 200 with an empty list before issuance.
  • Scoped GET /balance/{fundingMethodId} returns 404 when the ID is missing, not on the account, or not a Virtual Card funding method.
  • Path parameter is the Veem fundingMethodId (number), not an external card token.
  • onBehalfAccountId is an optional query string parameter for partner-on-behalf calls.

Get Virtual Card Details

Details endpoint provides operational metadata for an issued Virtual Card.

GET /v1.2/virtual-card/details
GET /v1.2/virtual-card/details/{fundingMethodId}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "fundingMethodId": 55182,
  "isoCurrencyCode": "USD",
  "status": "Active"
}
👍

Partner Notes:

  • Public details do not expose PAN, last four, CVV, or raw card-network payloads.
  • Application/funding-method lifecycle status remains on GET /v1.2/virtual-card; details status is the issued-card operational status.
  • Account-level details returns 200 with an empty list before issuance; scoped details returns 404 for invalid IDs.

Get Virtual Card Transactions

Returns date-bounded transaction history for one Virtual Card.

GET /v1.2/virtual-card/transactions/{fundingMethodId}?startDate=yyyy-MM-dd&endDate=yyyy-MM-dd&pageNumber=0&pageSize=25
{
  "content": [
    {
      "id": 1001,
      "accountId": 123456,
      "fundingMethodId": 55182,
      "paymentId": 477206,
      "transactionId": 90001,
      "amount": {
        "number": 25.00,
        "currency": "USD"
      },
      "type": "SPEND",
      "status": "COMPLETE",
      "createdAt": 1745448383244,
      "updatedAt": 1745448383244,
      "completedAt": 1745448383244,
      "date": 1745448383244,
      "originatorName": "Acme Store",
      "additionalInformation": "Card purchase"
    }
  ],
  "number": 0,
  "size": 25,
  "totalElements": 1,
  "totalPages": 1
}

Query parameters

ParameterMandatoryDescription
fundingMethodIdYesPath parameter. Partner card identifier from virtualCards[].
startDateYesyyyy-MM-dd
endDateYesyyyy-MM-dd
pageNumberNoDefault 0
pageSizeNoDefault 25, max 25
onBehalfAccountIdNoPartner-on-behalf referred account ID

Transaction types

SPEND, REFUND, FEE, DEPOSIT, WITHDRAWAL, CASH_BACK, TRANSFER, OTHER

Transaction statuses

IN_PROGRESS, COMPLETE, CLOSED

Amount and currency semantics

Rows use the amount and currency for the side of the movement that affects the card balance:

  • Incoming card movement: receiving-side amount/currency
  • Outgoing card movement: sending-side amount/currency

Responses do not expose external processor names, external transaction tokens, PAN-like values, or raw card-network JSON.

Fund Virtual Card from Wallet

Load funds from a referred-account Veem Wallet onto an issued Virtual Card.

POST /v1.2/payments/wallet/withdraw
{
  "onBehalfAccountId": 123456,
  "amount": {
    "number": 100.00,
    "currency": "USD"
  },
  "toFundingMethodType": "VirtualCard",
  "toFundingMethodId": 55182,
  "fromWalletId": 90001
}

Notes:

  • toFundingMethodType must be VirtualCard
  • toFundingMethodId is required (no default-first-card behavior)
  • Phase 1 funding is USD; existing Wallet withdraw minimums apply
  • Response is the standard public payment response; confirm with payment polling and balance reads

Fund Virtual Card from Bank

Load funds from a referred-account linked Bank funding method onto an issued Virtual Card.

POST /v1.2/payments/withdraw
{
  "onBehalfAccountId": 123456,
  "amount": {
    "number": 100.00,
    "currency": "USD"
  },
  "fromFundingMethodType": "Bank",
  "fromFundingMethodId": 175448,
  "toFundingMethodType": "VirtualCard",
  "toFundingMethodId": 55182
}

Notes:

  • fromFundingMethodType must be Bank
  • fromFundingMethodId is the linked Bank funding method ID on the referred account
  • toFundingMethodType must be VirtualCard
  • toFundingMethodId is required (no default-first-card behavior)
  • Funding is USD; existing Payment withdraw minimums apply
  • Response is the standard public payment response; confirm with payment polling and balance reads
  • This is a direct Bank → Virtual Card load. You do not need to fund a Wallet first.

Withdraw from Virtual Card to Wallet

Unload funds from an issued Virtual Card into a Wallet.

POST /v1.2/payments/withdraw
{
  "onBehalfAccountId": 123456,
  "amount": {
    "number": 50.00,
    "currency": "USD"
  },
  "fromFundingMethodType": "VirtualCard",
  "fromFundingMethodId": 55182,
  "toFundingMethodType": "Wallet",
  "toFundingMethodId": 90001
}

Notes:

  • fromFundingMethodType / fromFundingMethodId are required
  • Destination must be explicit: Wallet (toFundingMethodType + toFundingMethodId) or partner aggregated wallet sweep (sweepToWalletId)
  • Bank, card, VBA, and other destinations are out of scope for this Virtual Card unload path in Phase 1

Send Payment from Virtual Card

Use an issued Virtual Card as the payer funding method on existing payment routes:

POST /v1.2/payments
POST /v1.2/claimless-payments
POST /v1.2/invoices/claim

Set payer fundingMethod.type to VirtualCard and pass an explicit fundingMethod.id. There is no default-first-card behavior.

Create Invoice Settling to Virtual Card

POST /v1.2/invoices

Resolve the payee settlement destination to an issued Virtual Card funding method through an explicit fundingMethod or the payee account default credit method. Existing sweep precedence is unchanged:

sweepToWalletId -> sweepToVBAId -> explicit fundingMethod -> default credit method

Phase 1 does not add sweepToVirtualCardId.

Virtual Card Webhooks

For creating a webhook to be notified when a Virtual Card event occurs, use:

POST /v1.2/webhooks

In addition to the webhooks described on the Webhook Notifications page, you can subscribe to the following Virtual Card events:

EventDescription
VIRTUAL_CARD_APPLICATION_STATUS_UPDATEDNotifies when the Virtual Card application changes public status
VIRTUAL_CARD_BALANCE_UPDATEDNotifies after the canonical spendable balance is refreshed
VIRTUAL_CARD_TRANSACTIONNotifies for card-network activity (spend, refund, fee, external deposit, etc.)
📘

Subscribe using the same webhook create API as VBA. Each Virtual Card event is independently subscribable. There is no generic VIRTUAL_CARD_CHANGED event.

Virtual Card Application Status Webhook

{
  "callbackURL": "https://webhook-test.com/example",
  "event": "VIRTUAL_CARD_APPLICATION_STATUS_UPDATED"
}
{
  "type": "VIRTUAL_CARD_APPLICATION_STATUS_UPDATED",
  "data": "{\"accountId\":123456,\"status\":\"Completed\",\"updatedAt\":1745448383244}"
}
{
  "accountId": 123456,
  "status": "Completed",
  "reason": null,
  "updatedAt": 1745448383244
}
FieldDescriptionType
accountIdAccount IDLong
statusPublic application status (Initiated, Pending, Approved, Completed, Rejected)string
reasonOptional sanitized reasonstring
updatedAtUpdate timestampLong / date-time

Published on initial application creation and every persisted public-status change. Unchanged saves do not emit.

Virtual Card Balance Webhook

{
  "callbackURL": "https://webhook-test.com/example",
  "event": "VIRTUAL_CARD_BALANCE_UPDATED"
}
{
  "type": "VIRTUAL_CARD_BALANCE_UPDATED",
  "data": "{\"accountId\":123456,\"fundingMethodId\":55182,\"balance\":{\"amount\":950.00,\"currency\":\"USD\"},\"updatedAt\":1745448383244}"
}
{
  "accountId": 123456,
  "fundingMethodId": 55182,
  "balance": {
    "amount": 950.00,
    "currency": "USD"
  },
  "updatedAt": 1745448383244
}

Emitted only after Veem successfully refreshes the canonical spendable balance. Independent of the transaction or payment that caused the refresh.

Virtual Card Transaction Webhook

{
  "callbackURL": "https://webhook-test.com/example",
  "event": "VIRTUAL_CARD_TRANSACTION"
}
{
  "type": "VIRTUAL_CARD_TRANSACTION",
  "data": "{\"id\":1001,\"transactionId\":90001,\"accountId\":123456,\"fundingMethodId\":55182,\"amount\":{\"number\":25.00,\"currency\":\"USD\"},\"type\":\"SPEND\",\"status\":\"COMPLETE\",\"createdAt\":1745448383244,\"updatedAt\":1745448383244,\"completedAt\":1745448383244,\"originatorName\":\"Acme Store\",\"additionalInformation\":\"Card purchase\"}"
}
{
  "id": 1001,
  "transactionId": 90001,
  "accountId": 123456,
  "fundingMethodId": 55182,
  "amount": {
    "number": 25.00,
    "currency": "USD"
  },
  "type": "SPEND",
  "status": "COMPLETE",
  "createdAt": 1745448383244,
  "updatedAt": 1745448383244,
  "completedAt": 1745448383244,
  "originatorName": "Acme Store",
  "additionalInformation": "Card purchase"
}

Notes:

  • Delivered for card-network activity (card spend, refund, fee, externally originated deposit)
  • Wallet↔card funding and card→Wallet withdrawals initiated through Veem Payment APIs are owned by the existing payment-status webhook and do not also emit VIRTUAL_CARD_TRANSACTION
  • Exact redeliveries with the same transaction identity and status are suppressed
  • Payload omits external processor fields and paymentId
  • Transaction types/statuses match the transaction read API

Common Errors

HTTPWhen
400Invalid request body, ineligible account, invalid funding method on payment routes
404Unknown/invalid scoped card id on balance/details/transactions, or auth/account resolution failure
409Reused X-Request-Id with a different payload / conflict
5xxUnexpected server error (for example submit succeeded but application read-back failed)
)