Skip to main content

Overview

The CardClient provides methods for creating and managing virtual and physical cards. Cards are linked to ledger accounts and can be used for spending with support for multiple assets.

Accessing CardClient

import { SDK } from '@bloque/sdk';

const bloque = new SDK({
  auth: {
    type: 'apiKey',
    apiKey: process.env.BLOQUE_API_KEY,
  },
});

const user = await bloque.connect('@username');
const cardClient = user.accounts.card;

Creating Cards

Basic Card Creation

const card = await user.accounts.card.create({
  name: 'My Card',
});

console.log(card.urn);
console.log(card.lastFour);
console.log(card.status); // 'creation_in_progress'

Wait for Active Status

Use the waitLedger option to wait for the card to become active:
const card = await user.accounts.card.create(
  {
    name: 'My Card',
  },
  { waitLedger: true }
);

console.log(card.status); // 'active'
Cards can share a ledger account with other accounts (like virtual accounts or Polygon wallets):
// Create a virtual account first
const virtual = await user.accounts.virtual.create({}, { waitLedger: true });

// Create a card linked to the same ledger
const card = await user.accounts.card.create(
  {
    ledgerId: virtual.ledgerId,
    name: 'My Card',
  },
  { waitLedger: true }
);

// Both accounts now share the same balance
Linking multiple accounts to the same ledger creates a “pocket” - a shared balance that multiple payment methods can access.

Create with Metadata

const card = await user.accounts.card.create({
  name: 'Business Card',
  metadata: {
    preferred_asset: 'DUSD/6',
    default_asset: 'DUSD/6',
    department: 'marketing',
  },
});

Create with Webhook

const card = await user.accounts.card.create({
  name: 'My Card',
  webhookUrl: 'https://api.example.com/webhooks/card-events',
});

Listing Cards

List All Cards

const { accounts } = await user.accounts.card.list();

accounts.forEach(card => {
  console.log(card.urn);
  console.log(card.lastFour);
  console.log(card.productType); // 'CREDIT' | 'DEBIT'
  console.log(card.cardType);    // 'VIRTUAL' | 'PHYSICAL'
  console.log(card.status);
  console.log(card.balance);
});

Get Specific Card

const { accounts } = await user.accounts.card.list({
  urn: 'did:bloque:account:card:usr-123:crd-456'
});

const card = accounts[0];

Card Details

The CardAccount type includes:
urn
string
required
Unique resource name for the card account
id
string
required
Card account ID
lastFour
string
required
Last four digits of the card
productType
'CREDIT' | 'DEBIT'
required
Type of card product
cardType
'VIRTUAL' | 'PHYSICAL'
required
Whether the card is virtual or physical
status
AccountStatus
required
Current status: creation_in_progress, active, disabled, frozen, deleted, or creation_failed
detailsUrl
string
required
PCI-compliant URL to view full card details (number, CVV, expiration)
ownerUrn
string
required
URN of the card owner
ledgerId
string
required
Ledger account ID associated with the card
webhookUrl
string | null
Webhook URL for card events (if configured)
metadata
Record<string, unknown>
Custom metadata attached to the card
balance
Record<string, TokenBalance>
Token balances by asset (only included in list responses)

Card Operations

Get Card Balance

const balance = await user.accounts.card.balance({
  urn: 'did:bloque:account:card:usr-123:crd-456',
});

Object.entries(balance).forEach(([asset, b]) => {
  console.log(`${asset}:`);
  console.log(`  Current: ${b.current}`);
  console.log(`  Pending: ${b.pending}`);
  console.log(`  In: ${b.in}`);
  console.log(`  Out: ${b.out}`);
});

List Card Movements

const { data, pageSize, hasMore, next } = await user.accounts.card.movements({
  urn: 'did:bloque:account:card:usr-123:crd-456',
  asset: 'DUSD/6',
  limit: 50,
});

data.forEach(movement => {
  console.log(movement.type);      // 'deposit' | 'withdraw' | 'transfer'
  console.log(movement.amount);
  console.log(movement.direction); // 'in' | 'out'
  console.log(movement.status);
  console.log(movement.createdAt);
});

