# Bermuda Commercial Bank RESTful Open Banking API Implementation The Bermuda Commercial Bank (BCB) RESTful Open Banking API provides secure, programmatic access to BCB's banking services, enabling developers to integrate financial services into their applications. ### Key Features - Account details retrieval - Internal transfers - Payments (Swift) - Virtual Accounts - Transaction information access - Robust security and compliance - Comprehensive documentation ### Available Environments **UAT Environment** **URL:** https://api-uat.bcb.bm **Purpose:** Testing and integration **Production Environment** **URL:** https://api.bcb.bm **Purpose:** Live production use Version: v1 ## Servers UAT Environment - Used for testing and integration purposes ``` https://api-uat.bcb.bm ``` Production Environment - Live environment for production use ``` https://api.bcb.bm ``` ## Security ### Authorization Access token Type: http In: header Scheme: bearer Bearer Format: jwt ### Feature Permissions Feature-based permissions are claims contained in the JWT token. The token must include the specified permission claim to access the endpoint. These permissions are validated during token validation. Type: http In: header Scheme: bearer Bearer Format: jwt ## Download OpenAPI description [Bermuda Commercial Bank RESTful Open Banking API Implementation](https://developers.bcb.bm/_bundle/apis/open-banking-api/open-banking-api.yaml) ## Accounts ### Account Details - [GET /v1/accounts/{accountNumber}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/accounts/accounts_get.md): Retrieves the account details and balance. This endpoint requires authentication and returns comprehensive information for the specified account. The returned data includes: - Number: The human-readable account number assigned by the bank. - Label: A label provided by the account owner. - Owners: The list of users who own this account. - Type: The type of account. - Balance: The account's balance including currency and amount. - Account Attributes: Additional account information specific to Bermuda Commercial Bank. ### 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/accounts ### Sample Request in JavaScript: javascript async function getAccountDetails(accountNumber) { try { const response = await fetch(https://api.bcb.bm/v1/accounts/${accountNumber}, { 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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log('Account details:', data); // Example processing of the returned object const accountId = data.id; const accountNumber = data.number; const accountBalance = data.balance.amount; const accountCurrency = data.balance.currency; const accountStatus = data.accountAttributes.find(attr => attr.name === 'STATUS')?.value; console.log('Account ID:', accountId); console.log('Account Number:', accountNumber); console.log('Account Balance:', accountBalance); console.log('Account Currency:', accountCurrency); console.log('Account Status:', accountStatus); // Process all account attributes console.log('Account Attributes:'); data.accountAttributes.forEach(attribute => { console.log(${attribute.name}: ${attribute.value}); }); // Additional processing based on account status if (accountStatus === 'ACTIVE') { console.log('The account is active.'); } else { console.log('The account is not active.'); } } catch (error) { console.error('There was a problem with the fetch operation:', error.message); } } // Example usage: getAccountDetails('YOUR_ACCOUNT_NUMBER'); Required Permission: get-account This endpoint requires the permission claim get-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. ### List User Accounts - [GET /v1/accounts](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/accounts/accounts_getall.md): Retrieves a list of all accounts associated with the authenticated user's profile. This endpoint: - Uses the customer account number from the authenticated user's session to fetch all associated accounts. - Requires valid authentication. - Supports both JSON and CSV response formats based on the Accept header. - Returns a summary version of account information (AccountSummary) containing only essential fields - Supports cursor-based pagination for efficient handling of large account lists. ### 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/accounts ### Sample Request in JavaScript javascript async function getAllAccountsPaginated() { try { let allAccounts = []; let pageStart = 1; let pageToken = null; let totalPages = 0; do { // Build URL with pagination parameters let url = 'https://api.bcb.bm/v1/accounts'; const params = new URLSearchParams(); if (pageStart === 1) { // First request: optionally specify pageSize params.append('pageSize', '100'); } else { // Subsequent requests: use pageToken and pageStart params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log(Page ${pageStart} data:, data); // Store pagination info from first request if (pageStart === 1 && data.meta && data.meta.pagination) { pageToken = data.meta.pagination.page_token; totalPages = Math.ceil(data.meta.pagination.total_size / data.meta.pagination.page_size); console.log(Total pages: ${totalPages}, Page token: ${pageToken}); } // Collect accounts from this page if (data.data && data.data.length > 0) { allAccounts.push(...data.data); console.log(Collected ${data.data.length} accounts from page ${pageStart}); } pageStart++; } while (pageStart { console.log(Account ${index + 1}: ${account.number}); console.log(Balance: ${account.balance.amount} ${account.balance.currency}); }); return allAccounts; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Function to get a specific page of accounts async function getAccountsPage(pageStart, pageToken = null) { try { // Build URL let url = 'https://api.bcb.bm/v1/accounts'; const params = new URLSearchParams(); if (pageStart === 1) { // First request: optionally specify pageSize params.append('pageSize', '100'); } else { // Subsequent requests: use pageToken and pageStart params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log('Accounts page:', data); return data; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Example usage: getAllAccountsPaginated(); // Retrieves all accounts across multiple pages // OR getAccountsPage(1).then(firstPage => { console.log('First page:', firstPage); // Use firstPage.meta.pagination.page_token for subsequent requests }); Required Permission: get-all-accounts This endpoint requires the permission claim get-all-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. ### List payment statuses for an account - [GET /v1/accounts/{accountNumber}/payments](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/accounts/transactionstatus_getaccounttransactionstatuses.md): Retrieves status information for all payments associated with a specific account. This endpoint: - Provides comprehensive payment status details including type, status, transaction ID, external reference, remittance information, amounts, value date, and exchange rate. - Supports both JSON and CSV response formats based on the Accept header. - Supports cursor-based pagination for efficient handling of large payment status datasets. ### 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/accounts/{accountNumber}/payments ### Sample Request in JavaScript javascript async function getAllPaymentStatusesPaginated(accountNumber) { try { let allPaymentStatuses = []; let pageStart = 1; let pageToken = null; let totalPages = 0; do { // Build URL with pagination parameters let url = https://api.bcb.bm/v1/accounts/${accountNumber}/payments; const params = new URLSearchParams(); if (pageStart === 1) { // First request: specify pageSize params.append('pageSize', '100'); } else { // Subsequent requests: use pageToken and pageStart params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log(Page ${pageStart} data:, data); // Store pagination info from first request if (pageStart === 1 && data.meta && data.meta.pagination) { pageToken = data.meta.pagination.page_token; totalPages = Math.ceil(data.meta.pagination.total_size / data.meta.pagination.page_size); console.log(Total pages: ${totalPages}, Page token: ${pageToken}); } // Collect payment statuses from this page if (data.data && data.data.length > 0) { allPaymentStatuses.push(...data.data); console.log(Collected ${data.data.length} payment statuses from page ${pageStart}); } pageStart++; } while (pageStart { console.log(Payment ${index + 1}:, payment.transactionId); console.log('Type:', payment.type); console.log('Status:', payment.status); console.log('External Reference:', payment.externalReference); console.log('Remittance Information:', payment.remittanceInformation); console.log('Value Date:', payment.valueDate); console.log('Debit Amount:', ${payment.debitAmount.amount} ${payment.debitAmount.currency}); if (payment.creditAmount && payment.creditAmount.amount) { console.log('Credit Amount:', ${payment.creditAmount.amount} ${payment.creditAmount.currency}); } console.log('-------------------'); }); return allPaymentStatuses; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Alternative: Get single page of payment statuses async function getPaymentStatusesPage(accountNumber, pageStart = 1, pageToken = null) { try { let url = https://api.bcb.bm/v1/accounts/${accountNumber}/payments; const params = new URLSearchParams(); if (pageStart === 1 && !pageToken) { params.append('pageSize', '50'); // Custom page size } else { params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log('Payment statuses page:', data); return data; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Example usage: getAllPaymentStatusesPaginated('123456789'); // Retrieves all payment statuses across multiple pages // OR getPaymentStatusesPage('123456789', 1).then(firstPage => { console.log('First page:', firstPage); // Use firstPage.meta.pagination.page_token for subsequent requests }); Required Permission: get-payment-status This endpoint requires the permission claim get-payment-status 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. ### List payment statuses for an account - [GET /v1/accounts/{accountNumber}/payments](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/payments/transactionstatus_getaccounttransactionstatuses.md): Retrieves status information for all payments associated with a specific account. This endpoint: - Provides comprehensive payment status details including type, status, transaction ID, external reference, remittance information, amounts, value date, and exchange rate. - Supports both JSON and CSV response formats based on the Accept header. - Supports cursor-based pagination for efficient handling of large payment status datasets. ### 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/accounts/{accountNumber}/payments ### Sample Request in JavaScript javascript async function getAllPaymentStatusesPaginated(accountNumber) { try { let allPaymentStatuses = []; let pageStart = 1; let pageToken = null; let totalPages = 0; do { // Build URL with pagination parameters let url = https://api.bcb.bm/v1/accounts/${accountNumber}/payments; const params = new URLSearchParams(); if (pageStart === 1) { // First request: specify pageSize params.append('pageSize', '100'); } else { // Subsequent requests: use pageToken and pageStart params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log(Page ${pageStart} data:, data); // Store pagination info from first request if (pageStart === 1 && data.meta && data.meta.pagination) { pageToken = data.meta.pagination.page_token; totalPages = Math.ceil(data.meta.pagination.total_size / data.meta.pagination.page_size); console.log(Total pages: ${totalPages}, Page token: ${pageToken}); } // Collect payment statuses from this page if (data.data && data.data.length > 0) { allPaymentStatuses.push(...data.data); console.log(Collected ${data.data.length} payment statuses from page ${pageStart}); } pageStart++; } while (pageStart { console.log(Payment ${index + 1}:, payment.transactionId); console.log('Type:', payment.type); console.log('Status:', payment.status); console.log('External Reference:', payment.externalReference); console.log('Remittance Information:', payment.remittanceInformation); console.log('Value Date:', payment.valueDate); console.log('Debit Amount:', ${payment.debitAmount.amount} ${payment.debitAmount.currency}); if (payment.creditAmount && payment.creditAmount.amount) { console.log('Credit Amount:', ${payment.creditAmount.amount} ${payment.creditAmount.currency}); } console.log('-------------------'); }); return allPaymentStatuses; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Alternative: Get single page of payment statuses async function getPaymentStatusesPage(accountNumber, pageStart = 1, pageToken = null) { try { let url = https://api.bcb.bm/v1/accounts/${accountNumber}/payments; const params = new URLSearchParams(); if (pageStart === 1 && !pageToken) { params.append('pageSize', '50'); // Custom page size } else { params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log('Payment statuses page:', data); return data; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Example usage: getAllPaymentStatusesPaginated('123456789'); // Retrieves all payment statuses across multiple pages // OR getPaymentStatusesPage('123456789', 1).then(firstPage => { console.log('First page:', firstPage); // Use firstPage.meta.pagination.page_token for subsequent requests }); Required Permission: get-payment-status This endpoint requires the permission claim get-payment-status 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. ## Payments ### List payment statuses for an account - [GET /v1/accounts/{accountNumber}/payments](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/accounts/transactionstatus_getaccounttransactionstatuses.md): Retrieves status information for all payments associated with a specific account. This endpoint: - Provides comprehensive payment status details including type, status, transaction ID, external reference, remittance information, amounts, value date, and exchange rate. - Supports both JSON and CSV response formats based on the Accept header. - Supports cursor-based pagination for efficient handling of large payment status datasets. ### 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/accounts/{accountNumber}/payments ### Sample Request in JavaScript javascript async function getAllPaymentStatusesPaginated(accountNumber) { try { let allPaymentStatuses = []; let pageStart = 1; let pageToken = null; let totalPages = 0; do { // Build URL with pagination parameters let url = https://api.bcb.bm/v1/accounts/${accountNumber}/payments; const params = new URLSearchParams(); if (pageStart === 1) { // First request: specify pageSize params.append('pageSize', '100'); } else { // Subsequent requests: use pageToken and pageStart params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log(Page ${pageStart} data:, data); // Store pagination info from first request if (pageStart === 1 && data.meta && data.meta.pagination) { pageToken = data.meta.pagination.page_token; totalPages = Math.ceil(data.meta.pagination.total_size / data.meta.pagination.page_size); console.log(Total pages: ${totalPages}, Page token: ${pageToken}); } // Collect payment statuses from this page if (data.data && data.data.length > 0) { allPaymentStatuses.push(...data.data); console.log(Collected ${data.data.length} payment statuses from page ${pageStart}); } pageStart++; } while (pageStart { console.log(Payment ${index + 1}:, payment.transactionId); console.log('Type:', payment.type); console.log('Status:', payment.status); console.log('External Reference:', payment.externalReference); console.log('Remittance Information:', payment.remittanceInformation); console.log('Value Date:', payment.valueDate); console.log('Debit Amount:', ${payment.debitAmount.amount} ${payment.debitAmount.currency}); if (payment.creditAmount && payment.creditAmount.amount) { console.log('Credit Amount:', ${payment.creditAmount.amount} ${payment.creditAmount.currency}); } console.log('-------------------'); }); return allPaymentStatuses; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Alternative: Get single page of payment statuses async function getPaymentStatusesPage(accountNumber, pageStart = 1, pageToken = null) { try { let url = https://api.bcb.bm/v1/accounts/${accountNumber}/payments; const params = new URLSearchParams(); if (pageStart === 1 && !pageToken) { params.append('pageSize', '50'); // Custom page size } else { params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log('Payment statuses page:', data); return data; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Example usage: getAllPaymentStatusesPaginated('123456789'); // Retrieves all payment statuses across multiple pages // OR getPaymentStatusesPage('123456789', 1).then(firstPage => { console.log('First page:', firstPage); // Use firstPage.meta.pagination.page_token for subsequent requests }); Required Permission: get-payment-status This endpoint requires the permission claim get-payment-status 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. ### SWIFT Payment - [POST /v1/payments/swift](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/payments/payments_post.md): Initiates a SWIFT payment transfer. The request must include all required payment details including: - Source and destination account information - Payment amount and currency - Beneficiary details - Payment purpose and reference information ### Key Features: - Supports international wire transfers via SWIFT network - Implements idempotency to prevent duplicate transactions - Validates payment requests before processing - Supports both JSON and CSV response formats ### 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/payments/swift ### 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 in JavaScript: javascript async function processSwiftPayment() { try { const response = await fetch('https://api.bcb.bm/v1/payments/swift', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional: UUID format required if provided }, body: JSON.stringify({ instructionIdentification: "PAYMENT-123456", // Optional debtorAccount: { identification: "DEBTOR-ACC-123" }, instructedAmount: { currency: "USD", amount: "1000.00" }, creditorAccount: { identification: "CREDITOR-ACC-456", name: "John Doe", additionalInformation: ["Additional details"] }, creditorAgent: { identification: "BANKBIC123", name: "Beneficiary Bank", additionalInformation: ["SWIFT/BIC code"] }, chargesType: "OUR", remittanceInformation: ["Payment for services"] }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error processing payment: ${errorData.message || 'Unknown error'}); } const result = await response.json(); // Check payment status if (result.status === 'success') { console.log('Payment processed successfully'); // Log payment details console.log('Payment ID:', result.id); console.log('Transaction Status:', result.transactionStatus); console.log('Unique Identifier:', result.uniqueIdentifier); // Process payment details const details = result.details; console.log('External Reference:', details.extReference); console.log('Instructed Amount:', details.instructedAmount.amount, details.instructedAmount.currency); // Process account information console.log('Debtor Account:', details.debtorAccount.identification); console.log('Creditor Account:', details.creditorAccount.identification); console.log('Beneficiary Account:', details.beneficiaryAccount.identification); // Process settlement details const settlement = details.settlementDetails; console.log('Amount Credited:', settlement.amountCredited.amount, settlement.amountCredited.currency); console.log('Amount Debited:', settlement.amountDebited.amount, settlement.amountDebited.currency); console.log('Value Date:', settlement.valueDate); console.log('Record Status:', settlement.recordStatus); // Process charge details const charges = details.chargeDetails; console.log('Charges Type:', charges.chargesType); console.log('Total Charges:', charges.chargeAmount.amount, charges.chargeAmount.currency); // Process charge analysis const chargeAnalysis = charges.chargeAnalysis; console.log('Sender Charges:', chargeAnalysis.sender.amount, chargeAnalysis.sender.currency); console.log('Receiver Charges:', chargeAnalysis.receiver.amount, chargeAnalysis.receiver.currency); // Process beneficiary information console.log('Beneficiary Name:', details.beneficiary.name); console.log('Beneficiary Bank:', details.beneficiaryAgent.name); // Process remittance information if (details.remittanceInformation) { console.log('Remittance Information:'); details.remittanceInformation.forEach(info => console.log('-', info)); } // Process linked activities if (result.linkedActivities && result.linkedActivities.length > 0) { console.log('Linked Activities:'); result.linkedActivities.forEach(activity => { console.log('- Activity ID:', activity.id); console.log(' Status:', activity.status); console.log(' Transaction Status:', activity.transactionStatus); console.log(' Unique Identifier:', activity.uniqueIdentifier); }); } } else { console.error('Payment processing failed:', result.status); // Handle failed payment if (result.details) { console.error('Error details:', result.details); } } } catch (error) { console.error('Error:', error); // Handle error appropriately } } // Example usage: processSwiftPayment(); ### Response Structure | Field | Type | Description | |-------|------|-------------| | id | string | Unique identifier for the payment | | status | string | Payment status (success or failed) | | transactionStatus | string | Detailed transaction status | | uniqueIdentifier | string | Unique identifier for tracking | | details | object | Payment details object | | linkedActivities | array | Related financial activities | Required Permission: payment-swift This endpoint requires the permission claim payment-swift 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. ### List payment statuses for an account - [GET /v1/accounts/{accountNumber}/payments](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/payments/transactionstatus_getaccounttransactionstatuses.md): Retrieves status information for all payments associated with a specific account. This endpoint: - Provides comprehensive payment status details including type, status, transaction ID, external reference, remittance information, amounts, value date, and exchange rate. - Supports both JSON and CSV response formats based on the Accept header. - Supports cursor-based pagination for efficient handling of large payment status datasets. ### 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/accounts/{accountNumber}/payments ### Sample Request in JavaScript javascript async function getAllPaymentStatusesPaginated(accountNumber) { try { let allPaymentStatuses = []; let pageStart = 1; let pageToken = null; let totalPages = 0; do { // Build URL with pagination parameters let url = https://api.bcb.bm/v1/accounts/${accountNumber}/payments; const params = new URLSearchParams(); if (pageStart === 1) { // First request: specify pageSize params.append('pageSize', '100'); } else { // Subsequent requests: use pageToken and pageStart params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log(Page ${pageStart} data:, data); // Store pagination info from first request if (pageStart === 1 && data.meta && data.meta.pagination) { pageToken = data.meta.pagination.page_token; totalPages = Math.ceil(data.meta.pagination.total_size / data.meta.pagination.page_size); console.log(Total pages: ${totalPages}, Page token: ${pageToken}); } // Collect payment statuses from this page if (data.data && data.data.length > 0) { allPaymentStatuses.push(...data.data); console.log(Collected ${data.data.length} payment statuses from page ${pageStart}); } pageStart++; } while (pageStart { console.log(Payment ${index + 1}:, payment.transactionId); console.log('Type:', payment.type); console.log('Status:', payment.status); console.log('External Reference:', payment.externalReference); console.log('Remittance Information:', payment.remittanceInformation); console.log('Value Date:', payment.valueDate); console.log('Debit Amount:', ${payment.debitAmount.amount} ${payment.debitAmount.currency}); if (payment.creditAmount && payment.creditAmount.amount) { console.log('Credit Amount:', ${payment.creditAmount.amount} ${payment.creditAmount.currency}); } console.log('-------------------'); }); return allPaymentStatuses; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Alternative: Get single page of payment statuses async function getPaymentStatusesPage(accountNumber, pageStart = 1, pageToken = null) { try { let url = https://api.bcb.bm/v1/accounts/${accountNumber}/payments; const params = new URLSearchParams(); if (pageStart === 1 && !pageToken) { params.append('pageSize', '50'); // Custom page size } else { params.append('pageToken', pageToken); params.append('pageStart', pageStart.toString()); } if (params.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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log('Payment statuses page:', data); return data; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Example usage: getAllPaymentStatusesPaginated('123456789'); // Retrieves all payment statuses across multiple pages // OR getPaymentStatusesPage('123456789', 1).then(firstPage => { console.log('First page:', firstPage); // Use firstPage.meta.pagination.page_token for subsequent requests }); Required Permission: get-payment-status This endpoint requires the permission claim get-payment-status 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 payment status - [GET /v1/payments/{paymentId}/status](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/payments/transactionstatus_gettransactionstatus.md): Retrieves detailed status information for a specific payment identified by its payment ID (also known as transaction ID). This endpoint provides comprehensive status details including: - Type: The type of payment (e.g., "Outward Swift Payment MT103 API") - Status: Current status of the payment (e.g., "Pending", "Completed", "Reversed") - TransactionId: Unique payment identifier (or Transaction Id) - ExternalReference: External reference number for the payment - RemittanceInformation: Free-text information about the purpose of the payment - DebitAmount: The amount debited from the account, including currency code - CreditAmount: The amount credited to the account, including currency code - ValueDate: The date when the payment was/will be processed - ExchangeRate: The exchange rate applied to the payment ### 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/payments/{paymentId}/status ### Sample Request in JavaScript: javascript async function getPaymentStatus(paymentId) { try { const response = await fetch(https://api.bcb.bm/v1/payments/${paymentId}/status, { 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(Error: ${errorData.message || 'Unknown error'}); } const paymentStatus = await response.json(); console.log('Payment Status Details:'); console.log('Payment ID:', paymentStatus.transactionId); console.log('Type:', paymentStatus.type); console.log('Status:', paymentStatus.status); console.log('External Reference:', paymentStatus.externalReference); console.log('Remittance Information:', paymentStatus.remittanceInformation); console.log('Value Date:', paymentStatus.valueDate); console.log('Debit Amount:', ${paymentStatus.debitAmount.amount} ${paymentStatus.debitAmount.currency}); if (paymentStatus.creditAmount && paymentStatus.creditAmount.amount) { console.log('Credit Amount:', ${paymentStatus.creditAmount.amount} ${paymentStatus.creditAmount.currency}); } // Implement business logic based on payment status if (paymentStatus.status === 'Completed') { console.log('Payment has been successfully completed.'); } else if (paymentStatus.status === 'Pending') { console.log('Payment is still being processed.'); } else if (paymentStatus.status === 'Failed') { console.log('Payment failed. Please check the details or contact support.'); } } catch (error) { console.error('There was a problem retrieving the payment status:', error.message); } } // Example usage: getPaymentStatus('PAY-001-2023'); Required Permission: get-payment-status This endpoint requires the permission claim get-payment-status 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. ## Credentials ### Create new API client credentials - [POST /v1/credentials](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_post.md): Creates new API client credentials based on an existing client's permissions and configuration. The new credentials will inherit the same roles and permissions as the specified existing client. Key Features: - A new client ID (GUID) is generated automatically - A cryptographically secure password (22-30 characters) is generated automatically - A cryptographically secure message signing secret (32 bytes) is generated automatically for HMAC-SHA256 signing - All roles and direct permissions are copied from the existing client - The new credentials can have different IP restrictions if specified Password Security: - Generated passwords are 22-30 characters long for enhanced security - Include uppercase letters, lowercase letters, digits, and special characters - The generated password is only returned once in the response Message Signing Secret: - A 32-byte (256-bit) random key (Base64 encoded) is generated for signing API requests - This key will be used by the system to sign callback responses - notifications, background job webhooks - The secret is returned only once in the response Access Control: - You can only create credentials based on clients you have access to - New client inherits exact role and permission set from source client - IP restrictions can be customized or inherited from source client ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/credentials ### 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 in JavaScript: javascript async function createCredentials() { try { const token = localStorage.getItem('jwt'); // Your JWT token from authentication const response = await fetch('https://api.bcb.bm/v1/credentials', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': Bearer ${token} }, body: JSON.stringify({ allowedIps: '192.168.1.100,10.0.0.0/24' // Optional: specify IP restrictions, or omit/'*' for all IPs }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const data = await response.json(); console.log('New credentials created:', { clientId: data.clientId, clientSecret: data.clientSecret, // Save this securely - only shown once! messageSigningSecret: data.messageSigningSecret, // Save this securely - only shown once! isActive: data.isActive, allowedIps: data.allowedIps }); // Store new credentials securely // WARNING: This is just an example - use secure storage in production localStorage.setItem('newClientId', data.clientId); localStorage.setItem('newClientSecret', data.clientSecret); localStorage.setItem('newMessageSigningSecret', data.messageSigningSecret); } catch (error) { console.error('Error creating credentials:', error); } } createCredentials(); Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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. ### Rotate the client secret for an existing API client - [PATCH /v1/credentials/{clientId}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_patch.md): Rotates (changes) the client secret AND the message signing secret for an existing API client while preserving all other settings. This is useful for credential rotation policies, security incident response, or regular maintenance. Key Features: - A new cryptographically secure password (22-30 characters) is generated automatically - A new cryptographically secure message signing secret (32 bytes) is generated automatically - The existing client's secrets are immediately replaced with the new ones - All roles, permissions, and other settings remain unchanged - The old secrets become invalid immediately after successful rotation - The new secrets are returned in the response (only shown once) Password Security: - Generated passwords are 22-30 characters long for enhanced security - Include uppercase letters, lowercase letters, digits, and special characters - The new password is only returned once in the response Access Control: - You can only rotate secrets for clients you have access to - The rotated client retains all existing roles and permissions Important Security Notes: - The old secret stops working immediately after successful rotation - Any applications using the old secret will need to be updated with the new secret - Store the new secret securely as it won't be shown again ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/credentials/{clientId} ### 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 in JavaScript: javascript async function rotateClientSecret(clientId) { try { const token = localStorage.getItem('jwt'); // Your JWT token from authentication const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': Bearer ${token} } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const data = await response.json(); console.log('Client secret rotated successfully:', { clientId: data.clientId, newClientSecret: data.clientSecret, // Save this securely - only shown once! newMessageSigningSecret: data.messageSigningSecret, // Save this securely - only shown once! isActive: data.isActive, allowedIps: data.allowedIps }); // Update stored credentials securely // WARNING: This is just an example - use secure storage in production localStorage.setItem('clientSecret', data.clientSecret); localStorage.setItem('messageSigningSecret', data.messageSigningSecret); // Important: Update any applications using the old secret console.warn('IMPORTANT: Update all applications using this client with the new secret!'); } catch (error) { console.error('Error rotating client secret:', error); } } // Example usage rotateClientSecret('12345678-1234-1234-1234-123456789abc'); Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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. ### Disable an existing API client - [DELETE /v1/credentials/{clientId}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_delete.md): Disables an existing API client, immediately preventing any further authentication using that client ID and secret. This operation also revokes all active tokens associated with the client. Key Features: - Disables the credentials instantly – all authentication requests will fail after this operation - Revokes all active tokens immediately for enhanced security - Idempotent: calling the endpoint on an already inactive client returns success Security Considerations: - All active tokens are immediately invalidated and removed from the system - Any applications using the disabled client will lose access immediately - The client record is preserved for audit and compliance purposes Access Control: - You can only disable clients that belong to your organization ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/credentials/{clientId} ### Sample Request in JavaScript: javascript async function disableClient(clientId) { try { const token = localStorage.getItem('jwt'); // Your JWT token from authentication const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': Bearer ${token} } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const data = await response.json(); console.log('Client disabled successfully:', { clientId: data.clientId, isActive: data.isActive, // Should be false allowedIps: data.allowedIps }); // Important: Update any applications that were using this client console.warn('IMPORTANT: All applications using this client will lose access immediately!'); } catch (error) { console.error('Error disabling client:', error); } } // Example usage disableClient('12345678-1234-1234-1234-123456789abc'); Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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 permissions for an existing API client - [GET /v1/credentials/{clientId}/permissions](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_getpermissions.md): Retrieves all permissions assigned to the specified API client. The response provides a comprehensive view of what features the client can access. Key Features: - Returns all permissions assigned to the client - Results are sorted alphabetically by permission key for consistent ordering - Includes human-readable descriptions for each permission Access Control: - You can only view permissions for clients that belong to your organization Use Cases: - Audit client access capabilities - Troubleshoot authentication and authorization issues - Verify client configuration during security reviews - Document client permissions for compliance purposes ### Base URL: All API requests use the versioned base URL: https://api.bcb.bm/v1/credentials/{clientId}/permissions ### Sample Request in JavaScript: javascript async function getClientPermissions(clientId) { try { const token = localStorage.getItem('jwt'); // Your JWT token from authentication const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}/permissions, { method: 'GET', headers: { 'Accept': 'application/json', 'Authorization': Bearer ${token} } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const permissions = await response.json(); console.log('Client permissions:', permissions); // Display permissions in a user-friendly format permissions.forEach(permission => { console.log(- ${permission.key}: ${permission.description || 'No description available'}); }); return permissions; } catch (error) { console.error('Error retrieving client permissions:', error); } } // Example usage getClientPermissions('12345678-1234-1234-1234-123456789abc'); Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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 public key metadata - [GET /v1/credentials/{clientId}/keys](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_getkeys.md): Returns metadata for the partner RSA keys: - Indicates whether primary/secondary keys exist - Provides short fingerprints, algorithms, and last-updated timestamps - Shows verification status of the secondary key (after proof-of-possession) ### Sample Request in JavaScript: javascript async function getKeyMetadata(clientId) { try { const token = localStorage.getItem('jwt'); const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}/keys, { method: 'GET', headers: { 'Accept': 'application/json', 'Authorization': Bearer ${token} } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const metadata = await response.json(); console.log('Key metadata:', { hasPrimaryKey: metadata.hasPrimaryKey, hasSecondaryKey: metadata.hasSecondaryKey, primaryKeyFingerprint: metadata.primaryKeyFingerprint, secondaryKeyFingerprint: metadata.secondaryKeyFingerprint, secondaryKeyVerified: metadata.secondaryKeyVerified }); return metadata; } catch (error) { console.error('Error getting key metadata:', error); } } getKeyMetadata('12345678-1234-1234-1234-123456789abc'); Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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. ### Upload secondary public key - [PUT /v1/credentials/{clientId}/keys/secondary](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_putsecondarykey.md): Upload a new RSA public key (PEM format) into the secondary slot to stage rotation. Key Features: - Accepts RSA public keys (2048-bit minimum recommended) - Resets verification status when a new key is uploaded - Secondary key becomes active for signature verification alongside primary Rotation flow: 1. Upload secondary key (this endpoint) 2. POST challenge → sign locally → POST verify 3. POST promote (makes secondary the primary) 4. (Optional) DELETE secondary if aborting ### Sample Request in JavaScript: javascript async function uploadSecondaryKey(clientId, publicKeyPem) { try { const token = localStorage.getItem('jwt'); const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}/keys/secondary, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': Bearer ${token} }, body: JSON.stringify({ publicKeyPem: publicKeyPem }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const metadata = await response.json(); console.log('Secondary key uploaded:', { hasSecondaryKey: metadata.hasSecondaryKey, secondaryKeyFingerprint: metadata.secondaryKeyFingerprint, secondaryKeyVerified: metadata.secondaryKeyVerified // Will be false until verified }); return metadata; } catch (error) { console.error('Error uploading secondary key:', error); } } Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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. ### Delete secondary public key - [DELETE /v1/credentials/{clientId}/keys/secondary](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_deletesecondarykey.md): Removes the secondary key from the staging slot. Useful for aborting rotation or correcting mistakes before promotion. Key Features: - Clears the secondary key slot - Idempotent: returns success even if secondary key doesn't exist - Safe for retries ### Sample Request in JavaScript: javascript async function deleteSecondaryKey(clientId) { try { const token = localStorage.getItem('jwt'); const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}/keys/secondary, { method: 'DELETE', headers: { 'Accept': 'application/json', 'Authorization': Bearer ${token} } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const metadata = await response.json(); console.log('Secondary key deleted:', { hasSecondaryKey: metadata.hasSecondaryKey // Now false }); return metadata; } catch (error) { console.error('Error deleting secondary key:', error); } } Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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. ### Promote secondary key to primary - [POST /v1/credentials/{clientId}/keys/promote](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_promotesecondarykey.md): Promotes the current secondary key to primary and clears the secondary slot. Use after validating the new key (optionally after challenge/verify). Key Features: - Makes the secondary key the new primary - Clears the secondary slot - Previous primary key is replaced ### Sample Request in JavaScript: javascript async function promoteSecondaryKey(clientId) { try { const token = localStorage.getItem('jwt'); const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}/keys/promote, { method: 'POST', headers: { 'Accept': 'application/json', 'Authorization': Bearer ${token} } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const metadata = await response.json(); console.log('Secondary key promoted to primary:', { hasPrimaryKey: metadata.hasPrimaryKey, hasSecondaryKey: metadata.hasSecondaryKey, // Now false primaryKeyFingerprint: metadata.primaryKeyFingerprint // Updated }); return metadata; } catch (error) { console.error('Error promoting secondary key:', error); } } Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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. ### Generate secondary key challenge - [POST /v1/credentials/{clientId}/keys/secondary/challenge](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_requestsecondarykeychallenge.md): Returns a time-limited challenge (Base64) that must be signed with the private key corresponding to the secondary public key. Proves ownership before promotion. Challenge Format: - Base64 encoding of: {clientId}.{nonce}.{expiry}.{keyFingerprint} - Sign the decoded raw bytes of this challenge (not the Base64 literal). - Valid for ~5 minutes - Bound to the current secondary key (fingerprint included) ### Sample Request in JavaScript: javascript async function requestChallenge(clientId) { try { const token = localStorage.getItem('jwt'); const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}/keys/secondary/challenge, { method: 'POST', headers: { 'Accept': 'application/json', 'Authorization': Bearer ${token} } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const { challenge, expiresUtc } = await response.json(); console.log('Challenge received:', { challenge, expiresUtc }); // Sign the challenge with your private key const crypto = require('crypto'); const privateKeyPem = process.env.PRIVATE_KEY; const sign = crypto.createSign('RSA-SHA256'); sign.update(Buffer.from(challenge, 'base64')); const signature = sign.sign({ key: privateKeyPem, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST }, 'base64'); console.log('Signature created, ready for verification'); return { challenge, signature }; } catch (error) { console.error('Error requesting challenge:', error); } } Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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. ### Verify secondary key ownership - [POST /v1/credentials/{clientId}/keys/secondary/verify](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/credentials/credentials_verifysecondarykeychallenge.md): Submit the Base64 challenge and its RSA-PSS signature (SHA-256). Important: sign the decoded raw bytes of the challenge, not the Base64 string literal. On success, the secondary key is marked as verified. Key Features: - Validates signature using RSA-PSS + SHA-256 - Checks challenge expiry (5-minute window) - Verifies challenge matches current secondary key - Sets secondaryKeyVerified: true on success ### Sample Request in JavaScript: javascript async function verifySecondaryKey(clientId, challenge, signature) { try { const token = localStorage.getItem('jwt'); const response = await fetch(https://api.bcb.bm/v1/credentials/${clientId}/keys/secondary/verify, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': Bearer ${token} }, body: JSON.stringify({ challenge: challenge, signature: signature }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const metadata = await response.json(); if (metadata.secondaryKeyVerified) { console.log('✓ Secondary key verified successfully!'); console.log('You can now promote it to primary or test with production traffic.'); } else { console.error('✗ Verification failed - signature did not match'); } return metadata; } catch (error) { console.error('Error verifying secondary key:', error); } } // Complete rotation flow example: // 1. Upload: await uploadSecondaryKey(clientId, publicKeyPem); // 2. Challenge: const { challenge, signature } = await requestChallenge(clientId); // 3. Verify: await verifySecondaryKey(clientId, challenge, signature); // 4. Promote: await promoteSecondaryKey(clientId); Required Permission: manage-credentials This endpoint requires the permission claim manage-credentials 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. ## Fx Quotes ### Get FX Quote - [GET /v1/fx-quotes](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/fx-quotes/fxquotes_get.md): Retrieves a foreign exchange quote for converting between currencies (for the requested pair and amount). The same quote will be automatically applied by the system to any internal transfer or payment involving two different currencies, provided it is used within its expiry time. ### High-Value Exchange Requests (> 100 000 BMD) If the requested exchange amount exceeds 100 000 BMD, the system will not return an automatic quote in the GET /v1/fx-quotes response. Instead, the request is routed for manual processing by our treasury desk to secure the most competitive rate available. ### 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/fx-quotes ### Validation Rules - Currencies must be valid three-letter ISO 4217 codes - Unit currency and currency of transfer must be different - Instructed amount must be a valid decimal number with up to 2 decimal places ### Sample Request in JavaScript: javascript // Get FX quote for converting 100 USD to EUR const getFxQuote = async (unitCurrency, currencyOfTransfer, instructedAmount) => { try { const response = await fetch( 'https://api.bcb.bm/v1/fx-quotes?' + new URLSearchParams({ unitCurrency: unitCurrency, currencyOfTransfer: currencyOfTransfer, instructedAmount: instructedAmount }), { method: 'GET', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json' } }); // Check if the response is ok (status in the range 200-299) if (!response.ok) { // Parse error response const errorData = await response.json(); throw new Error(Error ${response.status}: ${errorData.error} - ${errorData.message}); } // Parse successful response const quote = await response.json(); // Log the complete quote details console.log('FX Quote Details:'); console.log(Source Currency: ${quote.sourceCurrency.currency}); console.log(Source Amount: ${quote.sourceCurrency.amount}); console.log(Target Currency: ${quote.targetCurrency.currency}); console.log(Target Amount: ${quote.targetCurrency.amount}); console.log(Exchange Rate: ${quote.exchangeRate}); console.log(Quote Expires: ${new Date(quote.expiryDateTime).toLocaleString()}); // Return the processed quote return { ...quote, // Add formatted values for display formattedSourceAmount: new Intl.NumberFormat('en-US', { style: 'currency', currency: quote.sourceCurrency.currency }).format(quote.sourceCurrency.amount), formattedTargetAmount: new Intl.NumberFormat('en-US', { style: 'currency', currency: quote.targetCurrency.currency }).format(quote.targetCurrency.amount) }; } catch (error) { // Handle different types of errors if (error.name === 'TypeError') { console.error('Network error:', error.message); } else { console.error('API error:', error.message); } throw error; // Re-throw to let caller handle it } }; // Example usage with error handling: try { const quote = await getFxQuote('USD', 'EUR', '100.00'); console.log('Formatted Quote:', quote.formattedSourceAmount, '→', quote.formattedTargetAmount); } catch (error) { console.error('Failed to get FX quote:', error.message); } Required Permission: get-fx-quote This endpoint requires the permission claim get-fx-quote 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. ## Internal Transfers ### Internal Transfer - [POST /v1/internal-transfers](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/internal-transfers/internaltransfers_post.md): Initiates an internal funds transfer between two accounts within the institution. The request must include source and destination account details, along with the amount and currency to be transferred. Optionally, clients may provide a transaction reference and remittance information describing the purpose of the payment. - debitAccountNumber: The account number from which funds will be debited. - debitAmountCurrency: The currency code for the debit amount. Must match the credit account currency. - creditAccountNumber: The account number to be credited. - creditAmountCurrency: The currency code for the credit amount. Must match the debit account currency. - debitAmount: The amount to be transferred. - endToEndIdentification: (Optional) A unique reference provided by the client to identify the transaction end-to-end. - remittanceInformation: (Optional) Free-text remittance information describing the purpose of the transaction. ### Important Notes: - Transfers between accounts with different currencies are not allowed. The debit and credit account currencies must match. - Ensure all inputs are validated and the source account has sufficient funds before making the request. ### High-Value Exchange Requests (> 100 000 BMD) If the requested exchange amount exceeds 100 000 BMD, the POST /v1/transfers/internal endpoint will not return an immediate confirmation. Instead, the request is routed for manual processing by our treasury desk to secure the most competitive rate available. ### 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/internal-transfers ### Sample Request in JavaScript: javascript async function executeInternalTransfer() { try { const response = await fetch('https://api.bcb.bm/v1/internal-transfers', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Idempotency-Key': '123e4567-e89b-12d3-a456-426614174000' // Optional: UUID format required if provided }, body: JSON.stringify({ debitAccountNumber: "12345678901234567890123456", debitAmountCurrency: "USD", creditAccountNumber: "98765432109876543210987654", creditAmountCurrency: "USD", // Must match debitAmountCurrency debitAmount: "100.00", endToEndIdentification: "REF-INV-20250417-001", // Optional external transaction reference remittanceInformationUnstructured: "Payment for invoice #12345" // Optional payment description }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Transfer failed: ${JSON.stringify(errorData)}); } const data = await response.json(); console.log('Transfer result:', data); // Example processing of the returned object const { id, status, uniqueIdentifier, internalTransferDetails, linkedActivities } = data; const { amountCredited, creditAmountCurrency, debitAmount, amountDebited, chargeAmount, valueDate, chargeAnalysisReceiver, chargeAnalysisSender, debitAccountNumber, creditAccountNumber, chargeAccountNumber } = internalTransferDetails; // Log the main transfer details. console.log('Transaction ID:', id); console.log('Status:', status); console.log('Unique Identifier:', uniqueIdentifier); console.log('Amount Credited:', amountCredited.amount, amountCredited.currency); console.log('Credit Amount Currency:', creditAmountCurrency); console.log('Debit Amount:', debitAmount.amount, debitAmount.currency); console.log('Amount Debited:', amountDebited.amount, amountDebited.currency); console.log('Charge Amount:', chargeAmount.amount, chargeAmount.currency); console.log('Value Date:', valueDate); console.log('Charge Analysis Receiver:', chargeAnalysisReceiver); console.log('Charge Analysis Sender:', chargeAnalysisSender); // Process debit account information. console.log('Debit Account Number:', debitAccountNumber.number); if (debitAccountNumber.accountRoutings) { debitAccountNumber.accountRoutings.forEach(routing => { console.log('Debit Account Routing Scheme:', routing.scheme); console.log('Debit Account Routing Address:', routing.address); }); } // Process credit account information. console.log('Credit Account Number:', creditAccountNumber.number); if (creditAccountNumber.accountRoutings) { creditAccountNumber.accountRoutings.forEach(routing => { console.log('Credit Account Routing Scheme:', routing.scheme); console.log('Credit Account Routing Address:', routing.address); }); } // Process charge account information. console.log('Charge Account Number:', chargeAccountNumber.number); if (chargeAccountNumber.accountRoutings) { chargeAccountNumber.accountRoutings.forEach(routing => { console.log('Charge Account Routing Scheme:', routing.scheme); console.log('Charge Account Routing Address:', routing.address); }); } // 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 transfer was successful.'); } else { console.log('The transfer failed:', status); } } catch (error) { console.error('Error executing internal transfer:', error); } } executeInternalTransfer(); Required Permission: internal-transfer This endpoint requires the permission claim internal-transfer 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. ## Public Keys ### Gets the bank's current signing public key. - [GET /v1/.well-known/jwks.json](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/public-keys/publickeys_getjwks.md): Gets the bank’s current signing public key in JWKS format. Returns a JWKS containing one RSA key with fields: - kid: rsa-{keyVersion} - kty: RSA - alg: PS256 - use: sig - n/e: base64url-encoded modulus and exponent This endpoint requires OpenBankApi authorization; no private key material is exposed. ## Token ### Generate Token - [POST /auth/token](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/token/token_generatetoken.md): Generates a JWT access token based on provided client credentials. Use this POST endpoint to authenticate using your clientId and clientSecret and receive a JWT token. Token Validity: 40 minutes from the time of issuance. Endpoint: https://api.bcb.bm/auth/token Required Headers: - Content-Type: application/json - Accept: application/json ### Sample Request in JavaScript: javascript async function getToken() { try { const response = await fetch('https://api.bcb.bm/auth/token', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ clientId: 'your-client-id', clientSecret: 'your-client-secret' }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(Error: ${errorData.message || response.statusText}); } const data = await response.json(); console.log('JWT Token:', data.token); // Store token securely localStorage.setItem('jwt', data.token); } catch (error) { console.error('Fetch error:', error); } } getToken(); ## Transactions ### Account Transactions - [GET /v1/accounts/{accountNumber}/transactions](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/transactions/transactions_get.md): Retrieves transaction details for the specified account and date range. This endpoint: - Validates the provided date parameters. The accepted date formats are yyyy-MM-dd or yyyyMMdd. - Maximum date range is one year. - Supports both JSON and CSV response formats based on the Accept header. - Supports cursor-based pagination for efficient handling of large transaction datasets. ### Transaction ID Uniqueness Important: Transaction IDs are globally unique across the entire banking system. For internal transfers, the same transaction ID appears on both accounts (debit and credit entries) with only the transaction type differing. When fees apply, multiple entries may share the same transaction ID. 📖 For detailed information about transaction ID behavior, see: https://developers.bcb.bm/guides/transaction-id-uniqueness-guide ### 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/accounts/{accountNumber}/transactions ### Sample Request in JavaScript javascript async function getAllTransactionsPaginated(accountNumber, fromDate, toDate) { try { let allTransactions = []; let pageStart = 1; let pageToken = null; let totalPages = 0; do { // Build URL with pagination parameters let url = https://api.bcb.bm/v1/accounts/${accountNumber}/transactions; const params = new URLSearchParams(); // Always include date range params.append('fromDate', fromDate); params.append('toDate', toDate); if (pageStart === 1) { // First request: specify pageSize params.append('pageSize', '100'); } else { // Subsequent requests: use pageToken and pageStart 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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log(Page ${pageStart} data:, data); // Store pagination info from first request if (pageStart === 1 && data.meta && data.meta.pagination) { pageToken = data.meta.pagination.page_token; totalPages = Math.ceil(data.meta.pagination.total_size / data.meta.pagination.page_size); console.log(Total pages: ${totalPages}, Page token: ${pageToken}); } // Collect transactions from this page if (data.data && data.data.length > 0) { allTransactions.push(...data.data); console.log(Collected ${data.data.length} transactions from page ${pageStart}); } pageStart++; } while (pageStart { console.log(Transaction ${index + 1}:, transaction.id); console.log('Account Number:', transaction.thisAccount.number); console.log('Other Account Number:', transaction.otherAccount.number); console.log('Type:', transaction.details.type); console.log('Description:', transaction.details.description); console.log('Posted Date:', transaction.details.posted); console.log('Amount:', transaction.details.value.amount); console.log('Currency:', transaction.details.value.currency); console.log('Narrative:', transaction.metadata.narrative); if (transaction.transactionAttributes && transaction.transactionAttributes.length > 0) { transaction.transactionAttributes.forEach(attribute => { console.log(${attribute.name}: ${attribute.value}); }); } }); return allTransactions; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Alternative: Get single page of transactions async function getTransactionsPage(accountNumber, fromDate, toDate, pageStart = 1, pageToken = null) { try { let url = https://api.bcb.bm/v1/accounts/${accountNumber}/transactions; const params = new URLSearchParams(); // Always include date range params.append('fromDate', fromDate); params.append('toDate', toDate); if (pageStart === 1 && !pageToken) { params.append('pageSize', '250'); // Custom page size } else { 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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log('Transactions page:', data); return data; } catch (error) { console.error('There was a problem with the fetch operation:', error.message); throw error; } } // Example usage: getAllTransactionsPaginated('1234567890', '2023-01-25', '2023-02-25'); // Retrieves all transactions across multiple pages // OR getTransactionsPage('1234567890', '2023-01-25', '2023-02-25', 1).then(firstPage => { console.log('First page:', firstPage); // Use firstPage.meta.pagination.page_token for subsequent requests }); Required Permission: get-transactions This endpoint requires the permission claim get-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 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. ## Notifications ### Create a new notification subscription - [POST /v1/notifications/subscriptions](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/notifications/notifications_create.md): Registers a webhook subscription to receive real-time deposit notifications. ### Notification Pipeline Overview: This endpoint is part of a two-stage deposit notification system: Stage 1: Subscription Setup (this endpoint) - Customers register their webhook URL and topic (e.g., "Deposits") - The system stores the subscription with optional custom headers - Subscriptions can be activated or deactivated Stage 2: Webhook Delivery - The system matches received events with active subscriptions - Webhooks are delivered to registered endpoints with retry logic ### Webhook Payload Structure: When a deposit matches your subscription, you'll receive a POST request to your webhook URL containing: json { "subscriptionId": "e2a55504-3924-4b48-9d7e-540efcd6fa30", "topic": "Deposits", "accountNumber": "1046406142", "transactionId": "FT2384654NXF6", "type": "Credit", "value": { "amount": "1000.00", "currency": "USD" }, "transactionType": "Swift payment", "transactionDetails": "Payment details" } The webhook payload is defined by the NotificationResponse model. ### Message Signing: Webhook requests are signed for authenticity and replay protection. - Asymmetric option (RSA-PSS + SHA-256): When response signing is enabled for your client configuration, webhooks include Bcb-Signature, Bcb-Timestamp, Bcb-Nonce, and Bcb-Signature-Version (e.g., rsa-v1). Verify using the bank public key from /v1/.well-known/jwks.json and the canonical string {timestamp}{nonce}{METHOD}{path}{body}. - HMAC option: If Bcb-Signature-Version is absent, the webhook uses your Message Signing Secret returned by the credentials endpoints. Use the same signature string {timestamp}{nonce}{METHOD}{path}{body} and compare an HMAC-SHA256 hash. - Replay protection: Enforce ±5 minute timestamp tolerance and reject any repeated {timestamp}:{nonce} pairs (cache the nonce for 5 minutes). See the Message Signing guide for full RSA and HMAC verification examples. ### Idempotency: This endpoint supports idempotency through the optional Idempotency-Key header: - If no idempotency key is provided, the request is processed normally - If a valid UUID idempotency key is provided, the system prevents duplicate subscriptions - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000") Required Permission: receive-notifications This endpoint requires the permission claim receive-notifications 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. ### List subscriptions - [GET /v1/notifications/subscriptions](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/notifications/notifications_getall.md): Retrieves all notification subscriptions for the authenticated client with pagination support. ### Pagination: - Use pageStart to specify the starting page (default: 1) - Use pageSize to specify the number of items per page (default: 100, max: 500) - The response includes total count and pagination metadata ### Response Details: Returns a paginated list of subscriptions, each containing: - Subscription ID (guid) - Topic (e.g., "Deposits") - Webhook URL - Status (IsActive flag) - Creation and update timestamps ### Filtering: - Only returns subscriptions owned by the authenticated client - Includes both active and inactive subscriptions - Results are ordered by creation date (newest first) Required Permission: receive-notifications This endpoint requires the permission claim receive-notifications 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. ### Deactivate a subscription - [DELETE /v1/notifications/subscriptions/{subscriptionId}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/notifications/notifications_delete.md): Deactivates an existing notification subscription. Once deactivated: - The subscription will no longer receive webhook notifications - Future deposits will not be matched to this subscription - In-flight notifications will continue to be delivered - The subscription record remains in the system but with IsActive=false ### Behavior: - Only the subscription owner can deactivate their own subscription - Attempting to deactivate another client's subscription returns 404 Not Found - Deactivating an already inactive subscription is idempotent (returns success) ### Idempotency: This endpoint supports idempotency through the optional Idempotency-Key header: - If a valid UUID idempotency key is provided, repeated calls with the same key return the same result - The idempotency key must be a valid UUID format (e.g., "123e4567-e89b-12d3-a456-426614174000") Required Permission: receive-notifications This endpoint requires the permission claim receive-notifications 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 subscription - [GET /v1/notifications/subscriptions/{subscriptionId}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/notifications/notifications_get.md): Retrieves a specific notification subscription by its unique identifier. ### Response Details: The response includes: - Subscription ID (guid) - Topic (e.g., "Deposits") - Webhook URL - Status (IsActive flag) - Creation and update timestamps - Client association ### Security: - Only the subscription owner can retrieve their own subscription - Attempting to retrieve another client's subscription returns 404 Not Found Required Permission: receive-notifications This endpoint requires the permission claim receive-notifications 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. ## Background Jobs ### Get All Background Jobs - [GET /v1/jobs](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/background-jobs/backgroundjobs_getall.md): Retrieves a paginated list of background jobs for the authenticated client. This endpoint: - Returns only active jobs (status: Pending or InProgress) - Completed, failed, or cancelled jobs are not included in this list - Provides job status information including progress summaries - Supports pagination for efficient handling of large job datasets ### Job Status Information Each job entry includes: - JobId: Unique identifier for the batch job - JobStatus: Current status (Pending, InProgress, Completed, CompletedWithErrors, Cancelled) - Pending: Job has been created and is waiting to be processed - InProgress: Job is currently being processed - Completed: Job has completed successfully with no errors - CompletedWithErrors: Job has completed but some items failed during processing - Cancelled: Job has been cancelled and will not be processed further - EventType: Type of status event (typically "job.status") - Summary: Progress statistics (Total, Completed, Failed counts) ### Pagination This endpoint uses simple numeric pagination: - pageStart: 1-based index of the first record to return (default: 1) - pageSize: Number of records to return (default: 100, maximum: 1000) - Total Pages: Calculate using Math.ceil(total_size / page_size) from 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/jobs ### Sample Request in JavaScript javascript async function getAllBackgroundJobs(pageStart = 1, pageSize = 50) { try { // Build URL with pagination parameters let url = 'https://api.bcb.bm/v1/jobs'; const params = new URLSearchParams(); params.append('pageStart', pageStart.toString()); params.append('pageSize', pageSize.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(Background jobs 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 background jobs result.data.forEach((job, index) => { console.log(Job ${index + 1}:); console.log( Job ID: ${job.jobId}); console.log( Status: ${job.jobStatus}); console.log( Event Type: ${job.eventType}); console.log( Summary:); console.log( Total: ${job.summary.total}); console.log( Completed: ${job.summary.completed}); console.log( Failed: ${job.summary.failed}); console.log('---'); }); return result; } catch (error) { console.error('Failed to retrieve background jobs:', error.message); throw error; } } // Example usage: // Get first 50 jobs getAllBackgroundJobs(1, 50); // Get next page getAllBackgroundJobs(2, 50); // Get all jobs with default pagination getAllBackgroundJobs(); ### Get Job Status - [GET /v1/jobs/{jobId}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/background-jobs/backgroundjobs_get.md): Retrieves the current status and progress information for a specific background job. This endpoint: - Returns detailed status information for the specified job - Provides real-time progress statistics (total, completed, failed counts) - Shows current job status (Pending, InProgress, Completed, Failed, Cancelled) - Includes event type information for status tracking ### Job Status Information The response includes: - JobId: Unique identifier for the batch job - JobStatus: Current status (Pending, InProgress, Completed, CompletedWithErrors, Cancelled) - Pending: Job has been created and is waiting to be processed - InProgress: Job is currently being processed - Completed: Job has completed successfully with no errors - CompletedWithErrors: Job has completed but some items failed during processing - Cancelled: Job has been cancelled and will not be processed further - EventType: Type of status event (typically "job.status") - Summary: Progress statistics (Total, Completed, Failed counts) ### Callback Notifications When a job reaches a completed state (Completed or CompletedWithErrors), the system automatically sends a callback notification to the callbackUrl provided during job creation (if specified). This callback allows you to receive real-time notifications without polling the status endpoint. Sample Callback Payload: json { "eventType": "job.completed", "jobId": "badabb89-8cdb-4d3d-aaf0-c714f487f1bc", "jobStatus": "Completed", "summary": { "total": 1, "completed": 1, "failed": 0 } } ### 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. ### 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/jobs/{jobId} ### Sample Request in JavaScript javascript async function getJobStatus(jobId) { try { const url = https://api.bcb.bm/v1/jobs/${jobId}; 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(Job status retrieval failed: ${JSON.stringify(errorData)}); } // Parse JSON response const jobStatus = await response.json(); // Display job information console.log('Job Status:'); console.log( Job ID: ${jobStatus.jobId}); console.log( Status: ${jobStatus.jobStatus}); console.log( Event Type: ${jobStatus.eventType}); console.log( Progress Summary:); console.log( Total Items: ${jobStatus.summary.total}); console.log( Completed: ${jobStatus.summary.completed}); console.log( Failed: ${jobStatus.summary.failed}); console.log( Progress: ${((jobStatus.summary.completed / jobStatus.summary.total) * 100).toFixed(1)}%); return jobStatus; } catch (error) { console.error('Failed to retrieve job status:', error.message); throw error; } } // Example usage: // Get status for a specific job getJobStatus('550e8400-e29b-41d4-a716-446655440001'); ### Cancel Job - [DELETE /v1/jobs/{jobId}](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/background-jobs/backgroundjobs_canceljob.md): Cancels a background job and stops processing of all pending and in-progress items. This endpoint: - Cancels the specified job if it's in a cancellable state - Stops processing of all pending and in-progress items within the job - Marks cancelled items with appropriate error messages - Returns the updated job status after cancellation - Provides immediate feedback on cancellation success ### Cancellation Rules A job can only be cancelled if it's in one of these states: - Pending: Job has been created but not yet started processing - InProgress: Job is currently being processed Jobs in these states cannot be cancelled: - Completed: Job has already finished successfully - CompletedWithErrors: Job has finished with some failures - Cancelled: Job has already been cancelled ### What Happens During Cancellation 1. Job Status Update: The job status is changed to "Cancelled" 2. Item Cancellation: All pending and in-progress items are marked as "Cancelled" 3. Error Messages: Cancelled items receive the error message "Job was cancelled by user request" 4. Counter Updates: Job completion counters are recalculated from the database 5. Immediate Effect: Processing stops immediately for all affected items ### 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/jobs/{jobId} ### 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 cancelJob(jobId) { try { const url = https://api.bcb.bm/v1/jobs/${jobId}; const response = await fetch(url, { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN', 'Content-Type': 'application/json', 'Accept': 'application/json' } }); if (!response.ok) { const errorData = await response.json(); throw new Error(Job cancellation failed: ${JSON.stringify(errorData)}); } // Parse JSON response const jobStatus = await response.json(); // Display cancellation result console.log('Job Cancellation Result:'); console.log( Job ID: ${jobStatus.jobId}); console.log( Status: ${jobStatus.jobStatus}); console.log( Event Type: ${jobStatus.eventType}); console.log( Final Summary:); console.log( Total Items: ${jobStatus.summary.total}); console.log( Completed: ${jobStatus.summary.completed}); console.log( Failed: ${jobStatus.summary.failed}); console.log( Cancelled: ${jobStatus.summary.total - jobStatus.summary.completed - jobStatus.summary.failed}); return jobStatus; } catch (error) { console.error('Failed to cancel job:', error.message); throw error; } } // Example usage: // Cancel a specific job cancelJob('550e8400-e29b-41d4-a716-446655440001'); ### Get Job Results - [GET /v1/jobs/{jobId}/results](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/background-jobs/backgroundjobs_getresults.md): Retrieves the detailed results for a specific background job. This endpoint: - Returns paginated results for all items processed in the job - Provides detailed information about each item's processing outcome - Shows processing status, attempts, HTTP responses, and error details - Includes original payload and result data for auditing - Supports pagination for efficient handling of large result sets ### Job Results Information Each result entry includes: - Id: Internal numeric identifier for this item result - JobId: Identifier of the parent batch job - ExternalItemId: Client-supplied item identifier from the original batch - PayloadJson: Original request payload serialized as JSON - Status: Current processing status (Pending, InProgress, Completed, Failed, Cancelled) - Attempt: Number of processing attempts made for this item - HttpStatusCode: HTTP status code returned by the target endpoint - ResultJson: Response payload from the target endpoint (if successful) - ErrorMessage: Error details (if processing failed) ### Pagination This endpoint uses simple numeric pagination: - pageStart: 1-based index of the first record to return (default: 1) - pageSize: Number of records to return (default: 100, maximum: 1000) - Total Pages: Calculate using Math.ceil(total_size / page_size) from 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/jobs/{jobId}/results ### Sample Request in JavaScript javascript async function getJobResults(jobId, pageStart = 1, pageSize = 50) { try { const url = https://api.bcb.bm/v1/jobs/${jobId}/results; const params = new URLSearchParams(); params.append('pageStart', pageStart.toString()); params.append('pageSize', pageSize.toString()); const fullUrl = url + '?' + params.toString(); const response = await fetch(fullUrl, { 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(Job results 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 job results result.data.forEach((item, index) => { console.log(Result ${index + 1}:); console.log( Item ID: ${item.externalItemId}); console.log( Status: ${item.status}); console.log( Attempts: ${item.attempt}); console.log( HTTP Status: ${item.httpStatusCode}); if (item.errorMessage) { console.log( Error: ${item.errorMessage}); } if (item.resultJson) { console.log( Result: ${item.resultJson}); } console.log('---'); }); return result; } catch (error) { console.error('Failed to retrieve job results:', error.message); throw error; } } // Example usage: // Get first 50 results for a job getJobResults('550e8400-e29b-41d4-a716-446655440001', 1, 50); // Get next page of results getJobResults('550e8400-e29b-41d4-a716-446655440001', 2, 50); // Get all results with default pagination getJobResults('550e8400-e29b-41d4-a716-446655440001'); ## System ### Get system time - [GET /v1/system/time](https://developers.bcb.bm/apis/open-banking-api/open-banking-api/system/system_getsystemtime.md): Returns the current server date and time in ISO-8601 format. This endpoint helps integrators synchronize with the server clock and craft valid date/time windows for other API requests. The response contains two fields: 1. timestamp – Current Bermuda local time in ISO-8601 format with the correct offset (e.g., 2025-01-07T14:30:15-04:00). 2. timeZone – Display name of the time zone currently in effect ("Atlantic Daylight Time" or "Atlantic Standard Time"). This allows clients to know both the precise instant and whether Daylight-Saving Time is observed. ### Content Negotiation Clients must use the HTTP Accept header to indicate the desired response format: - Set Accept: application/json for JSON responses (default) 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/system/time ### Sample Request in JavaScript: javascript async function getSystemTime() { try { const response = await fetch('https://api.bcb.bm/v1/system/time', { 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(Error: ${errorData.message || 'Unknown error'}); } const data = await response.json(); console.log('Server timestamp (Bermuda time UTC-4):', data.timestamp); return data; } catch (error) { console.error('There was a problem retrieving system time:', error.message); } } // Example usage: getSystemTime();