BBK Embedded Finance SDK v1.0.0

Partner Integration Guide

Embed BBK Bank's mortgage application widget on your website with a few lines of code. Customers can apply for mortgages without leaving your platform.

Quick Start #

Integrate the BBK mortgage widget in three steps. No build tools, no dependencies.

Add the SDK script

Include the BBK SDK in your HTML. This single file contains everything needed.

HTML
<script src="https://sdk.bbk.com/v1/bbk-embed.js"></script>

Initialize with your API key

Call BBK.init() with your public API key. Use pk_test_ keys for sandbox and pk_live_ for production.

JavaScript
<script> BBK.init({ apiKey: 'pk_test_YOUR_API_KEY', partnerId: 'your-partner-id' }); </script>

Open the widget

Call BBK.open() when a customer clicks your "Apply for Mortgage" button. Pass property details to pre-fill the form.

HTML
<button onclick="BBK.open({ name: 'Modern Villa', price: 185000 })"> Apply for BBK Mortgage </button>
That is all you need. The widget opens as a modal overlay with the complete mortgage flow: calculator, results, document upload, and submission. Customer data goes directly to BBK's secure infrastructure -- it never passes through your servers.

Installation #

CDN (Recommended)

HTML
<!-- Production --> <script src="https://sdk.bbk.com/v1/bbk-embed.min.js"></script> <!-- Sandbox / Testing --> <script src="https://sdk.bbk.com/v1/bbk-embed.js"></script>

NPM (TypeScript Projects)

Shell
npm install @bbk/embed-sdk
TypeScript
import { BBK } from '@bbk/embed-sdk'; BBK.init({ apiKey: 'pk_test_YOUR_API_KEY' });

Self-Hosted

Download bbk-embed.min.js and serve it from your own infrastructure. Ensure you update to the latest version when BBK releases SDK updates.

Configuration #

Pass a configuration object to BBK.init(). Only apiKey is required -- everything else has sensible defaults.

OptionTypeDefaultDescription
apiKey Required string -- Your public API key. Must start with pk_.
partnerId string null Your partner ID (provided by BBK during onboarding).
environment string 'sandbox' 'sandbox', 'production', or 'local'.
container string null CSS selector for inline mode. Omit for modal overlay.
modal boolean true Open as modal overlay. Set false with container for inline.
language string 'en' 'en' (English) or 'ar' (Arabic with RTL).
currency string 'BHD' ISO 4217 currency code.
debug boolean false Enable console logging. Disable in production.
loadTimeout number 15000 iFrame load timeout in milliseconds.
theme object BBK defaults Theme customization. See Theming section.
property object null Pre-fill property: { name, price, location, type, bedrooms, area }.
customer object null Pre-fill customer: { name, email, phone }.

Full Configuration Example