// Fetch next page
if (hasMore && next) {
  const nextPage = await user.accounts.card.movements({
    urn: 'did:bloque:account:card:usr-123:crd-456',
    asset: 'DUSD/6',
    next,
  });
}

Filter Movements

// Filter by direction
const incoming = await user.accounts.card.movements({
  urn: 'did:bloque:account:card:usr-123:crd-456',
  asset: 'DUSD/6',
  direction: 'in',
});

// Filter by date range
const recent = await user.accounts.card.movements({
  urn: 'did:bloque:account:card:usr-123:crd-456',
  asset: 'DUSD/6',
  after: '2025-01-01T00:00:00Z',
  before: '2025-12-31T23:59:59Z',
});

// Filter by pocket (main = confirmed, pending = pending movements)
const confirmed = await user.accounts.card.movements({
  urn: 'did:bloque:account:card:usr-123:crd-456',
  asset: 'DUSD/6',
  pocket: 'main',
});

// Filter by reference
const specific = await user.accounts.card.movements({
  urn: 'did:bloque:account:card:usr-123:crd-456',
  asset: 'DUSD/6',
  reference: '0xbff43fa587e0efa275f8b643d95881713c0f0ee13682d049cc452f607241b752',
});

Managing Cards

Update Card Metadata

const card = await user.accounts.card.updateMetadata({
  urn: 'did:bloque:mediums:card:account:123',
  metadata: {
    updated_by: 'admin',
    update_reason: 'customer_request',
  },
});
The name and source fields are reserved and cannot be modified through updateMetadata. Use updateName to change the card name.

Update Card Name

const card = await user.accounts.card.updateName(
  'did:bloque:mediums:card:account:123',
  'My Business Card'
);

Activate Card

const card = await user.accounts.card.activate(
  'did:bloque:mediums:card:account:123'
);

console.log(card.status); // 'active'

Freeze Card

const card = await user.accounts.card.freeze(
  'did:bloque:mediums:card:account:123'
);

console.log(card.status); // 'frozen'

Disable Card

const card = await user.accounts.card.disable(
  'did:bloque:mediums:card:account:123'
);

console.log(card.status); // 'disabled'

API Reference

create()

Create a new card account.
params
CreateCardParams
name
string
Display name for the card
webhookUrl
string
Webhook URL to receive card events
ledgerId
string
Ledger account ID to associate with the card
metadata
Record<string, unknown>
Custom metadata to associate with the card
options
CreateAccountOptions
waitLedger
boolean
default:false
If true, wait for the account to become active before returning
timeout
number
default:60000
Maximum time to wait in milliseconds (only applies when waitLedger is true)

list()

List card accounts.
params
ListCardAccountsParams
urn
string
URN of a specific card account to retrieve

movements()

List card account movements/transactions.
params
ListMovementsParams
required
urn
string
required
URN of the card account
asset
SupportedAsset
default:"DUSD/6"
Asset to filter transactions by
limit
number
Maximum number of transactions to return
before
string
Filter transactions before this date (ISO 8601)
after
string
Filter transactions after this date (ISO 8601)
reference
string
Filter by transaction reference
direction
'in' | 'out'
Filter by transaction direction
pocket
'main' | 'pending'
Filter by pocket: ‘main’ for confirmed, ‘pending’ for pending movements
next
string
Pagination token for fetching the next page

balance()

Get card account balance.
params
GetBalanceParams
required
urn
string
required
URN of the card account

updateMetadata()

Update card account metadata.
params
UpdateCardMetadataParams
required
urn
string
required
URN of the card account to update
metadata
Record<string, unknown>
required
Metadata to update (name and source are reserved)

updateName()

Update card account name.
urn
string
required
Card account URN
name
string
required
New name for the card

activate()

Activate a card account.
urn
string
required
Card account URN

freeze()

Freeze a card account.
urn
string
required
Card account URN

disable()

Disable a card account.
urn
string
required
Card account URN

Build docs developers (and LLMs) love