Issue a Virtual Card

Virtual cards are issued instantly and are immediately active — no activation step, no physical fulfillment. This guide covers issuance, the two retrieval modes (non-sensitive and sensitive), and how to handle the card securely.

Prerequisites

🚧

Attempting to issue a card to a Cardholder with any status other than 1 (Approved) will fail. Always check status before calling the issuance endpoint if there's any possibility the cardholder hasn't been through compliance yet.


Step 1: Issue the virtual card

POST /cards/virtual/{cardholderId}

Request fields

FieldRequiredTypeConstraintsNotes
nameOnCardYesstring1–26 charsThe name that will appear on the virtual card. Defaults to the cardholder's cardHolderFirstName + cardHolderLastName if not specified — best practice is to pass it explicitly
aliasNostringA localized display alias to distinguish between a cardholder's multiple cards (e.g., "Personal Spending", "Travel Card") — visible to your application, not the card network
transactionLimitNointegerDecimal-implied; cannot exceed the cardholder's transactionLimitCard-level spending ceiling. If omitted, inherits the cardholder's limit (which itself inherits the Program's ceiling if unset)
callingCodeNostring1–3 digits, zero-padded to 3Card-specific mobile dialing code — defaults to cardholder's if not set
countryCallingCodeNostringAlpha-2Card-specific country code for phoneNum
phoneNumNostring10–20 digitsCard-specific landline — defaults to cardholder's if not set
cellNumNostring10–20 digitsCard-specific mobile — defaults to cardholder's if not set
emailAdrNostring6–50 charsCard-specific email — defaults to cardholder's if not set

Example request

{
  "nameOnCard": "JORDAN REYES",
  "alias": "Personal Spending",
  "transactionLimit": 50000
}

transactionLimit: 50000 = $500.00 in a USD-denominated Program.

Response

{
  "status": "success",
  "cardId": 8821,
  "type": "virtual",
  "maskedCardNumber": "************1234",
  "cryptoAddresses": [
    { "chain": "evm",     "address": "0x742d35Cc6634C0532925a3b8D4C9B7e..." },
    { "chain": "bitcoin", "address": "bc1qxy2kgdygjrsqtzq2n0yrf249..." },
    { "chain": "solana",  "address": "7EqQdEULxntMjTnxHhq1p9RwP..." }
  ]
}

Save cardId — it's the key for all subsequent operations on this card. Note that:

  • The card is immediately issuerCardStatus = 1 (Active) — no activation required.
  • cryptoAddresses are provisioned at this moment and ready to receive digital-asset deposits.
  • maskedCardNumber shows only the last 4 digits — to display full card details, see Step 2.

Step 2: Retrieve card details

There are two retrieval modes with different sensitivity profiles:

Non-sensitive retrieval (safe for server-side storage and display)

GET /cards/{cardId}

Returns CardViewMasked:

FieldDescription
cardIdCard ID
cardholderIdOwning cardholder
cardStatusApproval status (0 Pending · 1 Approved · 2 Declined)
issuerCardStatusOperational status (0 Pending · 1 Active · 2 On Hold · 3 Closed · 4 Not Activated)
maskedCardNumberPAN masked to last 4 digits
typevirtual or physical
aliasThe card's display alias
transactionLimitCard-level limit (decimal-implied)
cryptoAddressesFull deposit address array
contactCard-level contact details (defaults to cardholder's if not set at issuance)

This response is safe to log, store, and display in administrative UIs.

Sensitive retrieval (full PAN, expiry, CVV)

GET /cards/{cardId}/details
❗️

This endpoint returns the full, unmasked PAN and CVV in plaintext, despite the name of its underlying schema (CardDetailsMasked). Treat the response as the most sensitive data this API returns:

  • Call it only when displaying full card details directly to the cardholder (e.g., to allow manual entry into a merchant form or digital wallet) — and only over a channel meeting PCI-DSS requirements for cardholder data display.
  • Never log the response.
  • Do not persist cardNumber or cvv in your systems beyond the immediate display use case.
  • If you're building a "show my card details" UX, render the values in the client UI and discard them server-side immediately after passing them to the client — do not cache.

Returns CardDetailsMasked (the schema name notwithstanding — the actual content is fully unmasked):

FieldDescription
cardNumberFull 16-digit PAN (unmasked)
expMonthExpiry month (MM)
expYearExpiry year
cvvCVV/CVC code
cryptoAddressesDeposit address array

Step 3: Check status and balance

GET /cards/{cardId}/status       → { "issuerCardStatus": 1 }
GET /cards/{cardId}/balance      → { "ledgerBalance": 0, "availableBalance": 0, "currency": 0 }

A newly issued virtual card has zero balance. To fund it, see Fund a Card Automatically via Crypto or Fund a Card via Bank Transfer.


Issuing multiple cards to one cardholder

A single approved Cardholder can hold multiple virtual cards simultaneously. Each card has its own:

  • cardId and maskedCardNumber
  • issuerCardStatus (managed independently)
  • transactionLimit (subject to the same inheritance ceiling)
  • cryptoAddresses (unique per card)
  • alias (useful for distinguishing cards in your UI)

Use GET /cards?cardholderId={cardholderId} to list all cards for a given cardholder.


What's next