Skip to content

Bermuda Commercial Bank RESTful Open Banking API Implementation (v1)

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

Download OpenAPI description
Overview
URL
Bermuda Commercial Bank Limited, 34 Bermudiana Road, Hamilton HM 11, Bermuda
Languages
Servers
Mock server
https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/
UAT Environment - Used for testing and integration purposes
https://api-uat.bcb.bm/
Production Environment - Live environment for production use
https://api.bcb.bm/

Accounts

Operations

Payments

Operations

Credentials

Operations

Create new API client credentials

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Bodyapplication/json
allowedIpsstring or null[ 0 .. 1000 ] characters

Optional IP address restrictions for the new client credentials. If omitted (null/empty) or set to "*", all IP addresses will be allowed. Otherwise, specify a comma-separated list of allowed IP addresses and/or CIDR ranges.

Example: "192.168.1.1,10.0.0.0/24,2001:db8::/32"
curl -i -X POST \
  https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "allowedIps": "192.168.1.1,192.168.1.2"
  }'

Responses

Credentials created successfully

Bodyapplication/json
clientIdstringrequired

Unique client identifier (GUID) assigned by the authorization server. This identifier is used in conjunction with the client secret for API authentication.

clientSecretstringrequired

Client secret assigned by the authorization server.

isActivebooleanrequired

Value indicating whether the client credentials are currently active and can be used for authentication.

allowedIpsstring or null

IP address restrictions for the client credentials. Defines which IP addresses or IP ranges are allowed to use these credentials for authentication.

messageSigningSecretstringrequired

Base64-encoded 32-byte secret used to sign messages for authentication or integrity verification.

Response
application/json
{ "clientId": "a1b2c3d4-e5f6-4789-b012-3456789abcde", "clientSecret": "Abc123XyzP9mN7kLAbc123XyzP95", "isActive": true, "allowedIps": "192.168.1.1,192.168.1.2", "messageSigningSecret": "HtYp2oJm5DwQ1xL8bSeRgUkN4vZc3PhYtLwSxV2N9Cs=" }

Rotate the client secret for an existing API client

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired

The unique identifier of the client whose secret should be rotated

curl -i -X PATCH \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/{clientId}' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>'

Responses

Secret rotated successfully

Bodyapplication/json
clientIdstringrequired

Unique client identifier (GUID) assigned by the authorization server. This identifier is used in conjunction with the client secret for API authentication.

clientSecretstringrequired

Client secret assigned by the authorization server.

isActivebooleanrequired

Value indicating whether the client credentials are currently active and can be used for authentication.

allowedIpsstring or null

IP address restrictions for the client credentials. Defines which IP addresses or IP ranges are allowed to use these credentials for authentication.

messageSigningSecretstringrequired

Base64-encoded 32-byte secret used to sign messages for authentication or integrity verification.

Response
application/json
{ "clientId": "a1b2c3d4-e5f6-4789-b012-3456789abcde", "clientSecret": "Abc123XyzP9mN7kLAbc123XyzP95", "isActive": true, "allowedIps": "192.168.1.1,192.168.1.2", "messageSigningSecret": "HtYp2oJm5DwQ1xL8bSeRgUkN4vZc3PhYtLwSxV2N9Cs=" }

Disable an existing API client

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired

The unique identifier of the client to disable

curl -i -X DELETE \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/{clientId}' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>'

Responses

Client disabled successfully

Bodyapplication/json
clientIdstringrequired

Unique client identifier (GUID) assigned by the authorization server. This identifier is used in conjunction with the client secret for API authentication.

clientSecretstringrequired

Client secret assigned by the authorization server.

isActivebooleanrequired

Value indicating whether the client credentials are currently active and can be used for authentication.

allowedIpsstring or null

IP address restrictions for the client credentials. Defines which IP addresses or IP ranges are allowed to use these credentials for authentication.

messageSigningSecretstringrequired

Base64-encoded 32-byte secret used to sign messages for authentication or integrity verification.

Response
application/json
{ "clientId": "a1b2c3d4-e5f6-7890-abcd-123456789def", "clientSecret": "", "isActive": false, "allowedIps": "192.168.1.100,10.0.0.0/24", "messageSigningSecret": null }

Get permissions for an existing API client

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired

The unique identifier of the client to retrieve permissions for

curl -i -X GET \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/{clientId}/permissions' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>'

Responses

Permissions retrieved successfully

