Overview
The Bloque SDK allows you to move funds seamlessly between any account types:
- Virtual to virtual
- Virtual to card
- Card to Polygon wallet
- And any other combination
Transfers are queued and processed asynchronously, with optional webhook notifications for completion.
Single Transfer
Transfer funds from one account to another using the transfer() method.
Initialize the SDK
Connect to a user session:import { SDK } from '@bloque/sdk';
const bloque = new SDK({
origin: process.env.ORIGIN!,
auth: {
type: 'apiKey',
apiKey: process.env.API_KEY!,
},
mode: 'production',
});
const user = await bloque.connect('@username');
Execute the transfer
Transfer funds between accounts:const result = await user.accounts.transfer({
sourceUrn: savings.urn,
destinationUrn: spending.urn,
amount: '50000000', // 50 DUSD (50 * 10^6)
asset: 'DUSD/6',
metadata: {
note: 'Weekly allowance',
},
});
console.log('Transfer queued:', result.queueId);
console.log('Status:', result.status);
Understanding Amounts
Amounts are strings (not numbers) to preserve precision. The asset format is SYMBOL/DECIMALS:
DUSD/6 means 6 decimal places
"10000000" = 10.000000 DUSD (10 dollars)
"50000000" = 50.000000 DUSD (50 dollars)
KSM/12 means 12 decimal places
"1000000000000" = 1.000000000000 KSM
Transfer to Card
You can top up a card account from a virtual account:
const card = await user.accounts.card.create(
{
name: 'My Card',
ledgerId: spending.ledgerId,
},
{ waitLedger: true },
);
const topUp = await user.accounts.transfer({
sourceUrn: savings.urn,
destinationUrn: card.urn,
amount: '25000000', // 25 DUSD
asset: 'DUSD/6',
metadata: {
note: 'Card top-up',
},
});
console.log('Card top-up queued:', topUp.queueId);
Batch Transfer
Send multiple transfers in a single operation. Perfect for:
- Payroll processing
- Splitting bills
- Distributing funds across multiple accounts
Large batches (80+ operations) are automatically chunked for you. Each chunk gets its own queue ID for tracking.
Example: Payroll Distribution
Create employee accounts
Set up accounts for the treasury and employees:const treasury = await user.accounts.virtual.create(
{ name: 'Treasury' },
{ waitLedger: true },
);
const alice = await user.accounts.virtual.create(
{ name: 'Alice' },
{ waitLedger: true },
);
const bob = await user.accounts.virtual.create(
{ name: 'Bob' },
{ waitLedger: true },
);
Execute batch transfer
Process all payments in one batch:const result = await user.accounts.batchTransfer({
reference: 'payroll-2025-02',
operations: [
{
fromUrn: treasury.urn,
toUrn: alice.urn,
reference: 'salary-alice-feb',
amount: '3000000000', // 3,000 DUSD
asset: 'DUSD/6',
metadata: { employee: 'alice', type: 'salary' },
},
{
fromUrn: treasury.urn,
toUrn: bob.urn,
reference: 'salary-bob-feb',
amount: '2500000000', // 2,500 DUSD
asset: 'DUSD/6',
metadata: { employee: 'bob', type: 'salary' },
},
],
metadata: {
department: 'engineering',
period: '2025-02',
},
webhookUrl: 'https://api.example.com/webhooks/payroll',
});
console.log(`Batch sent: ${result.totalOperations} operations in ${result.totalChunks} chunk(s)`);
for (const chunk of result.chunks) {
console.log(`Chunk ${chunk.queueId}: ${chunk.status} — ${chunk.message}`);
}
Batch Transfer Parameters
interface BatchTransferOperation {
fromUrn: string; // Source account URN
toUrn: string; // Destination account URN
reference: string; // Unique reference for tracking
amount: string; // Amount as string
asset: SupportedAsset; // e.g., 'DUSD/6', 'KSM/12'
metadata?: Record<string, unknown>;
}
Transfer Status
Transfers are processed asynchronously. The possible statuses are:
queued - Transfer is queued for processing
processing - Transfer is being processed
completed - Transfer completed successfully
failed - Transfer failed (check message for details)
Use webhooks to receive real-time notifications when transfers complete. See the Webhooks guide for setup instructions.
Error Handling
Handle transfer errors gracefully:
import { BloqueInsufficientFundsError, BloqueValidationError } from '@bloque/sdk';
try {
const result = await user.accounts.transfer({
sourceUrn: account1.urn,
destinationUrn: account2.urn,
amount: '1000000000',
asset: 'DUSD/6',
});
if (result.status === 'failed') {
console.error('Transfer failed:', result.message);
}
} catch (error) {
if (error instanceof BloqueInsufficientFundsError) {
console.error('Insufficient funds for transfer');
} else if (error instanceof BloqueValidationError) {
console.error('Invalid transfer parameters:', error.message);
} else {
console.error('Unexpected error:', error);
}
}
Best Practices
Use batch transfers for multiple operations
Instead of multiple single transfers, use batchTransfer() to process them atomically.
Include meaningful metadata
Add context to transfers with metadata for easier tracking and reconciliation.
Set up webhooks
Configure webhooks to receive completion notifications instead of polling.
Use unique references
Provide unique reference IDs for idempotency and easier debugging.