JavaScript
BBK.init({ // Required apiKey: 'pk_live_xxxxxxxxxxxx', // Environment partnerId: 'naseej-001', environment: 'production', // Display modal: true, language: 'en', currency: 'BHD', debug: false, // Branding theme: { primaryColor: '#1e3c72', accentColor: '#2a5298', borderRadius: '12px', fontFamily: 'Inter, sans-serif' }, // Pre-fill property property: { id: 'prop-villa-001', name: 'Modern Villa - Saar', price: 185000, location: 'Saar, Bahrain', type: 'Villa' }, // Event callbacks onReady: function() { console.log('Widget ready'); }, onCalculated: function(result) { /* ... */ }, onApplicationSubmitted: function(result) { /* ... */ }, onApproved: function(result) { /* ... */ }, onRejected: function(result) { /* ... */ }, onError: function(error) { /* ... */ }, onClose: function() { /* ... */ } });

Methods #

MethodReturnsDescription
BBK.init(config) BBK Initialize the SDK. Must be called before any other method. Returns the BBK instance for chaining.
BBK.open([property]) void Open the modal. Optionally pass property data to override the init config.
BBK.close() void Close the modal with a fade-out animation. Safe to call multiple times.
BBK.updateProperty(prop) void Update property details while the widget is open.
BBK.updateCustomer(cust) void Update customer pre-fill data while the widget is open.
BBK.destroy() void Completely destroy the SDK instance. Removes all DOM elements and event listeners.
BBK.isInitialized() boolean Returns true if init() has been called.
BBK.isOpen() boolean Returns true if the modal is currently open.
BBK.version string The SDK version string (e.g., '1.0.0').

BBK.open() with property override

JavaScript
// Open with default property from init config BBK.open(); // Open with a specific property (overrides init config) BBK.open({ name: 'Luxury Apartment - Juffair', price: 95000, location: 'Juffair, Bahrain', type: 'Apartment' });

Event Callbacks #

Register callbacks in the init() config to respond to widget events.

EventPayloadDescription
onReady none Widget has fully loaded and is ready for user interaction.
onCalculated result Customer completed the mortgage calculator step.
onApplicationSubmitted result Customer submitted the mortgage application.
onApproved result Application received pre-approval.
onRejected result Application was rejected. Generic reason for compliance.
onError error Widget encountered an error. See error codes table below.
onClose none Modal was closed (by user or programmatically).

onCalculated Payload

JavaScript
onCalculated: function(result) { console.log('Monthly payment:', result.monthlyPayment); // 720.500 console.log('Interest rate:', result.interestRate); // 3.25 console.log('Loan type:', result.loanType); // 'normal' or 'eskan' console.log('Affordability:', result.affordability); // 'Excellent'|'Good'|'Fair'|'HighRisk' console.log('DTI ratio:', result.dtiRatio); // 28.8 console.log('LTV ratio:', result.ltvRatio); // 80.0 console.log('Eligible:', result.isEligible); // true }

onApplicationSubmitted Payload

JavaScript
onApplicationSubmitted: function(result) { console.log('Application ID:', result.applicationId); // 'BBK-a1b2c3d4' console.log('Status:', result.status); // 'SUBMITTED' console.log('Submitted at:', result.submittedAt); // ISO 8601 timestamp // Save reference in your system saveToDatabase({ bbkApplicationId: result.applicationId, propertyId: 'your-property-id' }); }

Error Codes

CodeDescriptionSuggested Action
LOAD_TIMEOUTWidget did not load within timeoutCheck network, retry
LOAD_ERRORiFrame failed to load entirelyCheck CSP, ad blockers
VALIDATION_ERRORForm validation failureUser corrects input
API_ERRORBBK backend returned an errorRetry or contact support
SESSION_EXPIREDCustomer session timed out (15 min)Re-open widget
RATE_LIMITEDToo many requests from this sessionWait and retry
MAINTENANCEBBK systems under maintenanceShow maintenance message

Theming #

Customize the widget to match your brand using the theme configuration object.

PropertyTypeDefaultDescription
primaryColor string '#1e3c72' Header, buttons, progress indicators, section titles.
accentColor string '#2a5298' Secondary buttons, hover states, input focus borders, badges.
borderRadius string '12px' Card and input border radius.
fontFamily string 'Inter, sans-serif' Font override for the widget.
JavaScript
BBK.init({ apiKey: 'pk_live_xxxxxxxxxxxx', theme: { primaryColor: '#0a2647', // Your brand's primary accentColor: '#144272', // Your brand's secondary borderRadius: '8px', // Sharper corners fontFamily: 'Roboto, sans-serif' } });
Accessibility: Both primaryColor and accentColor should meet WCAG 2.1 AA contrast ratio (4.5:1) against white text. The BBK default colors are already compliant.

Rendering Modes #

Modal Mode (Default)

The widget opens as a centered overlay with a dark backdrop. Recommended for property listing pages where multiple properties each have a "Finance" button.

  • Dark backdrop (rgba(0,0,0,0.75))
  • Centered card with max-width 740px
  • Close on backdrop click, Escape key, or close button
  • Body scroll locked while open
  • Focus trapped within the modal for accessibility

Inline Mode

The widget renders directly inside a container element. Useful for dedicated mortgage pages where the calculator is a primary feature.

HTML
<div id="bbk-mortgage-widget" style="min-height: 700px;"></div> <script> BBK.init({ apiKey: 'pk_live_xxxxxxxxxxxx', container: '#bbk-mortgage-widget', property: { name: 'Modern Villa - Saar', price: 185000 } }); </script>

Code Examples #

Basic Integration

Minimal setup for a property listing page with multiple properties.

HTML
<script src="https://sdk.bbk.com/v1/bbk-embed.js"></script> <script> BBK.init({ apiKey: 'pk_live_xxxxxxxxxxxx', partnerId: 'naseej-001', environment: 'production', onApproved: function(result) { alert('Pre-approved for BHD ' + result.approvedAmount); } }); function applyForMortgage(name, price, location, type) { BBK.open({ name: name, price: price, location: location, type: type }); } </script> <button onclick="applyForMortgage('Modern Villa', 185000, 'Saar', 'Villa')"> Apply for BBK Mortgage </button>

Modal with Button Trigger

Initialize once, open the modal with different properties each time.

JavaScript
// Initialize once on page load BBK.init({ apiKey: 'pk_live_xxxxxxxxxxxx', partnerId: 'naseej-001', onClose: function() { document.getElementById('apply-btn').disabled = false; } }); // Attach to each property card document.querySelectorAll('[data-property]').forEach(function(card) { card.addEventListener('click', function() { BBK.open({ name: this.dataset.name, price: Number(this.dataset.price), location: this.dataset.location, type: this.dataset.type }); }); });

React Component Wrapper

JSX (React)
import { useEffect, useRef } from 'react'; function MortgageButton({ property }) { const initialized = useRef(false); useEffect(() => { if (!initialized.current) { BBK.init({ apiKey: process.env.REACT_APP_BBK_API_KEY, partnerId: 'naseej-001', environment: process.env.NODE_ENV === 'production' ? 'production' : 'sandbox', onApproved: (result) => { // Handle approval in your React app } }); initialized.current = true; } return () => BBK.destroy(); }, []); return ( <button onClick={() => BBK.open(property)}> Apply for BBK Mortgage </button> ); }

Programmatic with Analytics

JavaScript
BBK.init({ apiKey: 'pk_live_xxxxxxxxxxxx', partnerId: 'naseej-001', onReady: function() { analytics.track('bbk_widget_loaded'); }, onCalculated: function(result) { analytics.track('mortgage_calculated', { monthly_payment: result.monthlyPayment, loan_type: result.loanType, affordability: result.affordability }); }, onApplicationSubmitted: function(result) { analytics.track('mortgage_application_submitted', { application_id: result.applicationId }); // Conversion pixel fbq('track', 'Lead', { value: result.loanAmount, currency: 'BHD' }); }, onError: function(error) { Sentry.captureException(new Error('BBK SDK: ' + error.code)); } });

Security #

API Keys

Key TypeFormatUse
Public key pk_live_* or pk_test_* Client-side SDK (safe to expose in HTML)
Secret key sk_live_* or sk_test_* Server-side API calls only (webhooks, status queries)
Never use secret keys in client-side code. The SDK will throw an error if you attempt to use an sk_* key. Secret keys must never appear in HTML source, JavaScript bundles, or browser developer tools.

iFrame Sandbox

The widget runs inside a sandboxed iFrame with restricted permissions:

HTML Attribute
sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"

This prevents the widget from accessing the partner page's DOM, cookies, or localStorage. It cannot navigate the parent page or submit forms to arbitrary URLs.

postMessage Origin Validation

All communication between the SDK and widget uses postMessage with strict origin validation. The SDK only accepts messages from configured BBK environment domains:

  • Sandbox: https://sandbox-embed.bbk.com
  • Production: https://embed.bbk.com

Messages from any other origin are silently dropped.

Content Security Policy

If your site uses CSP, add the following directives:

CSP Header
frame-src https://sandbox-embed.bbk.com https://embed.bbk.com; script-src https://sdk.bbk.com;

Data Handling

  • Customer PII is transmitted directly to BBK servers via the iFrame. It never passes through the partner's domain.
  • The SDK does not store any data in localStorage, sessionStorage, or cookies.
  • Document uploads go directly to BBK's secure S3 storage via pre-signed URLs.
  • The widget is PCI DSS compliant -- no sensitive financial data passes through the partner's domain.

Browser Support #

The SDK uses ES5 syntax for maximum compatibility. No transpilation or polyfills required.

Chrome
49+
Firefox
52+
Safari
10+
Edge
14+
IE
IE
11
Android
Chrome 49+
iOS Safari
10+
SI
Samsung
5+

FAQ #

Does the SDK work with Single Page Applications (React, Vue, Angular)?
Yes. Call BBK.init() once when your app mounts, and BBK.open() whenever you need the widget. Call BBK.destroy() when the component unmounts to clean up event listeners and DOM elements.
Can I open the widget for different properties without re-initializing?
Yes. Pass property data to BBK.open(property). Each call can use different property details without re-initializing the SDK.
What happens if the customer's session expires?
After 15 minutes of inactivity, the widget fires onError with code SESSION_EXPIRED. The customer can re-open the widget to start fresh. No data is lost on your side -- only the in-progress form within the widget resets.
Does the widget support Arabic (RTL)?
Yes. Set language: 'ar' in the config. The widget automatically switches to RTL layout with Arabic text, including all form labels, buttons, and result displays.
Can I customize which fields are shown in the form?
Field visibility is controlled by BBK for compliance reasons (Central Bank of Bahrain requirements). You can pre-fill customer data using the customer config to reduce friction, and you can pre-fill property data to skip the property selection step.
Is the widget PCI DSS compliant?
Yes. The widget runs inside an iFrame served from BBK's PCI-certified infrastructure. No sensitive financial data passes through the partner's domain. Document uploads go directly to BBK's secure S3 storage via pre-signed URLs. The SDK itself does not store any customer data.
What about ad blockers?
The SDK is served from sdk.bbk.com which is not typically blocked by ad blockers. If a customer's ad blocker interferes, the onError callback fires with LOAD_ERROR. We recommend showing a fallback link to BBK's direct application page in this case.
What loan types are supported?
Two loan types are available: Normal Mortgage (standard BBK home financing from 3.25% APR) and Eskan Housing (Ministry of Housing subsidized from 2.50% APR for eligible Bahraini citizens). The widget presents both options to the customer.