Skip to main content

Introduction

The Card API provides complete control over the card lifecycle, from ordering and activation through day-to-day management and transaction monitoring. Built with security as a priority, all sensitive operations use tokenized access patterns to ensure PCI compliance without exposing card data to your application.

Card Types

Virtual Cards

Virtual cards are issued instantly upon order completion and can be used immediately for online purchases and digital wallet integration. Characteristics:
  • Instant issuance (no physical delivery required)
  • Immediate activation after order
  • Full card details available through secure token flow
  • Supports all online and digital wallet transactions
Use Cases:
  • E-commerce purchases
  • Subscription services
  • Digital wallet integration (Apple Pay, Google Pay)
  • Instant account funding

Physical Cards

Physical card support is coming soon. Currently, only virtual cards are available.
Physical cards will provide all the benefits of virtual cards with the addition of in-person purchase capabilities. Planned Features:
  • Contactless payments (NFC)
  • ATM withdrawals
  • In-store purchases
  • Same security features as virtual cards

Card Lifecycle

Understanding the card lifecycle helps you build robust card management features:

Card States

Card is fully operational and can be used for transactions. This is the normal operating state after a card is successfully ordered and activated.Available Actions:
  • Make purchases
  • View card details
  • View/set PIN
  • Freeze card
  • View transactions
Card is temporarily disabled. All transaction attempts will be declined until the card is unfrozen. User initiated freeze for security purposes.Available Actions:
  • Unfreeze card
  • View card details (read-only)
  • View transactions
Blocked Actions:
  • Make purchases
  • Change PIN
Card is permanently disabled, typically due to fraud detection, repeated failed PIN attempts, or compliance issues. Cannot be unfrozen.Available Actions:
  • View transaction history
  • Order replacement card
Blocked Actions:
  • All card operations
  • Make purchases

Security Architecture

Token-Based Access Model

All sensitive card operations (viewing details, PIN management) use a secure token-based flow:
  1. Generate Token: Request a single-use token from the API
  2. Use Token: Present token to hosted secure page or embed in iframe
  3. Token Expires: Token is invalidated after use or timeout (~10 minutes)
Benefits:
  • Sensitive data never touches your application
  • PCI compliance without scope expansion
  • Reduced security liability
  • Built-in session management
Never attempt to store or cache sensitive card data (PAN, CVV, PIN) in your application. Always use the token-based flow for each access.

Secure Display Methods

The API uses different methods to securely display sensitive card data: Image-Based Display (Card Details & PIN Viewing)
  • Card details (PAN, CVV, expiry) delivered as secure images
  • PIN numbers displayed as secure images
  • No sensitive data touches your application
  • Simple implementation with <img> tags
  • Customizable styling to match your brand
Hosted Pages (PIN Setting Only)
  • Interactive PIN entry form
  • Built-in validation and error handling
  • Embeddable in iframe with postMessage communication
  • PCI-compliant PIN submission
// Generate token for card details or PIN viewing
const response = await fetch('/v1/card/details/token', {
  method: 'POST',
  headers: {
    'X-Client-ID': clientId,
    'Authorization': `Bearer ${accessToken}`
  },
  body: JSON.stringify({
    customCss: {
      cardBackgroundColor: '#000000',
      cardTextColor: '#FFFFFF'
    }
  })
});

const { imageUrl } = await response.json();

// Display as image
const img = document.createElement('img');
img.src = imageUrl;
img.alt = 'Card Details';
document.getElementById('container').appendChild(img);

Available Operations

Card Information

  • Check Status: Get current card state and basic details
  • View Details: Access full card number, CVV, expiry through secure token
  • Transaction History: Query past transactions with filtering

Card Control

  • Order Card: Create new virtual card for verified users
  • Freeze Card: Temporarily disable card for security
  • Unfreeze Card: Reactivate frozen card
  • Replace Card: Order replacement for blocked/lost cards (coming soon)

PIN Management

  • View PIN: Display current PIN as secure image
  • Set PIN: Create or change PIN through secure hosted page
  • Validate PIN: Verify PIN without exposing it (internal validation)

Transactions

  • List Transactions: Retrieve paginated transaction history
  • Filter Transactions: By date range, merchant, or category
  • Generate Statements: Export transactions as CSV or PDF

Prerequisites

Before using card operations, ensure:
1

User Registration & Consent

User must have completed registration including consent acceptance. During registration, users agree to terms of service and provide consent for data processing. See Consent Management for tracking requirements.
2

