| name | bloque-sdk-ts |
| description | Integration guide for the Bloque SDK — a TypeScript SDK for programmable financial accounts, cards with spending controls, and multi-asset transfers. Use when the user asks to "integrate Bloque", "create a card", "set up spending controls", "handle card webhooks", "transfer funds", "create pockets", "set up MCC routing", "share balances between any mediums", "same balance across pockets/cards/Polygon/bank", or build any fintech feature on the Bloque platform.
|
| license | MIT |
| metadata | {"author":"bloque","version":"1.1.0"} |
Bloque SDK Integration
TypeScript SDK for programmable financial infrastructure: identity, accounts, cards, compliance, transfers, swap, and webhooks.
When to Apply
Use this skill when:
- Integrating the Bloque SDK into a new or existing project
- Creating accounts (virtual pockets, cards, Polygon wallets, bank accounts)
- Sharing balances between any mediums — pockets, Polygon, cards, bank accounts (use the same
ledgerId)
- Setting up card spending controls (default or smart MCC routing)
- Implementing browser/mobile JWT auth and OTP login (
assert / connect / me)
- Bootstrapping a singleton authenticated SDK client in SPA apps
- Launching or resuming KYC verification flows
- Handling card transaction webhooks
- Transferring funds between accounts (single or batch)
- Creating top-ups via bank transfer (
swap.findRates + swap.bankTransfer.create)
- Building budgeting or expense-management features
- Querying balances or transaction history
SDK at a Glance
@bloque/sdk → Main package (aggregates everything)
@bloque/sdk-core → HttpClient, errors, types
@bloque/sdk-accounts → Accounts, cards, transfers
@bloque/sdk-identity → User identities and aliases
@bloque/sdk-compliance → KYC/KYB verification
@bloque/sdk-orgs → Organizations
@bloque/sdk-swap → Currency swap and bank transfers
Platforms: Node.js, Bun, Deno (API key auth) | Browser, React Native (JWT auth)
Assets: DUSD/6, COPB/6, COPM/2, KSM/12
Amounts: Always strings to preserve precision. "10000000" = 10 DUSD (6 decimals).
Country codes: Must be 3 letters (ISO 3166-1 alpha-3), e.g. USA, COL, GBR. Do not use 2-letter codes.
Wallet-Style Workflow (JWT + OTP + KYC)
Use this flow for frontend wallets similar to /projects/wallet/src:
- Create SDK with
auth: { type: 'jwt' }, platform: 'browser', origin, and optional custom baseUrl.
- For OTP login:
sdk.assert(origin, alias) to send code
sdk.connect(origin, alias, code) to establish session
sdk.me() to hydrate user profile in app state
- Initialize app-wide authenticated client once (
await sdk.authenticate()), then expose it through a singleton/provider/proxy.
- Resolve KYC:
bloque.compliance.kyc.getVerification({ urn })
- if 404 or missing
url, call bloque.compliance.kyc.startVerification({ urn })
- Use accounts/cards/swap methods through the authenticated client.
API Surface Commonly Needed in Wallet Apps
| Domain | Methods |
|---|
| Identity/Auth | assert, connect, me, authenticate |
| Accounts | accounts.get, accounts.balance, accounts.balances, accounts.movements, accounts.transactions |
| Cards | accounts.card.list, accounts.card.freeze, accounts.card.activate, accounts.card.updateName |
| Compliance | compliance.kyc.getVerification, compliance.kyc.startVerification |
| Swap/Top-up | swap.findRates, swap.bankTransfer.create |
Quick Start
import { SDK } from '@bloque/sdk';
const bloque = new SDK({
origin: process.env.ORIGIN,
auth: { type: 'apiKey', apiKey: process.env.API_KEY },
mode: 'sandbox',
});
await bloque.register('@alice', {
type: 'individual',
profile: { firstName: 'Alice', lastName: 'Smith', email: 'alice@example.com',
phone: '+1234567890', birthdate: '1990-01-01', city: 'Miami', state: 'FL',
postalCode: '33101', countryOfBirthCode: 'USA', countryOfResidenceCode: 'USA' },
});
const user = await bloque.connect('@alice');
const pocket = await user.accounts.virtual.create({}, { waitLedger: true });
const card = await user.accounts.card.create(
{ ledgerId: pocket.ledgerId, name: 'My Card' },
{ waitLedger: true },
);
References
For deeper guidance, read these files in order of relevance to the task:
| File | When to read |
|---|
references/api-reference.md | Read first for any integration. All methods, params, and exact return types. |
references/quick-start.md | First-time setup, configuration, auth strategies |
references/accounts.md | Creating pockets, Polygon wallets, bank accounts |
references/cards-and-spending-controls.md | Card creation, default/smart spending, MCC routing |
references/transfers.md | Movements, balances, and swap/bank-transfer flows |
references/webhooks.md | Handling transaction events, webhook payloads |
references/transfers.md | Moving funds, batch transfers, movement metadata |
Key Concepts
- Pockets — Virtual accounts that hold funds. Every card must be linked to a pocket via
ledgerId.
- Spending Controls —
"default" (one pocket, all merchants) or "smart" (MCC-based multi-pocket routing).
- MCC Routing — Map Merchant Category Codes to pockets. Priority order determines fallback.
- Webhooks — Async events for card transactions (authorization, adjustment). Delivered to
webhookUrl.
- Assets — Format is
SYMBOL/DECIMALS. Amounts are raw integer strings. 10 DUSD = "10000000".
- Medium-specific accounts —
user.accounts.get() and user.accounts.list() return MappedAccount (union of CardAccount, VirtualAccount, PolygonAccount, BancolombiaAccount, UsAccount). Each medium has its own shape (e.g., CardAccount has detailsUrl for card details).
- Movements are paged —
user.accounts.movements() and user.accounts.card.movements() return { data, pageSize, hasMore, next? }. Use result.data for the list of movements; use next to fetch the next page when hasMore is true. Optional param pocket: 'main' (confirmed) or 'pending'.
- Country codes — Always 3 letters (ISO 3166-1 alpha-3): e.g.
USA, COL, GBR. Use for countryOfBirthCode, countryOfResidenceCode, and any other country fields. Do not use 2-letter codes (e.g. US, CO).
Critical: Sharing Balances — Use the Same Ledger ID
To share balances between any account mediums (virtual/pocket, Polygon, card, Bancolombia, US, etc.), all of those accounts must use the same ledgerId. The ledger is the single balance pool; any accounts that share a ledgerId see the same balance and can move funds between them (e.g., crypto on Polygon → pocket → card spending, or bank deposits → same balance).
- Create one virtual account (pocket) first with
{ waitLedger: true } and capture its ledgerId.
- When creating any other medium (Polygon, card, Bancolombia, US, etc.), pass that same
ledgerId so they attach to the same ledger.
- Different
ledgerId values = separate balance pools. Same ledgerId = shared balance across all linked accounts, regardless of medium.
const pocket = await user.accounts.virtual.create({}, { waitLedger: true });
const polygon = await user.accounts.polygon.create(
{ ledgerId: pocket.ledgerId },
{ waitLedger: true },
);
const card = await user.accounts.card.create(
{ ledgerId: pocket.ledgerId, name: 'My Card' },
{ waitLedger: true },
);
Critical: Alias Consistency
The alias used in register() and connect() MUST be identical. If you register a user as '@alice', you must connect with exactly '@alice' — not 'alice', '@Alice', or any variation. A mismatch will throw a BloqueNotFoundError ("identity not found").
await bloque.register('@alice', { type: 'individual', profile: { ... } });
const user = await bloque.connect('@alice');
const user = await bloque.connect('alice');
const user = await bloque.connect('@Alice');
Rule: Pick one alias string and reuse it everywhere. Store it in a constant or environment variable.
Critical: connect() Always Succeeds
connect() always returns a session — even if register() was never called for that alias. It does NOT validate whether the identity exists. You will only discover the error later when you try to call account methods (e.g., user.accounts.card.create() will fail).
The SDK does NOT provide a "user exists" check. Your application must track whether a user has been registered before calling connect().
const user = await bloque.connect('@bob');
const card = await user.accounts.card.create();
const isRegistered = await db.users.exists('@bob');
if (!isRegistered) {
await bloque.register('@bob', { type: 'individual', profile: { ... } });
await db.users.markRegistered('@bob');
}
const user = await bloque.connect('@bob');
Rule: Never assume connect() validates the user. Always ensure register() has been called first, using your own application logic.
Error Handling
All errors extend BloqueAPIError and include requestId, timestamp, and toJSON():
| Error Class | HTTP | When |
|---|
BloqueValidationError | 400 | Invalid params |
BloqueAuthenticationError | 401/403 | Bad API key or JWT |
BloqueNotFoundError | 404 | Resource missing |
BloqueRateLimitError | 429 | Too many requests |
BloqueInsufficientFundsError | — | Not enough balance |
BloqueNetworkError | — | Connection failed |
BloqueTimeoutError | — | Request timed out |
import { BloqueInsufficientFundsError } from '@bloque/sdk-core';
try {
await user.accounts.transfer({ sourceUrn, destinationUrn, amount, asset });
} catch (err) {
if (err instanceof BloqueInsufficientFundsError) {
console.log('Not enough funds:', err.toJSON());
}
}