Bodyapplication/jsonArray [
keystringrequired

Unique permission key that identifies the specific permission. Used in authorization checks and JWT token claims.

Example: "get-account"
descriptionstring or null

Human-readable description of what this permission allows. Provides context for administrators managing client permissions.

Example: "Allows access to account information endpoints"
]
Response
application/json
[ { "key": "get-account", "description": "Allows access to retrieve individual account information" }, { "key": "get-all-accounts", "description": "Allows access to retrieve all accounts for a customer" }, { "key": "get-fx-quote", "description": "Allows access to foreign exchange quote endpoints" }, { "key": "get-transactions", "description": "Allows access to transaction history endpoints" }, { "key": "get-payment-status", "description": "Allows access to payment status tracking endpoints" }, { "key": "make-internal-transfer", "description": "Allows execution of internal transfers between accounts" }, { "key": "make-payment-swift", "description": "Allows execution of SWIFT payment transactions" }, { "key": "manage-credentials", "description": "Allows management of API client credentials and permissions" } ]

Get public key metadata

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired
curl -i -X GET \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/{clientId}/keys' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>'

Responses

Bodyapplication/json
hasPrimaryKeybooleanrequired

True when a primary partner public key is configured.

hasSecondaryKeybooleanrequired

True when a secondary partner public key is configured (staged for rotation).

primaryKeyFingerprintstring or null

Short fingerprint of the primary key (first 8 bytes of SHA-256 over canonical key).

secondaryKeyFingerprintstring or null

Short fingerprint of the secondary key (first 8 bytes of SHA-256 over canonical key).

primaryKeyAlgorithmstring or null

Algorithm/size description of the primary key (e.g., RSA-2048).

secondaryKeyAlgorithmstring or null

Algorithm/size description of the secondary key (e.g., RSA-2048).

primaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the primary key was last updated.

secondaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the secondary key was last updated.

secondaryKeyVerifiedbooleanrequired

Indicates whether the secondary key has been verified via challenge.

secondaryKeyVerifiedUtcstring or null(date-time)

Timestamp when the secondary key was last verified.

Response
application/json
{ "hasPrimaryKey": true, "hasSecondaryKey": true, "primaryKeyFingerprint": "A1B2C3D4E5F60708", "secondaryKeyFingerprint": "0F1E2D3C4B5A6978", "primaryKeyAlgorithm": "RSA-3072", "secondaryKeyAlgorithm": "RSA-3072", "primaryKeyUpdatedUtc": "2026-03-22T12:47:20.8993822Z", "secondaryKeyUpdatedUtc": "2026-04-01T12:47:20.8994091Z", "secondaryKeyVerified": false, "secondaryKeyVerifiedUtc": null }

Upload secondary public key

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired
Example: publicKeyPem,-----BEGIN PUBLIC KEY----- MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxq1RqYIgYOb7H1uxC5mS M8s2Dhrz6sGJYvRq9A0KIf8v0pqm+9B6ZcM+3PEm2rUp7N0CYaUtR32W0bz1gM/b d3BFPFdcTnMjYwXomfjAZW9XvsC8t7y7mNLgO2cMYk2fT7k6aQp0yrzmmkCudIsc q4drqgG/Kxi4SpwYgYYnZ2hEo6VtV5JpR6TfyxwTXXxoH1WPr5oH7D8fFvG3a7dD RZl/vM8UzA2yN6lcn/zoVPQ7xY9qaTYjz4cmOcuQKBgQCQKBgQCQKBgQCQKBgQ -----END PUBLIC KEY-----
Bodyapplication/jsonrequired
publicKeyPemstringnon-emptyrequired
curl -i -X PUT \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/[object Object]/keys/secondary' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxq1RqYIgYOb7H1uxC5mS\nM8s2Dhrz6sGJYvRq9A0KIf8v0pqm+9B6ZcM+3PEm2rUp7N0CYaUtR32W0bz1gM/b\nd3BFPFdcTnMjYwXomfjAZW9XvsC8t7y7mNLgO2cMYk2fT7k6aQp0yrzmmkCudIsc\nq4drqgG/Kxi4SpwYgYYnZ2hEo6VtV5JpR6TfyxwTXXxoH1WPr5oH7D8fFvG3a7dD\nRZl/vM8UzA2yN6lcn/zoVPQ7xY9qaTYjz4cmOcuQKBgQCQKBgQCQKBgQCQKBgQ\n-----END PUBLIC KEY-----"
  }'

Responses

Bodyapplication/json
hasPrimaryKeybooleanrequired

True when a primary partner public key is configured.

hasSecondaryKeybooleanrequired