User Verification

User must have completed KYC and have VERIFIED status. Check user status with GET /v1/user/profile.
3

Authentication

All card endpoints require both clientId and bearerAuth (user access token).
4

No Existing Card

Users can only have one active card at a time. Check with GET /v1/card/status before ordering.
5

Funded Wallet

Ensure user has delegated wallet with sufficient balance for card operations.

Common Workflows

First-Time Card Setup

// 1. Verify user eligibility
const profile = await fetch('/v1/user/profile', {
  headers: {
    'X-Client-ID': clientId,
    'Authorization': `Bearer ${accessToken}`
  }
});

if (profile.status !== 'VERIFIED') {
  throw new Error('User must complete KYC first');
}

// 2. Check if user already has a card
const statusResponse = await fetch('/v1/card/status', {
  headers: {
    'X-Client-ID': clientId,
    'Authorization': `Bearer ${accessToken}`
  }
});

if (statusResponse.ok) {
  console.log('User already has a card');
  return;
}

// 3. Order virtual card
const order = await fetch('/v1/card/order', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Client-ID': clientId,
    'Authorization': `Bearer ${accessToken}`
  },
  body: JSON.stringify({ type: 'VIRTUAL' })
});

// 4. Wait for activation (usually instant for virtual)
const card = await fetch('/v1/card/status', {
  headers: {
    'X-Client-ID': clientId,
    'Authorization': `Bearer ${accessToken}`
  }
});

console.log(`Card ${card.id} is ${card.status}`);

Temporary Card Freeze (Lost Wallet)

// User reports wallet lost - freeze card immediately
const freezeResponse = await fetch('/v1/card/freeze', {
  method: 'POST',
  headers: {
    'X-Client-ID': clientId,
    'Authorization': `Bearer ${accessToken}`
  }
});

if (freezeResponse.ok) {
  console.log('Card frozen - all transactions will be declined');
}

// Later: User finds wallet - unfreeze card
const unfreezeResponse = await fetch('/v1/card/unfreeze', {
  method: 'POST',
  headers: {
    'X-Client-ID': clientId,
    'Authorization': `Bearer ${accessToken}`
  }
});

if (unfreezeResponse.ok) {
  console.log('Card reactivated');
}

View Card Details Securely

// 1. Generate token for viewing card details
const tokenResponse = await fetch('https://dev.api.baanx.com/v1/card/details/token', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Client-ID': clientId,
    'Authorization': `Bearer ${accessToken}`
  },
  body: JSON.stringify({
    customCss: {
      cardBackgroundColor: '#000000',
      cardTextColor: '#FFFFFF',
      panBackgroundColor: '#EFEFEF',
      panTextColor: '#000000'
    }
  })
});

const { token, imageUrl } = await tokenResponse.json();

// 2. Display as secure image
const img = document.createElement('img');
img.src = imageUrl;
img.alt = 'Card Details';
img.style.cssText = 'max-width: 100%; border-radius: 12px;';
document.getElementById('card-details-container').appendChild(img);

// 3. Clean up when user closes
function closeCardDetails() {
  img.remove();
  // imageUrl is automatically garbage collected
}

Error Handling

Common Error Scenarios

User hasn’t ordered a card yet. Direct them to the card ordering flow.
if (response.status === 404) {
  // Show "Order Card" UI
  redirectToCardOrdering();
}
Returned when attempting to order a card but user already has one.
{
  "message": "User already has a card",
  "code": "CARD_EXISTS"
}
Fetch existing card status instead of ordering new one.
User hasn’t completed KYC. They must verify identity before ordering cards.
if (response.status === 403) {
  // Redirect to KYC flow
  redirectToVerification();
}
Operation not allowed in current card state (e.g., trying to unfreeze an active card).
{
  "message": "Card is not frozen",
  "code": "INVALID_STATE"
}
Check card status before operations.

Best Practices

Security

Always use HTTPS for all API calls
Never log or store sensitive card data
Implement token expiration handling
Use CSP headers when embedding hosted pages
Validate user authentication before card operations

User Experience

Show clear status indicators for card state
Provide transaction history for transparency
Allow easy freeze/unfreeze for security
Display last 4 digits for card identification
Offer statement downloads for record keeping

Performance

Cache card status locally with reasonable TTL
Use pagination for transaction history
Implement optimistic UI updates for freeze/unfreeze
Lazy load transaction details on demand

Next Steps