Appearance
Create and manage platform cards
Use createCard after the application is approved. This guide uses platform user authentication; partners should use partner card issuance.
Creating cards
The createCard mutation
graphql
mutation CreateCard($input: CreateCardInput!) {
createCard(input: $input) {
success
id
cardId
cardType
status
last4
expirationMonth
expirationYear
error
}
}Creating a virtual card
Virtual cards are available as soon as they are created.
json
{
"input": {
"cardApplicationId": 42,
"cardType": "virtual",
"limit": {
"amount": 50000,
"frequency": "per30DayPeriod"
},
"displayName": "JANE SMITH"
}
}Creating a physical card
Physical cards require a shipping address and phone number. The card ships to the provided address and must be activated upon receipt.
json
{
"input": {
"cardApplicationId": 42,
"cardType": "physical",
"limit": {
"amount": 100000,
"frequency": "per30DayPeriod"
},
"displayName": "JANE SMITH",
"shipping": {
"firstName": "Jane",
"lastName": "Smith",
"phoneNumber": "+15555551234",
"line1": "123 Main St",
"city": "Miami",
"region": "FL",
"postalCode": "33101",
"countryCode": "US",
"method": "standard"
}
}
}Input fields
| Field | Type | Description |
|---|---|---|
cardApplicationId | Int! | ID of the approved card application |
cardType | CardType! | "virtual" or "physical" |
limit | CardLimitInput | Spending limit: { amount, frequency } |
displayName | String | Name printed on card (max 26 chars, alphanumeric + spaces + periods + hyphens). Immutable after creation. |
shipping | CardShippingInput | Required for physical cards. Ignored for virtual. |
billing | CardAddressInput | Billing address. Defaults to shipping address if omitted. |
sessionId | String | From generateEncryptionKeys (required if setting PIN) |
encryptedPin | String | Pre-encrypted PIN (4-12 digits) |
Spending limit frequencies
| Frequency | Description |
|---|---|
per24HourPeriod | Rolling 24-hour window |
per7DayPeriod | Rolling 7-day window |
per30DayPeriod | Rolling 30-day window |
perYearPeriod | Rolling 365-day window |
perAuthorization | Per-transaction cap |
allTime | Lifetime total limit |
Amounts in Cents
All limit amounts are in cents. 50000 = $500.00, 100000 = $1,000.00.
Card status lifecycle
| Status | Description | Reversible |
|---|---|---|
notActivated | Issued but requires activation (physical cards) | Yes |
active | Fully functional | -- |
locked | Temporarily frozen | Yes (unfreeze) |
canceled | Permanently disabled | No |
Card management
Freeze a card
Temporarily disable a card. The card cannot be used for transactions while frozen.
graphql
mutation FreezeCard($cardId: Int!) {
freezeCard(cardId: $cardId) {
success
id
cardId
status
error
}
}Unfreeze a card
Re-enable a frozen card.
graphql
mutation UnfreezeCard($cardId: Int!) {
unfreezeCard(cardId: $cardId) {
success
id
cardId
status
error
}
}Cancel a card
Permanently cancel a card. This action is irreversible.
graphql
mutation CancelCard($input: CancelCardInput!) {
cancelCard(input: $input) {
success
id
cardId
status
error
}
}json
{
"input": {
"cardId": 42,
"reason": "No longer needed"
}
}Replace a virtual card
Generate a new card number for an existing virtual card. The old card is canceled automatically and the new card inherits spending limits.
graphql
mutation ReplaceVirtualCard($cardId: Int!) {
replaceVirtualCard(cardId: $cardId) {
success
id
oldCardId
newCard {
id
type
status
last4
expirationMonth
expirationYear
}
error
}
}Replace any card (Lost/Stolen/Damaged)
Replace a virtual or physical card with a reason code. Physical card replacements require a shipping address.
graphql
mutation ReplaceCard($input: ReplaceCardInput!) {
replaceCard(input: $input) {
success
id
oldCardId
newCard {
id
type
status
last4
expirationMonth
expirationYear
}
error
}
}json
{
"input": {
"cardId": 42,
"reason": "lost",
"shippingAddress": {
"firstName": "Jane",
"lastName": "Smith",
"phoneNumber": "+15555551234",
"line1": "123 Main St",
"city": "Miami",
"region": "FL",
"postalCode": "33101",
"countryCode": "US"
}
}
}Replacement reasons: lost, stolen, damaged.
Update spending limit
graphql
mutation UpdateCardLimit($input: UpdateCardLimitInput!) {
updateCardLimit(input: $input) {
success
id
cardId
limitAmount
limitFrequency
error
}
}json
{
"input": {
"cardId": 42,
"limitAmount": 200000,
"limitFrequency": "per30DayPeriod"
}
}Rename a card
Update the card's display nickname (max 26 characters).
graphql
mutation UpdateCardNickname($cardId: Int!, $nickname: String!) {
updateCardNickname(cardId: $cardId, nickname: $nickname) {
success
id
error
}
}PIN management
PINs are encrypted using RSA + AES-128-GCM. You must first generate an encryption session, then pass the sessionId with PIN operations.
Set or update PIN
graphql
mutation SetCardPin($input: SetCardPinInput!) {
setCardPin(input: $input) {
success
id
error
}
}json
{
"input": {
"cardId": 42,
"sessionId": "session-id-from-generateEncryptionKeys",
"encryptedPin": "encrypted-pin-value"
}
}PIN requirements: 4-12 digits, no repeated digits (e.g., 1111), no sequential patterns (e.g., 1234, 4321).
Reveal PIN
graphql
mutation GetCardPin($cardId: Int!, $sessionId: String!) {
getCardPin(cardId: $cardId, sessionId: $sessionId) {
success
id
encryptedPin
error
}
}The response encryptedPin must be decrypted client-side using the session key.
Card secrets
Reveal the full card number (PAN), CVC, and expiry. Secrets are returned encrypted and must be decrypted client-side.
graphql
mutation RevealCardSecrets($cardId: Int!, $sessionId: String!) {
revealCardSecrets(cardId: $cardId, sessionId: $sessionId) {
success
id
encryptedSecrets
error
}
}The encryptedSecrets field contains a JSON string that, when decrypted, yields:
json
{
"pan": "4111111111111234",
"cvc": "123",
"expiry": { "month": "12", "year": "2028" }
}Security
Never store decrypted card secrets. Only request them when absolutely necessary for display to the cardholder.
Listing cards
For partner integrations, use partner card queries.