True when a secondary partner public key is configured (staged for rotation).

primaryKeyFingerprintstring or null

Short fingerprint of the primary key (first 8 bytes of SHA-256 over canonical key).

secondaryKeyFingerprintstring or null

Short fingerprint of the secondary key (first 8 bytes of SHA-256 over canonical key).

primaryKeyAlgorithmstring or null

Algorithm/size description of the primary key (e.g., RSA-2048).

secondaryKeyAlgorithmstring or null

Algorithm/size description of the secondary key (e.g., RSA-2048).

primaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the primary key was last updated.

secondaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the secondary key was last updated.

secondaryKeyVerifiedbooleanrequired

Indicates whether the secondary key has been verified via challenge.

secondaryKeyVerifiedUtcstring or null(date-time)

Timestamp when the secondary key was last verified.

Response
application/json
{ "hasPrimaryKey": true, "hasSecondaryKey": true, "primaryKeyFingerprint": "A1B2C3D4E5F60708", "secondaryKeyFingerprint": "0F1E2D3C4B5A6978", "primaryKeyAlgorithm": "RSA-3072", "secondaryKeyAlgorithm": "RSA-3072", "primaryKeyUpdatedUtc": "2026-03-22T12:47:20.9116007Z", "secondaryKeyUpdatedUtc": "2026-04-01T12:47:20.9116022Z", "secondaryKeyVerified": false, "secondaryKeyVerifiedUtc": null }

Delete secondary public key

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired
curl -i -X DELETE \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/{clientId}/keys/secondary' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>'

Responses

Bodyapplication/json
hasPrimaryKeybooleanrequired

True when a primary partner public key is configured.

hasSecondaryKeybooleanrequired

True when a secondary partner public key is configured (staged for rotation).

primaryKeyFingerprintstring or null

Short fingerprint of the primary key (first 8 bytes of SHA-256 over canonical key).

secondaryKeyFingerprintstring or null

Short fingerprint of the secondary key (first 8 bytes of SHA-256 over canonical key).

primaryKeyAlgorithmstring or null

Algorithm/size description of the primary key (e.g., RSA-2048).

secondaryKeyAlgorithmstring or null

Algorithm/size description of the secondary key (e.g., RSA-2048).

primaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the primary key was last updated.

secondaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the secondary key was last updated.

secondaryKeyVerifiedbooleanrequired

Indicates whether the secondary key has been verified via challenge.

secondaryKeyVerifiedUtcstring or null(date-time)

Timestamp when the secondary key was last verified.

Response
application/json
{ "hasPrimaryKey": true, "hasSecondaryKey": true, "primaryKeyFingerprint": "A1B2C3D4E5F60708", "secondaryKeyFingerprint": "0F1E2D3C4B5A6978", "primaryKeyAlgorithm": "RSA-3072", "secondaryKeyAlgorithm": "RSA-3072", "primaryKeyUpdatedUtc": "2026-03-22T12:47:20.9202624Z", "secondaryKeyUpdatedUtc": "2026-04-01T12:47:20.9202638Z", "secondaryKeyVerified": false, "secondaryKeyVerifiedUtc": null }

Promote secondary key to primary

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired
curl -i -X POST \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/{clientId}/keys/promote' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>'

Responses

Bodyapplication/json
hasPrimaryKeybooleanrequired

True when a primary partner public key is configured.

hasSecondaryKeybooleanrequired

True when a secondary partner public key is configured (staged for rotation).

primaryKeyFingerprintstring or null

Short fingerprint of the primary key (first 8 bytes of SHA-256 over canonical key).

secondaryKeyFingerprintstring or null

Short fingerprint of the secondary key (first 8 bytes of SHA-256 over canonical key).

primaryKeyAlgorithmstring or null

Algorithm/size description of the primary key (e.g., RSA-2048).

secondaryKeyAlgorithmstring or null

Algorithm/size description of the secondary key (e.g., RSA-2048).

primaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the primary key was last updated.

secondaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the secondary key was last updated.

secondaryKeyVerifiedbooleanrequired

Indicates whether the secondary key has been verified via challenge.

secondaryKeyVerifiedUtcstring or null(date-time)

Timestamp when the secondary key was last verified.

