# Virtual Accounts ## Create Virtual Account - [POST /v1/virtual-accounts](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccounts_post.md): Creates one or more virtual (sub) accounts for a corporate client. Virtual accounts allow funds to be segregated and tracked independently while remaining linked to a single settlement account. Required Request Properties - items: Array of virtual account creation requests (minimum 1, maximum 1000) - currency: ISO-4217 currency code for the virtual account (e.g., USD, BMD) - accountHolderName: Human-readable label for the virtual account (required unless unallocated is true). Immutable after first update. - accountName: Official account title that will appear on statements (required unless unallocated is true). Immutable after first update. Optional Request Properties - unallocated: When set to true, creates the account in "for allocation" mode with placeholder values ("UNALLOCATED") for accountHolderName and accountName. This allows bulk pre-creation of virtual accounts for later assignment to end-customers via a one-time PATCH update. - dob: Date of birth of the account holder, if applicable. Immutable after first update. - nativeLanguageName: Native name of the account holder's language, if applicable. Immutable after first update. - callbackUrl: URL to receive notifications when the batch job completes (optional) - clientReference: External reference provided by the client to aid reconciliation (max 35 characters) - per item - customHeaders: Object of string key/value pairs to be echoed back in the completion callback. Limits: up to 10 headers; each key ≤ 50 characters; each value ≤ 500 characters. ### Unallocated Accounts Operationally, clients often need to pre-create many virtual accounts to allocate later. The unallocated flag enables a safe "for allocation" mode: - Creates accounts with generic placeholder values: "UNALLOCATED" for accountHolderName and accountName - When unallocated is true, the accountHolderName and accountName fields become optional - Allows a one-time update via PATCH when the account is assigned to a real end-customer - Important: The following fields are immutable after the first update: accountHolderName, accountName, dob, and nativeLanguageName ### Asynchronous Processing Virtual account creation requests are processed asynchronously to ensure optimal performance and reliability: - Immediate Response: You receive a job ID and status URLs immediately upon submission - Status Monitoring: Use the provided status URL to monitor job progress - Result Retrieval: Use the provided result URL to fetch final outcomes when complete - Callback Notifications: Optionally provide a callback URL for automatic notifications afther job completes ### Message Signing Callback notifications are signed. When your client configuration enables response signing, callbacks use the asymmetric option (RSA-PSS + SHA-256) and include Bcb-Signature, Bcb-Timestamp, Bcb-Nonce, and Bcb-Signature-Version (e.g., rsa-v1). If asymmetry is not configured, callbacks use the HMAC option with your Message Signing Secret and no Bcb-Signature-Version header. See the Message Signing guide for verification steps. ### Virtual Account Structure Each successfully created virtual account will contain the following properties: json { "virtualAccountNumber": "1000327642", "bicCode": "BPBKBMHMXXX", "accountHolderName": "T1 Project Alpha Escrow", "accountName": "New Title T2", "currency": "USD", "balance": { "amount": "0", "currency": "USD" }, "category": "CMS Sub Acct" } ### Job Status Tracking The response includes URLs for monitoring your batch job: - Status URL: Poll this URL to check job progress and completion status - Result URL: Access this URL to retrieve detailed results for each virtual account - Job ID: Unique identifier for tracking your batch job ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided, the system stores the key and associates it with the batch job - If the same idempotency key is received again, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000") ### Sample Request in JavaScript javascript async function createVirtualAccounts() { try { const response = await fetch('https://api.bcb.bm/v1/virtual-accounts', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional }, body: JSON.stringify({ callbackUrl: 'https://my-callback-url.com', // Optional // Optional: custom headers echoed in the completion webhook customHeaders: { 'X-Custom-Header-1': 'CustomValue1', 'X-Custom-Header-2': 'CustomValue2', 'X-Custom-Header-3': 'CustomValue3' }, items: [ { currency: 'USD', accountHolderName: 'Test Company Ltd', accountName: 'Test Virtual Account 001', clientReference: 'BATCH-REF-001' }, { currency: 'USD', accountHolderName: 'Test Company Ltd', accountName: 'Test Virtual Account 002', clientReference: 'BATCH-REF-002' }, // Example: Pre-create unallocated accounts for later assignment { currency: 'USD', unallocated: true, clientReference: 'UNALLOC-001' } ] }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Virtual account creation failed: ${JSON.stringify(errorData)}); } // Parse JSON response const batchResponse = await response.json(); // Display batch job information console.log('Batch Job Created:'); console.log( Job ID: ${batchResponse.jobId}); console.log( Status: ${batchResponse.status}); console.log( Status URL: ${batchResponse.statusUrl}); console.log( Result URL: ${batchResponse.resultUrl}); // Store these URLs for monitoring the job // Use statusUrl to check progress // Use resultUrl to get final outcomes return batchResponse; } catch (error) { console.error('Failed to create virtual accounts:', error.message); throw error; } } // Example usage: // Create multiple virtual accounts createVirtualAccounts(); Required Permission: create-virtual-account This endpoint requires the permission claim create-virtual-account to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Get All Virtual Accounts - [GET /v1/virtual-accounts](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccounts_getall.md): Retrieves all virtual accounts for the authenticated corporate client. This endpoint: - Returns a paginated list of virtual accounts for the client - Response contains the client’s real (non-virtual) accounts as well: - Settlement Account – the primary clearing account used for cash movements. Account category: "CMS Settlement". - Parent Account – the parent account under which all virtual accounts are organised. Account category: "CMS Parent Cate". - Virtual accounts have the category "CMS Sub Acct". - Supports optional currency filtering to return only accounts in a specific currency - Supports pagination for efficient handling of large account datasets ### Filtering Use the optional currency query parameter to filter results: - Must be a valid 3-letter ISO currency code (e.g., USD, BMD, EUR) - If omitted, accounts in all currencies are returned ### Pagination This endpoint uses cursor-based pagination with server-side result-set management: - First Request: Optionally specify pageSize (default: 100, max: 1000). The server creates a cursor and returns a pageToken. - Subsequent Requests: Use the pageToken from previous responses with pageStart to navigate pages. - Page Token: Contains encoded pagination context including pageSize, so don't specify pageSize in subsequent requests. - Total Pages: Calculate using Math.ceil(total_size / page_size) from the response metadata. ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts ### Sample Request in JavaScript javascript async function getAllVirtualAccounts(currency = null, pageSize = 25, pageStart = 1, pageToken = null) { try { // Build URL with optional parameters let url = 'https://api.bcb.bm/v1/virtual-accounts'; const params = new URLSearchParams(); if (currency) { params.append('currency', currency); } if (pageStart === 1 && !pageToken) { // First request only: optionally specify pageSize params.append('pageSize', pageSize.toString()); } else { // Subsequent requests: use pageToken + pageStart and do NOT send pageSize again params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } url += '?' + params.toString(); const response = await fetch(url, { method: 'GET', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Virtual accounts retrieval failed: ${JSON.stringify(errorData)}); } // Parse JSON response const result = await response.json(); // Access pagination info const pagination = result.meta.pagination; console.log(Page: ${pagination.page_start}, Size: ${pagination.page_size}, Total: ${pagination.total_size}); // Process virtual accounts result.data.forEach((account, index) => { console.log(Account ${index + 1}:); console.log( Virtual Account Number: ${account.virtualAccountNumber}); console.log( BIC: ${account.bicCode}); console.log( Account Holder: ${account.accountHolderName}); console.log( Account Name: ${account.accountName}); console.log( Currency: ${account.currency}); console.log( Balance: ${account.balance ? account.balance.amount + ' ' + account.balance.currency : 'N/A'}); console.log( Category: ${account.category}); if (account.clientReference) { console.log( Client Reference: ${account.clientReference}); } if (account.effectiveDate) { console.log( Effective Date: ${account.effectiveDate}); } if (account.createdAt) { console.log( Created At: ${account.createdAt}); } // Log parent/settlement account relationships if (account.parentAccount) { console.log( Parent Account: ${account.parentAccount.accountNumber} (${account.parentAccount.accountName})); } if (account.settlementAccount) { console.log( Settlement Account: ${account.settlementAccount.accountNumber} (${account.settlementAccount.accountName})); } console.log('---'); }); return result; } catch (error) { console.error('Failed to retrieve virtual accounts:', error.message); throw error; } } // Example usage: // Get all virtual accounts getAllVirtualAccounts(); // Get only USD virtual accounts getAllVirtualAccounts('USD'); // Get first 10 virtual accounts getAllVirtualAccounts(null, 10); Required Permission: get-virtual-accounts This endpoint requires the permission claim get-virtual-accounts to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Update Virtual Account - [PATCH /v1/virtual-accounts/{virtualAccountNumber}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccounts_patch.md): Updates an existing virtual (sub) account for a corporate client. Only the fields provided in the request body will be updated. Updateable Properties - accountHolderName: Human-readable label for the virtual account. Immutable after first update – can only be changed once from the "UNALLOCATED" state. - accountName: Official account title that will appear on statements. Immutable after first update – can only be changed once from the "UNALLOCATED" state. - dob: Date of birth of the account holder. Immutable after first update – can only be set once. - nativeLanguageName: Native name of the account holder's language. Immutable after first update – can only be set once. - clientReference: External reference provided by the client to aid reconciliation (max 35 characters). This field can be updated multiple times. ### Allocating Unallocated Accounts For virtual accounts created with unallocated: true, use this endpoint to perform a one-time assignment to a real end-customer: - Update accountHolderName, accountName, dob, and nativeLanguageName from their initial/placeholder values to the actual customer details - Important: This is a one-time operation. Once these fields are set, they become immutable: - accountHolderName and accountName can only be changed from "UNALLOCATED" state - dob and nativeLanguageName can only be set once (if not provided during creation) - Attempting to update immutable fields after the first update will result in a 409 Conflict error with code ACCOUNT_NAMES_IMMUTABLE - Only clientReference can be updated after allocation ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided for a new transaction, the system stores the key and associates it with the transaction results - If the same idempotency key is received again for the same endpoint/action, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000"). ### Sample Request (JavaScript) javascript async function updateVirtualAccount(virtualAccountNumber) { try { const response = await fetch(https://api.bcb.bm/v1/virtual-accounts/${virtualAccountNumber}, { method: 'PATCH', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ // Note: Only clientReference can be updated after first allocation // accountHolderName, accountName, dob, and nativeLanguageName are immutable after first update clientReference: 'updated-reference-123' }) }); if (!response.ok) { const errorData = await response.json(); // Handle immutable field error if (response.status === 409 && errorData.code === 'ACCOUNT_NAMES_IMMUTABLE') { console.error('Cannot update immutable fields - already set after first update'); return; } throw new Error(Virtual account update failed: ${JSON.stringify(errorData)}); } // Parse JSON response const result = await response.json(); const virtualAccount = result.data; // Log updated details console.log('Virtual Account Updated Successfully:'); console.log( Account Number: ${virtualAccount.virtualAccountNumber}); console.log( Account Holder: ${virtualAccount.accountHolderName}); console.log( Account Name: ${virtualAccount.accountName}); console.log( Currency: ${virtualAccount.currency}); console.log( Category: ${virtualAccount.category}); if (virtualAccount.balance) { console.log( Balance: ${virtualAccount.balance.amount} ${virtualAccount.balance.currency}); } if (virtualAccount.clientReference) { console.log( Client Reference: ${virtualAccount.clientReference}); } console.log( Effective Date: ${virtualAccount.effectiveDate}); console.log( Created: ${virtualAccount.createdAt}); // Log parent/settlement account info if (virtualAccount.parentAccount) { console.log( Parent Account: ${virtualAccount.parentAccount.accountNumber} (${virtualAccount.parentAccount.accountSubType})); } if (virtualAccount.settlementAccount) { console.log( Settlement Account: ${virtualAccount.settlementAccount.accountNumber} (${virtualAccount.settlementAccount.accountSubType})); } return result; } catch (err) { console.error('Error updating virtual account:', err); throw err; } } // Example usage: updateVirtualAccount('1000327642'); // Example: Allocating an unallocated account to a customer (ONE-TIME OPERATION) async function allocateUnallocatedAccount(virtualAccountNumber, customerName, accountTitle, dob, nativeLanguageName) { try { const response = await fetch(https://api.bcb.bm/v1/virtual-accounts/${virtualAccountNumber}, { method: 'PATCH', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ // All these fields are immutable after this update! accountHolderName: customerName, accountName: accountTitle, dob: dob, // Optional - immutable after set nativeLanguageName: nativeLanguageName // Optional - immutable after set }) }); if (!response.ok) { const errorData = await response.json(); // Handle case where account was already allocated if (response.status === 409 && errorData.code === 'ACCOUNT_NAMES_IMMUTABLE') { throw new Error('Account has already been allocated. Immutable fields cannot be changed after first update.'); } throw new Error(Account allocation failed: ${JSON.stringify(errorData)}); } const result = await response.json(); console.log('Account successfully allocated to:', customerName); return result; } catch (err) { console.error('Error allocating account:', err); throw err; } } // Allocate a pre-created unallocated account (can only be done once!) allocateUnallocatedAccount('1000327650', 'Acme Corporation', 'Acme Trading Account', '1990-05-15', 'John Smith'); Required Permission: update-virtual-account This endpoint requires the permission claim update-virtual-account to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Get Virtual Account Details - [GET /v1/virtual-accounts/{virtualAccountNumber}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccounts_getdetails.md): Retrieves comprehensive information about a specific virtual account, including all its sub-accounts, parent account details, and settlement account information. This endpoint: - Returns the virtual account details as a single object - Includes parent account information (the account this virtual account is derived from) - Provides settlement account details (the account used for settlement operations) ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{accountNumber} ### Sample Request in JavaScript javascript async function getVirtualAccountDetails(accountNumber) { try { const url = https://api.bcb.bm/v1/virtual-accounts/${encodeURIComponent(accountNumber)}; const response = await fetch(url, { method: 'GET', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Virtual account details retrieval failed: ${JSON.stringify(errorData)}); } // Parse JSON response const result = await response.json(); // Get the virtual account details (single object, not an array) const virtualAccount = result.data; console.log('Virtual Account Details:'); console.log( Account Number: ${virtualAccount.virtualAccountNumber}); console.log( BIC: ${virtualAccount.bicCode}); console.log( Account Holder: ${virtualAccount.accountHolderName}); console.log( Account Name: ${virtualAccount.accountName}); console.log( Currency: ${virtualAccount.currency}); console.log( Category: ${virtualAccount.category}); if (virtualAccount.balance) { console.log( Balance: ${virtualAccount.balance.amount} ${virtualAccount.balance.currency}); } console.log( Effective Date: ${virtualAccount.effectiveDate}); console.log( Created: ${virtualAccount.createdAt}); if (virtualAccount.clientReference) { console.log( Client Reference: ${virtualAccount.clientReference}); } // Log parent account details if (virtualAccount.parentAccount) { console.log(' Parent Account:'); console.log( Account Number: ${virtualAccount.parentAccount.accountNumber}); console.log( Account ID: ${virtualAccount.parentAccount.accountId}); console.log( CIF: ${virtualAccount.parentAccount.cif}); console.log( Currency: ${virtualAccount.parentAccount.currency}); console.log( Sub Type: ${virtualAccount.parentAccount.accountSubType}); console.log( Status: ${virtualAccount.parentAccount.status}); if (virtualAccount.parentAccount.availableBalance) { console.log( Available Balance: ${virtualAccount.parentAccount.availableBalance.amount} ${virtualAccount.parentAccount.availableBalance.currency}); } if (virtualAccount.parentAccount.owners && virtualAccount.parentAccount.owners.length > 0) { console.log( Owner: ${virtualAccount.parentAccount.owners[0].displayName} (${virtualAccount.parentAccount.owners[0].accountHolderType})); } } // Log settlement account details if (virtualAccount.settlementAccount) { console.log(' Settlement Account:'); console.log( Account Number: ${virtualAccount.settlementAccount.accountNumber}); console.log( Account ID: ${virtualAccount.settlementAccount.accountId}); console.log( CIF: ${virtualAccount.settlementAccount.cif}); console.log( Currency: ${virtualAccount.settlementAccount.currency}); console.log( Sub Type: ${virtualAccount.settlementAccount.accountSubType}); console.log( Status: ${virtualAccount.settlementAccount.status}); if (virtualAccount.settlementAccount.availableBalance) { console.log( Available Balance: ${virtualAccount.settlementAccount.availableBalance.amount} ${virtualAccount.settlementAccount.availableBalance.currency}); } if (virtualAccount.settlementAccount.owners && virtualAccount.settlementAccount.owners.length > 0) { console.log( Owner: ${virtualAccount.settlementAccount.owners[0].displayName} (${virtualAccount.settlementAccount.owners[0].accountHolderType})); } } return result; } catch (error) { console.error('Failed to retrieve virtual account details:', error.message); throw error; } } // Example usage: // Get details for a specific virtual account getVirtualAccountDetails('1000326808'); Required Permission: get-a-virtual-account This endpoint requires the permission claim get-a-virtual-account to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Virtual Account Transactions - [GET /v1/virtual-accounts/{virtualAccountNumber}/transactions](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransactions_get.md): Retrieves transaction entries for a specific virtual (sub) account within a given date range. This endpoint: - Validates the provided date parameters. Accepted formats: yyyy-MM-dd or yyyyMMdd. - Supports a maximum date range of one year. - Supports both JSON and CSV response formats based on the Accept header. - Uses cursor-based pagination with server-side result-set management. ### Pagination This endpoint uses cursor-based pagination with server-side result-set management: - First Request: Optionally specify pageSize (default: 100, max: 1000). The server creates a cursor and returns a pageToken. - Subsequent Requests: Use the pageToken from previous responses with pageStart to navigate pages. - Page Token: Contains encoded pagination context including pageSize, so don't specify pageSize in subsequent requests. - Total Pages: Calculate using Math.ceil(total_size / page_size) from the response metadata. ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{virtualAccountNumber}/transactions ### Sample Request in JavaScript javascript // Get first page async function getVirtualAccountTransactions(virtualAccountNumber, fromDate, toDate) { const url = new URL(https://api.bcb.bm/v1/virtual-accounts/${encodeURIComponent(virtualAccountNumber)}/transactions); url.searchParams.set('fromDate', fromDate); // yyyy-MM-dd or yyyyMMdd url.searchParams.set('toDate', toDate); // yyyy-MM-dd or yyyyMMdd url.searchParams.set('pageSize', '100'); // optional (first call only) const response = await fetch(url.toString(), { method: 'GET', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Accept': 'application/json' } }); if (!response.ok) { const error = await response.json(); throw new Error(Failed to get VA transactions: ${error.message || 'Unknown error'}); } const result = await response.json(); // result.meta.pagination: { page_start, page_token, total_size, page_size } // result.data: Array of VA transactions // Example: inspect first item if (result.data?.length) { const t = result.data[0]; console.log('Tx:', t.id, t.description, t.valueDate, t.value?.amount, t.value?.currency, t.debitAccountNumber?.number, t.creditAccountNumber?.number); } return result; } // Paginate through all pages async function getAllVirtualAccountTransactions(virtualAccountNumber, fromDate, toDate) { let pageStart = 1; let pageToken = null; let totalPages = 0; const all = []; do { const url = new URL(https://api.bcb.bm/v1/virtual-accounts/${encodeURIComponent(virtualAccountNumber)}/transactions); url.searchParams.set('fromDate', fromDate); url.searchParams.set('toDate', toDate); if (pageStart === 1) { url.searchParams.set('pageSize', '100'); // first call only } else { url.searchParams.set('pageStart', String(pageStart)); url.searchParams.set('pageToken', pageToken); } const res = await fetch(url.toString(), { headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Accept': 'application/json' } }); if (!res.ok) throw new Error('Request failed'); const body = await res.json(); if (pageStart === 1) { const p = body.meta?.pagination; pageToken = p?.page_token; totalPages = Math.ceil((p?.total_size ?? 0) / (p?.page_size ?? 100)); console.log('First page meta:', p); } if (Array.isArray(body.data)) all.push(...body.data); pageStart++; } while (pageStart <= totalPages); return all; } Required Permission: get-virtual-account-transactions This endpoint requires the permission claim get-virtual-account-transactions to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Virtual Account Transaction Report - [GET /v1/virtual-accounts/transaction/report](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransactions_getreport.md): Retrieves a transaction report for all virtual (sub) accounts belonging to the authenticated customer within a given date range. Response shape - The endpoint returns a JSON object with meta and data fields. - meta.pagination contains pagination metadata (cursor-based). - data contains the raw CSV report content as a single string (RFC4180, CRLF line endings). Note: This endpoint does not return an array of transaction objects. The report is provided as CSV text inside the JSON envelope. This endpoint: - Validates the provided date parameters. Accepted formats: yyyy-MM-dd or yyyyMMdd. - Supports a maximum date range of one year. - Uses cursor-based pagination with server-side result-set management. ### Pagination This endpoint uses cursor-based pagination with server-side result-set management: - First Request: Optionally specify pageSize (default: 100, max: 1000). The server creates a cursor and returns a pageToken. - Subsequent Requests: Use the pageToken from previous responses with pageStart to navigate pages. - Page Token: Contains encoded pagination context including pageSize, so don't specify pageSize in subsequent requests. - Total Pages: Calculate using Math.ceil(total_size / page_size) from the response metadata. ### Content Negotiation - Set Accept: application/json to receive the JSON envelope where data is the raw CSV report string. - If you request Accept: text/csv, the platform CSV formatter will attempt to serialize the entire response object as CSV, which is different from returning the report payload itself. For the raw report content, use application/json. ### Base URL All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/transaction/report ### Sample Request in JavaScript javascript // Fetch the report (JSON envelope, report CSV in result.data) async function getVirtualAccountTransactionsReport(fromDate, toDate) { const url = new URL(https://api.bcb.bm/v1/virtual-accounts/transaction/report); url.searchParams.set('fromDate', fromDate); // yyyy-MM-dd or yyyyMMdd url.searchParams.set('toDate', toDate); // yyyy-MM-dd or yyyyMMdd const response = await fetch(url.toString(), { method: 'GET', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Accept': 'application/json' } }); if (!response.ok) { const error = await response.json(); throw new Error(Failed to get VA transaction report: ${error.message || 'Unknown error'}); } const result = await response.json(); // result.meta.pagination: { page_start, page_token, total_size, page_size } // result.data: raw CSV report string (may include header + summary sections) const csvText = result.data || ''; console.log(csvText); return result; } // Download the CSV report from the JSON envelope async function downloadVirtualAccountTransactionsReport(fromDate, toDate) { const { data: csvText } = await getVirtualAccountTransactionsReport(fromDate, toDate); const blob = new Blob([csvText || ''], { type: 'text/csv;charset=utf-8' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = vas-transaction-report-${fromDate}-${toDate}.csv; a.click(); URL.revokeObjectURL(a.href); } Required Permission: get-virtual-account-transactions This endpoint requires the permission claim get-virtual-account-transactions to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Virtual Account Transaction Details - [GET /v1/virtual-accounts/transactions/{transactionId}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransactions_getdetails.md): Retrieves detailed information for a specific virtual-account transaction identified by its globally unique transaction ID. This endpoint: - Returns a single transaction detail object with full context (accounts, amounts, value date, narrative, attributes) - Supports both JSON and CSV response formats based on the Accept header ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Account Routing Metadata The transaction detail response includes routing metadata for debitAccountNumber or/and creditAccountNumber depending of transaction type. Account entity contains an accountRoutings collection with up to four entries (when data is available): - BankId – BIC / SWIFT identifier of the bank handling the account - BankName – Legal name of the bank - AccountName – Account holder or counterparty name - AccountAddress – Postal address details associated with the account Entries are ordered as listed above and only appear when the upstream system returns the corresponding value. Consumers can rely on the scheme field to differentiate each routing record. ### Base URL All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/transactions/{transactionId} ### Sample Request in JavaScript javascript async function getVirtualAccountTransactionDetail(transactionId) { const url = https://api.bcb.bm/v1/virtual-accounts/transactions/${encodeURIComponent(transactionId)}; const response = await fetch(url, { method: 'GET', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Accept': 'application/json' } }); if (!response.ok) { const error = await response.json(); throw new Error(Failed to get VA transaction detail: ${error.message || 'Unknown error'}); } const result = await response.json(); // result is a single transaction detail object console.log('Transaction ID:', result.id); console.log('Description:', result.description); console.log('Value Date:', result.valueDate); if (result.value) { console.log('Amount:', result.value.amount, result.value.currency); } return result; } Required Permission: get-virtual-account-transactions This endpoint requires the permission claim get-virtual-account-transactions to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Reverse Virtual Account Transaction - [DELETE /v1/virtual-accounts/transactions/{transactionId}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransactions_reverse.md): Reverses a specific virtual-account transaction identified by its globally unique transaction ID. This endpoint: - Reverses the specified transaction and returns the reversal details - Supports both JSON and CSV response formats based on the Accept header - Requires appropriate permissions to perform transaction reversals ### Important Business Rules - Same-Day Reversal Only: The current development design allows only to reverse records created on the same day - Completed Status Required: The transaction status must have "Completed" status to be eligible for reversal ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided for a new transaction, the system stores the key and associates it with the transaction results - If the same idempotency key is received again for the same endpoint/action, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000"). ### Base URL All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/transactions/{transactionId} ### Sample Request in JavaScript javascript async function reverseVirtualAccountTransaction(transactionId) { const url = https://api.bcb.bm/v1/virtual-accounts/transactions/${encodeURIComponent(transactionId)}; const response = await fetch(url, { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional } }); if (!response.ok) { const error = await response.json(); throw new Error(Failed to reverse VA transaction: ${error.message || 'Unknown error'}); } const result = await response.json(); // result is a transaction reversal object console.log('Reversal Transaction ID:', result.transactionId); console.log('Status:', result.status); console.log('Transaction Status:', result.transactionStatus); if (result.value) { console.log('Amount:', result.value.amount, result.value.currency); } return result; } Required Permission: reverse-virtual-account-transaction This endpoint requires the permission claim reverse-virtual-account-transaction to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Get Virtual Account Deposits - [GET /v1/virtual-accounts/{virtualAccountNumber}/deposits](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransactions_getdeposits.md): Retrieves deposit transaction entries for a specific virtual (sub) account. This endpoint: - Returns detailed deposit transaction information including account numbers, amounts, and transaction status. - Supports both JSON and CSV response formats based on the Accept header. - Uses cursor-based pagination with server-side result-set management. ### Pagination This endpoint uses cursor-based pagination with server-side result-set management: - First Request: Optionally specify pageSize (default: 100, max: 1000). The server creates a cursor and returns a pageToken. - Subsequent Requests: Use the pageToken from previous responses with pageStart to navigate pages. - Page Token: Contains encoded pagination context including pageSize, so don't specify pageSize in subsequent requests. - Total Pages: Calculate using Math.ceil(total_size / page_size) from the response metadata. ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{virtualAccountNumber}/deposits ### Sample Request in JavaScript javascript // Get first page of deposits async function getVirtualAccountDeposits(virtualAccountNumber, fromDate, toDate) { const url = new URL(https://api.bcb.bm/v1/virtual-accounts/${encodeURIComponent(virtualAccountNumber)}/deposits); url.searchParams.set('fromDate', fromDate); // yyyy-MM-dd or yyyyMMdd url.searchParams.set('toDate', toDate); // yyyy-MM-dd or yyyyMMdd url.searchParams.set('pageSize', '100'); // optional (first call only) const response = await fetch(url.toString(), { method: 'GET', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Accept': 'application/json' } }); if (!response.ok) { const error = await response.json(); throw new Error(Failed to get VA deposits: ${error.message || 'Unknown error'}); } const result = await response.json(); // result.meta.pagination: { page_start, page_token, total_size, page_size } // result.data: Array of VA deposit transactions // Example: inspect first deposit if (result.data?.length) { const d = result.data[0]; console.log('Deposit:', d.id, d.valueDate, d.value?.amount, d.value?.currency, d.proprietaryBankTransactionCode); console.log('From:', d.debitAccountNumber?.number, 'To:', d.creditAccountNumber?.number); console.log('Status:', d.status); } return result; } // Paginate through all deposit pages async function getAllVirtualAccountDeposits(virtualAccountNumber, fromDate, toDate) { let pageStart = 1; let pageToken = null; let totalPages = 0; const all = []; do { const url = new URL(https://api.bcb.bm/v1/virtual-accounts/${encodeURIComponent(virtualAccountNumber)}/deposits); url.searchParams.set('fromDate', fromDate); url.searchParams.set('toDate', toDate); if (pageStart === 1) { url.searchParams.set('pageSize', '100'); // first call only } else { url.searchParams.set('pageStart', String(pageStart)); url.searchParams.set('pageToken', pageToken); } const res = await fetch(url.toString(), { headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Accept': 'application/json' } }); if (!res.ok) throw new Error('Request failed'); const body = await res.json(); if (pageStart === 1) { const p = body.meta?.pagination; pageToken = p?.page_token; totalPages = Math.ceil((p?.total_size ?? 0) / (p?.page_size ?? 100)); console.log('First page meta:', p); } if (Array.isArray(body.data)) all.push(...body.data); pageStart++; } while (pageStart <= totalPages); return all; } Required Permission: deposit-virtual-account This endpoint requires the permission claim deposit-virtual-account to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Credit Virtual Account - [POST /v1/virtual-accounts/{accountNumber}/transfers/credit](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransfers_credit.md): Credits funds to a virtual account from a parent account. This endpoint allows clients to transfer funds into a virtual account. The request must include source account details, the amount to be credited, and currency information. ### Key Features: - Transfers funds from a source account to a virtual account - Supports idempotency to prevent duplicate transactions - Validates account numbers and currency matching - Supports both JSON and CSV response formats - Automatic account number validation and matching ### Important Notes: - The virtual account number (creditAccountNumber) is specified in the URL route, not in the request body - Ensure the source account has sufficient funds before making the request - Virtual accounts must be in an active state to receive credits Virtual Account Hierarchy Virtual accounts are sub-accounts linked to a parent account: Parent Account → Virtual Account (Sub-Account) When crediting a virtual account, funds flow from the parent account to the virtual account. ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided for a new transaction, the system stores the key and associates it with the transaction results - If the same idempotency key is received again for the same endpoint/action, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000"). ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{accountNumber}/transfers/credit ### Sample Request in JavaScript: javascript async function creditVirtualAccount() { try { const virtualAccountNumber = "1556008272"; const response = await fetch(https://api.bcb.bm/v1/virtual-accounts/${virtualAccountNumber}/transfers/credit, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional }, body: JSON.stringify({ debitAccountNumber: "1000320567", debitAmountCurrency: "USD", creditAmountCurrency: "USD", // Must match debitAmountCurrency debitAmount: "100.00" }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Credit transfer failed: ${JSON.stringify(errorData)}); } const data = await response.json(); console.log('Credit transfer result:', data); // Example processing of the returned object const { id, status, uniqueIdentifier, details, linkedActivities } = data; const { debitAmount, valueDate, childTransactionId, creditAmountCurrency, debitAccountNumber, creditAccountNumber } = details; // Log the main transfer details console.log('Transaction ID:', id); console.log('Status:', status); console.log('Unique Identifier:', uniqueIdentifier); console.log('Debit Amount:', debitAmount.amount, debitAmount.currency); console.log('Value Date:', valueDate); console.log('Child Transaction ID:', childTransactionId); console.log('Credit Amount Currency:', creditAmountCurrency); // Process debit account information console.log('Debit Account Number:', debitAccountNumber.number); // Process credit account information (virtual account) console.log('Credit Account Number:', creditAccountNumber.number); // Process linked activities linkedActivities.forEach(activity => { console.log('Linked Activity ID:', activity.id); console.log('Linked Activity Transaction Status:', activity.transactionStatus); console.log('Linked Activity Status:', activity.status); console.log('Linked Activity Unique Identifier:', activity.uniqueIdentifier); const { arrangementId, activityId, productId, currencyId, effectiveDate } = activity.activityDetails; console.log('Linked Activity Arrangement ID:', arrangementId); console.log('Linked Activity Activity ID:', activityId); console.log('Linked Activity Product ID:', productId); console.log('Linked Activity Currency ID:', currencyId); console.log('Linked Activity Effective Date:', effectiveDate); }); // Final status logging if (status === 'success') { console.log('The virtual account credit was successful.'); } else { console.log('The virtual account credit failed:', status); } } catch (error) { console.error('Error crediting virtual account:', error); } } creditVirtualAccount(); Required Permission: deposit-virtual-account This endpoint requires the permission claim deposit-virtual-account to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Debit Virtual Account - [POST /v1/virtual-accounts/{accountNumber}/transfers/debit](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransfers_debit.md): Initiates a debit transfer from a virtual (sub) account to transfer funds to the parent account and ultimately to the settlement account. This endpoint allows corporate clients to withdraw funds from their virtual accounts for settlement purposes. Use Case: As a corporate client, I want to debit a sub account to transfer funds to the parent account and ultimately to the settlement account. ### Key Features: - Transfers funds from a virtual account to a main account - Supports idempotency to prevent duplicate transactions - Validates account numbers and currency matching - Supports both JSON and CSV response formats - Automatic account number validation and matching ### Important Notes: - The virtual account number (debitAccountNumber) is specified in the URL route, not in the request body - Ensure the virtual account has sufficient funds before making the request Virtual Account Hierarchy Virtual accounts are sub-accounts linked to a parent account: Virtual Account (Sub-Account) → Parent Account When debiting a virtual account, funds flow from the virtual account to the parent account. ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided for a new transaction, the system stores the key and associates it with the transaction results - If the same idempotency key is received again for the same endpoint/action, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000"). ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{accountNumber}/transfers/debit ### Sample Request in JavaScript: javascript async function debitVirtualAccount() { try { const accountNumber = "1000000000"; // Virtual account number const response = await fetch(https://api.bcb.bm/v1/virtual-accounts/${accountNumber}/transfers/debit, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional }, body: JSON.stringify({ debitAmount: "1000.00", debitAmountCurrency: "USD", creditAccountNumber: "1000320567", // Parent/settlement account creditAmountCurrency: "USD", // Must match debitAmountCurrency }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Debit transfer failed: ${JSON.stringify(errorData)}); } const data = await response.json(); console.log('Debit transfer result:', data); // Example processing of the returned object const { id, status, uniqueIdentifier, details, linkedActivities } = data; const { debitAmount, valueDate, childTransactionId, creditAmountCurrency, debitAccountNumber, creditAccountNumber } = details; // Log the main transfer details console.log('Transaction ID:', id); console.log('Status:', status); console.log('Unique Identifier:', uniqueIdentifier); console.log('Debit Amount:', debitAmount.amount, debitAmount.currency); console.log('Value Date:', valueDate); console.log('Child Transaction ID:', childTransactionId); console.log('Credit Amount Currency:', creditAmountCurrency); // Process debit account information console.log('Debit Account Number:', debitAccountNumber.number); // Process credit account information console.log('Credit Account Number:', creditAccountNumber.number); // Process linked activities linkedActivities.forEach(activity => { console.log('Linked Activity ID:', activity.id); console.log('Linked Activity Transaction Status:', activity.transactionStatus); console.log('Linked Activity Status:', activity.status); console.log('Linked Activity Unique Identifier:', activity.uniqueIdentifier); const { arrangementId, activityId, productId, currencyId, effectiveDate } = activity.activityDetails; console.log('Linked Activity Arrangement ID:', arrangementId); console.log('Linked Activity Activity ID:', activityId); console.log('Linked Activity Product ID:', productId); console.log('Linked Activity Currency ID:', currencyId); console.log('Linked Activity Effective Date:', effectiveDate); }); // Final status logging if (status === 'SUCCESS') { console.log('The debit transfer was successful.'); } else { console.log('The debit transfer failed:', status); } } catch (error) { console.error('Error debiting virtual account:', error); } } // Execute example debitVirtualAccount(); Required Permission: withdraw-virtual-account This endpoint requires the permission claim withdraw-virtual-account to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Counter-party Settlement Transfer (Internal) - [POST /v1/virtual-accounts/{settlementAccountNumber}/settlements/internal](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransferssettlement_settlementinternal.md): Corporate Client initiates Settlement request to BCB to debit Settlement Account and credit to Counterparty Account. This endpoint allows clients to transfer funds from a settlement account to an internal counterparty account. ### Key Features: - Transfers funds from a settlement account to an internal counterparty account - Supports idempotency to prevent duplicate transactions - Validates account numbers and currency matching - Supports both JSON and CSV response formats - Automatic settlement account number validation ### Important Notes: - The settlementAccountNumber in the route parameter identifies the source settlement account - The creditAccountNumber in the request body specifies the destination counterparty account - Ensure the settlement account has sufficient funds before making the request - Settlement accounts must be in an active state to process transfers ### Settlement Account Structure Settlement accounts are special accounts used for counterparty transactions: Settlement Account → Counterparty Account (Internal) When processing a settlement transfer, funds flow from the settlement account to the counterparty account. ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided for a new transaction, the system stores the key and associates it with the transaction results - If the same idempotency key is received again for the same endpoint/action, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000"). ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{settlementAccountNumber}/settlements/internal ### Sample Request in JavaScript: javascript async function processInternalSettlement() { try { const settlementAccountNumber = "1000320559"; const response = await fetch(https://api.bcb.bm/v1/virtual-accounts/${settlementAccountNumber}/settlements/internal, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional }, body: JSON.stringify({ debitCurrency: "USD", creditAmount: { amount: "1000.00", currency: "USD" }, creditAccountNumber: "1000076925" }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Internal settlement failed: ${JSON.stringify(errorData)}); } const data = await response.json(); console.log('Internal settlement result:', data); // Example processing of the returned object const { id, status, uniqueIdentifier, details, linkedActivities } = data; const { creditAmount, debitAmountCurrency, debitAccountNumber, creditAccountNumber, valueDate } = details; // Log the main transfer details console.log('Transaction ID:', id); console.log('Status:', status); console.log('Unique Identifier:', uniqueIdentifier); console.log('Credit Amount:', creditAmount.amount, creditAmount.currency); console.log('Debit Amount Currency:', debitAmountCurrency); console.log('Value Date:', valueDate); // Process debit account information (settlement account) console.log('Debit Account Number:', debitAccountNumber.number); // Process credit account information (counterparty account) console.log('Credit Account Number:', creditAccountNumber.number); // Final status logging if (status === 'success') { console.log('The internal settlement was successful.'); } else { console.log('The internal settlement failed:', status); } } catch (error) { console.error('Error processing internal settlement:', error); } } processInternalSettlement(); Required Permission: counter-party-settlement-transaction This endpoint requires the permission claim counter-party-settlement-transaction to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Counter-party Settlement Transfer (External) - [POST /v1/virtual-accounts/{settlementAccountNumber}/settlements/external](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransferssettlement_settlementexternal.md): Corporate Client initiates External Settlement request to BCB to debit Settlement Account and credit to External Counterparty Account. This endpoint allows clients to transfer funds from a settlement account to an external counterparty account. ### Key Features: - Transfers funds from a settlement account to an external counterparty account - Supports idempotency to prevent duplicate transactions - Supports both JSON and CSV response formats - Automatic settlement account number validation - Includes beneficiary and ordering customer information for external transfers ### Important Notes: - The settlementAccountNumber in the route parameter identifies the source settlement account - The request body specifies the destination external counterparty account via creditorAccount.identification - Ensure the settlement account has sufficient funds before making the request - Settlement accounts must be in an active state to process transfers - External transfers require additional beneficiary information for compliance ### Settlement Account Structure Settlement accounts are special accounts used for counterparty transactions: Settlement Account → External Counterparty Account When processing an external settlement transfer, funds flow from the settlement account to the external counterparty account. ### External Transfer Requirements External transfers require additional information for regulatory compliance: - debitCurrency: Currency to debit from the settlement account (e.g., "USD") - creditAmount: Amount and currency to credit externally (e.g., { amount: "19", currency: "GBP" }) - debtor: Ordering customer information (e.g., company name or reference) - debtorAgent: Ordering bank/agent identifier (free text) - creditorAccount.identification: External beneficiary account identifier - creditorAccount.name / additionalInformation: Beneficiary name and auxiliary details - chargesType: Who bears charges (e.g., OUR, BEN, SHA) - creditorAgent: Beneficiary bank info (identification, name, additionalInformation) - intermediaryAgent (optional): Intermediary bank info (identification, name, additionalInformation) - remittanceInformation (optional): Unstructured remittance lines ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided for a new transaction, the system stores the key and associates it with the transaction results - If the same idempotency key is received again for the same endpoint/action, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000"). ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{settlementAccountNumber}/settlements/external ### Sample Request in JavaScript: javascript async function processExternalSettlement() { try { const settlementAccountNumber = "1000320559"; const response = await fetch(https://api.bcb.bm/v1/virtual-accounts/${settlementAccountNumber}/settlements/external, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional }, body: JSON.stringify({ debitCurrency: "USD", creditAmount: { amount: "19", currency: "GBP" }, debtor: "ACME GLOBAL TRADING INC.", debtorAgent: "FIRST ATLANTIC BANK", creditorAccount: { identification: "GB29NWBK60161331926819", name: "OMEGA INTERNATIONAL LTD.", additionalInformation: ["LONDON", "GB"] }, chargesType: "OUR", creditorAgent: { identification: "//ZZ123456789", name: "OMEGA BANK", additionalInformation: ["LONDON", "UK"] }, intermediaryAgent: { identification: "INTL", name: "EURO CLEAR BANK", additionalInformation: ["BRUSSELS", "BE"] }, remittanceInformation: ["INVOICE 2025-00042"] }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(External settlement failed: ${JSON.stringify(errorData)}); } const data = await response.json(); console.log('External settlement result:', data); // Example processing of the returned object const { id, status, uniqueIdentifier, details, linkedActivities } = data; const { creditAmount, debitAmountCurrency, debitAccountNumber, creditAccountNumber, valueDate } = details; // Log the main transfer details console.log('Transaction ID:', id); console.log('Status:', status); console.log('Unique Identifier:', uniqueIdentifier); console.log('Credit Amount:', creditAmount.amount, creditAmount.currency); console.log('Debit Amount Currency:', debitAmountCurrency); console.log('Value Date:', valueDate); // Process debit account information (settlement account) console.log('Debit Account Number:', debitAccountNumber.number); // Process credit account information (external counterparty account) console.log('Credit Account Number:', creditAccountNumber.number); // Final status logging if (status === 'success') { console.log('The external settlement was successful.'); } else { console.log('The external settlement failed:', status); } } catch (error) { console.error('Error processing external settlement:', error); } } processExternalSettlement(); Required Permission: counter-party-settlement-transaction This endpoint requires the permission claim counter-party-settlement-transaction to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Withdraw funds (Internal) - [POST /v1/virtual-accounts/{virtualAccountId}/withdrawals/internal](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransferswithdrawal_withdrawalinternal.md): Initiates an internal withdrawal transfer from a virtual account to an internal destination account. This endpoint allows clients to withdraw funds from a virtual account to an internal account within the institution. ### Key Features: - Withdraws funds from a virtual account to an internal destination account - Supports idempotency to prevent duplicate transactions - Validates account numbers and currency matching - Supports both JSON and CSV response formats - Automatic virtual account number validation ### Important Notes: - The virtualAccountId in the route parameter identifies the source virtual account - The creditAccountNumber in the request body specifies the destination internal account - Ensure the virtual account has sufficient funds before making the request - Virtual accounts must be in an active state to process withdrawals ### Virtual Account Withdrawal Structure Virtual account withdrawals transfer funds from virtual accounts to internal accounts: Virtual Account → Internal Destination Account When processing a withdrawal transfer, funds flow from the virtual account to the internal destination account. ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided for a new transaction, the system stores the key and associates it with the transaction results - If the same idempotency key is received again for the same endpoint/action, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000"). ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{virtualAccountId}/withdrawals/internal ### Sample Request in JavaScript: javascript async function withdrawFromVirtualAccount() { try { const virtualAccountId = "1000320575"; const response = await fetch(https://api.bcb.bm/v1/virtual-accounts/${virtualAccountId}/withdrawals/internal, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional }, body: JSON.stringify({ debitCurrency: "USD", creditAmount: { currency: "USD", amount: "100.00" }, creditAccountNumber: "1000076925" }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Withdrawal transfer failed: ${JSON.stringify(errorData)}); } const data = await response.json(); console.log('Withdrawal transfer result:', data); // Example processing of the returned object const { id, status, uniqueIdentifier, details, linkedActivities } = data; const { debitAmount, valueDate, childTransactionId, creditAmountCurrency, debitAccountNumber, creditAccountNumber } = details; // Log the main transfer details console.log('Transaction ID:', id); console.log('Status:', status); console.log('Unique Identifier:', uniqueIdentifier); console.log('Debit Amount:', debitAmount.amount, debitAmount.currency); console.log('Value Date:', valueDate); console.log('Child Transaction ID:', childTransactionId); console.log('Credit Amount Currency:', creditAmountCurrency); // Process debit account information (virtual account) console.log('Debit Account Number:', debitAccountNumber.number); // Process credit account information (internal destination) console.log('Credit Account Number:', creditAccountNumber.number); // Process linked activities linkedActivities.forEach(activity => { console.log('Linked Activity ID:', activity.id); console.log('Linked Activity Transaction Status:', activity.transactionStatus); console.log('Linked Activity Status:', activity.status); console.log('Linked Activity Unique Identifier:', activity.uniqueIdentifier); const { arrangementId, activityId, productId, currencyId, effectiveDate } = activity.activityDetails; console.log('Linked Activity Arrangement ID:', arrangementId); console.log('Linked Activity Activity ID:', activityId); console.log('Linked Activity Product ID:', productId); console.log('Linked Activity Currency ID:', currencyId); console.log('Linked Activity Effective Date:', effectiveDate); }); // Final status logging if (status === 'success') { console.log('The virtual account withdrawal was successful.'); } else { console.log('The virtual account withdrawal failed:', status); } } catch (error) { console.error('Error withdrawing from virtual account:', error); } } // Example usage: withdrawFromVirtualAccount(); Required Permission: withdraw-virtual-account This endpoint requires the permission claim withdraw-virtual-account to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint. ## Withdraw funds (External) - [POST /v1/virtual-accounts/{virtualAccountId}/withdrawals/external](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/virtual-accounts/virtualaccountstransferswithdrawal_withdrawalexternal.md): Corporate Client initiates External Withdrawal request to BCB to debit Virtual Account and credit to External Beneficiary Account. This endpoint allows clients to withdraw funds from a virtual account to an external beneficiary account. ### Key Features: - Withdraws funds from a virtual account to an external beneficiary account - Supports idempotency to prevent duplicate transactions - Supports both JSON and CSV response formats - Automatic virtual account number validation - Includes comprehensive beneficiary and ordering customer information for external transfers ### Important Notes: - The virtualAccountId in the route parameter identifies the source virtual account - The request body specifies the destination external beneficiary account via creditorAccount.identification - Ensure the virtual account has sufficient funds before making the request - Virtual accounts must be in an active state to process withdrawals - External transfers require additional beneficiary information for compliance ### Virtual Account Withdrawal Structure Virtual account withdrawals transfer funds from virtual accounts to external beneficiary accounts: Virtual Account → External Beneficiary Account When processing an external withdrawal transfer, funds flow from the virtual account to the external beneficiary account. ### External Transfer Requirements External transfers require additional information for regulatory compliance: - debitCurrency: Currency to debit from the virtual account (e.g., "USD") - creditAmount: Amount and currency to credit externally (e.g., { amount: "2500.00", currency: "USD" }) - debtor: Ordering customer information (e.g., company name or reference) - debtorAgent: Ordering bank/agent identifier (free text) - Optional - creditorAccount.identification: External beneficiary account identifier - creditorAccount.name / additionalInformation: Beneficiary name and auxiliary details - chargesType: Who bears charges (e.g., OUR, BEN, SHA) - creditorAgent: Beneficiary bank info (identification, name, additionalInformation) - intermediaryAgent (optional): Intermediary bank info (identification, name, additionalInformation) - remittanceInformation (optional): Unstructured remittance lines ### Idempotency The API supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally (duplicates are possible) - If a valid UUID idempotency key is provided for a new transaction, the system stores the key and associates it with the transaction results - If the same idempotency key is received again for the same endpoint/action, the system returns the previously stored response - Idempotency keys are user-specific - different users with the same keys don't share cached responses - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000"). ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) - Set Accept: text/csv for CSV responses If the Accept header is omitted, application/json is assumed. ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/virtual-accounts/{virtualAccountId}/withdrawals/external ### Sample Request in JavaScript: javascript async function processExternalWithdrawal() { try { const virtualAccountId = "1000320575"; const response = await fetch(https://api.bcb.bm/v1/virtual-accounts/${virtualAccountId}/withdrawals/external, { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional }, body: JSON.stringify({ debitCurrency: "USD", creditAmount: { currency: "USD", amount: "2500.00" }, debtor: "John Smith Corporation", debtorAgent: "CHASUS33XXX", creditorAccount: { identification: "GB29NWBK60161331926819", name: "Acme Manufacturing Ltd", additionalInformation: [ "123 Business Street", "London, UK SW1A 1AA" ] }, chargesType: "OUR", creditorAgent: { identification: "NWBKGB2L", name: "NatWest Bank", additionalInformation: [ "250 Bishopsgate", "London, UK EC2M 4AA" ] }, intermediaryAgent: { identification: "CHASUS33", name: "JPMorgan Chase Bank", additionalInformation: [ "383 Madison Avenue", "New York, NY 10017" ] }, remittanceInformation: [ "Withdrawal from Virtual Account VA-2024-001", "Transfer to external beneficiary account", "Reference: WD-2024-789456" ] }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(External withdrawal transfer failed: ${JSON.stringify(errorData)}); } const data = await response.json(); console.log('External withdrawal transfer result:', data); // Example processing of the returned object const { id, status, uniqueIdentifier, details, linkedActivities } = data; const { debitAmount, valueDate, childTransactionId, creditAmountCurrency, debitAccountNumber, creditAccountNumber } = details; // Log the main transfer details console.log('Transaction ID:', id); console.log('Status:', status); console.log('Unique Identifier:', uniqueIdentifier); console.log('Debit Amount:', debitAmount.amount, debitAmount.currency); console.log('Value Date:', valueDate); console.log('Child Transaction ID:', childTransactionId); console.log('Credit Amount Currency:', creditAmountCurrency); // Process debit account information (virtual account) console.log('Debit Account Number:', debitAccountNumber.number); // Process credit account information (external beneficiary account) console.log('Credit Account Number:', creditAccountNumber.number); // Process linked activities linkedActivities.forEach(activity => { console.log('Linked Activity ID:', activity.id); console.log('Linked Activity Transaction Status:', activity.transactionStatus); console.log('Linked Activity Status:', activity.status); console.log('Linked Activity Unique Identifier:', activity.uniqueIdentifier); const { arrangementId, activityId, productId, currencyId, effectiveDate } = activity.activityDetails; console.log('Linked Activity Arrangement ID:', arrangementId); console.log('Linked Activity Activity ID:', activityId); console.log('Linked Activity Product ID:', productId); console.log('Linked Activity Currency ID:', currencyId); console.log('Linked Activity Effective Date:', effectiveDate); }); // Final status logging if (status === 'success') { console.log('The external withdrawal was successful.'); } else { console.log('The external withdrawal failed:', status); } } catch (error) { console.error('Error processing external withdrawal:', error); } } // Example usage: processExternalWithdrawal(); Required Permission: withdraw-virtual-account This endpoint requires the permission claim withdraw-virtual-account to be present in the JWT token. These permissions are embedded in the token during the authentication process and cannot be modified afterward. The token must be obtained with the appropriate permissions to access this endpoint.