Response
application/json
{ "hasPrimaryKey": true, "hasSecondaryKey": true, "primaryKeyFingerprint": "A1B2C3D4E5F60708", "secondaryKeyFingerprint": "0F1E2D3C4B5A6978", "primaryKeyAlgorithm": "RSA-3072", "secondaryKeyAlgorithm": "RSA-3072", "primaryKeyUpdatedUtc": "2026-03-22T12:47:20.9167024Z", "secondaryKeyUpdatedUtc": "2026-04-01T12:47:20.9167031Z", "secondaryKeyVerified": false, "secondaryKeyVerifiedUtc": null }

Generate secondary key challenge

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired
curl -i -X POST \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/{clientId}/keys/secondary/challenge' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>'

Responses

Bodyapplication/json
challengestringrequired

Base64-encoded challenge string. Format: {clientId}.{nonce}.{expiry}.{keyFingerprint} (UTF-8 then Base64). Sign this exact Base64 value with your private key using RSA-PSS + SHA-256.

expiresUtcstring(date-time)required

When this challenge expires (UTC). Request a new challenge after this time.

Response
application/json
{ "challenge": "Y2xpZW50SWQubm9uY2UuMTcwMDAwMDAwMC5BMTIzRjQ1RjY3OA==", "expiresUtc": "2026-04-01T12:52:20.9261693Z" }

Verify secondary key ownership

Request

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:

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.

Security
(Authorization and Feature Permissions) or Authorization
Path
clientIdstringrequired
Example: challenge,Y2xpZW50SWQubm9uY2UuMTcwMDAwMDAwMC5BMTIzRjQ1RjY3OA==,signature,MEUCIQC0j7Xf7PqJ8n+q2eVY7k1nqM+UogYNDpFQ2a3E7Xy1zwIgFqYY3d3rVfJq8zlfjtqZ5rXwzBkVxH93+zVTe6y8ygE=
Bodyapplication/jsonrequired
challengestringnon-emptyrequired

Base64-encoded challenge issued by the bank (unchanged from the response).

signaturestringnon-emptyrequired

Base64-encoded RSA-PSS (SHA-256) signature of the Base64 challenge, generated with the partner private key.

curl -i -X POST \
  'https://developers.bcb.bm/_mock/apis/open-banking-api/open-banking-api/v1/credentials/[object Object]/keys/secondary/verify' \
  -H 'Authorization: Bearer <YOUR_jwt_HERE>' \
  -H 'Content-Type: application/json' \
  -d '{
    "challenge": "Y2xpZW50SWQubm9uY2UuMTcwMDAwMDAwMC5BMTIzRjQ1RjY3OA==",
    "signature": "MEUCIQC0j7Xf7PqJ8n+q2eVY7k1nqM+UogYNDpFQ2a3E7Xy1zwIgFqYY3d3rVfJq8zlfjtqZ5rXwzBkVxH93+zVTe6y8ygE="
  }'

Responses

Bodyapplication/json
hasPrimaryKeybooleanrequired

True when a primary partner public key is configured.

hasSecondaryKeybooleanrequired

True when a secondary partner public key is configured (staged for rotation).

primaryKeyFingerprintstring or null

Short fingerprint of the primary key (first 8 bytes of SHA-256 over canonical key).

secondaryKeyFingerprintstring or null

Short fingerprint of the secondary key (first 8 bytes of SHA-256 over canonical key).

primaryKeyAlgorithmstring or null

Algorithm/size description of the primary key (e.g., RSA-2048).

secondaryKeyAlgorithmstring or null

Algorithm/size description of the secondary key (e.g., RSA-2048).

primaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the primary key was last updated.

secondaryKeyUpdatedUtcstring or null(date-time)

Timestamp when the secondary key was last updated.

secondaryKeyVerifiedbooleanrequired

Indicates whether the secondary key has been verified via challenge.

secondaryKeyVerifiedUtcstring or null(date-time)

Timestamp when the secondary key was last verified.

Response
application/json
{ "hasPrimaryKey": true, "hasSecondaryKey": true, "primaryKeyFingerprint": "A1B2C3D4E5F60708", "secondaryKeyFingerprint": "0F1E2D3C4B5A6978", "primaryKeyAlgorithm": "RSA-3072", "secondaryKeyAlgorithm": "RSA-3072", "primaryKeyUpdatedUtc": "2026-03-22T12:47:20.9357266Z", "secondaryKeyUpdatedUtc": "2026-04-01T12:47:20.9357276Z", "secondaryKeyVerified": false, "secondaryKeyVerifiedUtc": null }

Testing

Operations

Fx Quotes

Operations

Internal Transfers

Operations

Public Keys

Operations

Token

Operations

Transactions

Operations

Virtual Accounts

Operations

Notifications

Operations

Background Jobs

Operations

System

Operations