Web
The Web SDK is loaded via the Link Loader script, which exposes a global Lean object for every method.
PrerequisitesBefore calling any SDK method you need to have completed the backend setup in the Getting Started section:
- Create your Lean application in the developer dashboard to obtain an
app_token.- Authentication — OAuth flow for minting customer-scoped
access_tokens.- Creating a customer —
POST /customers/v1to obtain acustomer_id.- Sandbox testing — test users and mock bank.
This page covers only the client-side SDK integration.
Installation
Add the Link Loader script to your page:
<script src="https://cdn.leantech.me/link/loader/prod/ae/latest/lean-link-loader.min.js"></script>Load the script at app initialisation / page load — not when the user initiates a flow. Loading it early means the loader and its iframe are warm by the time you call a method.
The loader exposes a global Lean object. Every method lives on it directly: Lean.connect(...), Lean.pay(...), etc.
Available methods
Every method takes a single config object. Each example below lists required fields explicitly and shows the most common optional ones. Every method also accepts these shared optional fields: access_token, sandbox, language, customization, callback.
.connect()
Link a bank account for data access (and optionally payments).
Lean.connect({
app_token: "<YOUR_APP_TOKEN>",
customer_id: "CUSTOMER_ID",
permissions: ["identity", "accounts", "transactions", "balance"],
// Optional:
bank_identifier: "<BANK_IDENTIFIER>",
account_type: "PERSONAL", // or "BUSINESS"
access_from: "2025-01-01",
access_to: "2025-12-31",
show_consent_explanation: true,
access_token: "<CUSTOMER_SCOPED_JWT>",
sandbox: true,
callback: ({ status }) => console.log("Status:", status),
});.pay()
Initiate a bank-to-bank payment.
Required: app_token + one of payment_intent_id or bulk_payment_intent_id.
Lean.pay({
app_token: "<YOUR_APP_TOKEN>",
payment_intent_id: "PAYMENT_INTENT_ID",
// OR for bulk payments: bulk_payment_intent_id: "BULK_PAYMENT_INTENT_ID",
// Optional:
account_id: "<ACCOUNT_ID>",
bank_identifier: "<BANK_IDENTIFIER>",
risk_details: { /* fraud signals */ },
access_token: "<CUSTOMER_SCOPED_JWT>",
sandbox: true,
callback: ({ status }) => console.log("Status:", status),
});.reconnect()
Restore a broken bank connection.
Required: app_token, reconnect_id.
Lean.reconnect({
app_token: "<YOUR_APP_TOKEN>",
reconnect_id: "RECONNECT_ID",
access_token: "<CUSTOMER_SCOPED_JWT>",
sandbox: true,
callback: ({ status }) => console.log("Status:", status),
});.updatePaymentSource()
Add a beneficiary to an existing payment source.
Required: app_token, customer_id, payment_destination_id, and one of payment_source_id or entity_id.
Lean.updatePaymentSource({
app_token: "<YOUR_APP_TOKEN>",
customer_id: "CUSTOMER_ID",
payment_destination_id: "PAYMENT_DESTINATION_ID",
payment_source_id: "PAYMENT_SOURCE_ID",
// OR to upgrade a data-only customer: entity_id: "ENTITY_ID",
access_token: "<CUSTOMER_SCOPED_JWT>",
sandbox: true,
callback: ({ status }) => console.log("Status:", status),
});.checkout()
Open Finance guest payment — the customer authenticates at the bank and is redirected back to your success_redirect_url or fail_redirect_url with status query parameters that you feed into captureRedirect.
Required: app_token, payment_intent_id, success_redirect_url, fail_redirect_url.
Lean.checkout({
app_token: "<YOUR_APP_TOKEN>",
payment_intent_id: "PAYMENT_INTENT_ID",
success_redirect_url: "https://yourapp.com/payment-success",
fail_redirect_url: "https://yourapp.com/payment-failure",
// Optional:
customer_name: "Jane Doe",
bank_identifier: "<BANK_IDENTIFIER>",
risk_details: { /* fraud signals */ },
callback: ({ status }) => console.log("Status:", status),
});.authorizeConsent()
Grant a long-lived Open Finance consent. Redirects to the bank and returns to your success_redirect_url / fail_redirect_url.
Required: app_token, customer_id, consent_id, success_redirect_url, fail_redirect_url.
Lean.authorizeConsent({
app_token: "<YOUR_APP_TOKEN>",
customer_id: "CUSTOMER_ID",
consent_id: "CONSENT_ID",
success_redirect_url: "https://yourapp.com/consent-success",
fail_redirect_url: "https://yourapp.com/consent-failure",
// Optional:
risk_details: { /* fraud signals */ },
access_token: "<CUSTOMER_SCOPED_JWT>",
sandbox: true,
callback: ({ status }) => console.log("Status:", status),
});.manageConsents()
Show a customer-facing consent management screen where users can view and revoke their active consents.
Required: app_token, customer_id.
Lean.manageConsents({
app_token: "<YOUR_APP_TOKEN>",
customer_id: "CUSTOMER_ID",
access_token: "<CUSTOMER_SCOPED_JWT>",
sandbox: true,
callback: ({ status }) => console.log("Status:", status),
});.captureRedirect()
Show the outcome screen after an Open Finance redirect. Extract the status query parameters Lean appends to your redirect URL (consent_attempt_id, granular_status_code, status_additional_info) and pass them in.
Required: app_token, customer_id.
const params = new URLSearchParams(window.location.search);
Lean.captureRedirect({
app_token: "<YOUR_APP_TOKEN>",
customer_id: "<CUSTOMER_ID>",
consent_attempt_id: params.get("consent_attempt_id") ?? undefined,
granular_status_code: params.get("granular_status_code") ?? undefined,
status_additional_info: params.get("status_additional_info") ?? undefined,
access_token: "<CUSTOMER_SCOPED_JWT>",
callback: ({ status }) => console.log("Status:", status),
});.verifyAddress()
Proof-of-address check. The SDK automatically sets permissions: ["identity"].
Required: app_token, customer_id, customer_name.
Lean.verifyAddress({
app_token: "<YOUR_APP_TOKEN>",
customer_id: "CUSTOMER_ID",
customer_name: "Jane Doe",
access_token: "<CUSTOMER_SCOPED_JWT>",
sandbox: true,
callback: ({ status }) => console.log("Status:", status),
});Deprecated methods
.createBeneficiary()
Deprecated — useupdatePaymentSource.
Alias for updatePaymentSource. Accepts the same configuration and behaves identically.
.createPaymentSource()
Deprecated — useconnectwithpermissions: ["payments"]instead.
Alias for connect that forces permissions: ["payments"]. Any permissions you pass is ignored.
Callback
Every method accepts a callback that fires on SDK close with a CallbackData object. Status codes documented at LinkSDK statuses.
The CallbackData shape:
| Field | Type | Notes |
|---|---|---|
status | string | SUCCESS | ERROR | CANCELLED | REDIRECT | LINK_CLOSED_PROGRAMMATICALLY |
message | string | Human-readable description of the outcome. |
bank | { bank_identifier, is_supported } | Bank the user selected; is_supported is false when the user taps "My bank is not listed". |
exit_point | string | Last screen the user saw. |
secondary_status | string | Additional detail on failures (e.g. INVALID_CREDENTIALS) — see LinkSDK statuses. |
last_api_response | string | Last status returned by the Lean API during the flow. |
lean_correlation_id | string | Unique correlation ID — include in support requests. |
open_banking_redirect_url | string | Populated on REDIRECT status (Open Finance flows). |
Lean.connect({
app_token: "<YOUR_APP_TOKEN>",
customer_id: "CUSTOMER_ID",
permissions: ["identity", "accounts"],
callback: (data) => {
switch (data.status) {
case "SUCCESS":
// Account linked. Webhook will follow — treat webhook as authoritative.
break;
case "CANCELLED":
// User closed the SDK.
break;
case "ERROR":
// Inspect data.message and data.secondary_status.
break;
case "REDIRECT":
// Open Finance flow redirected — handle at your redirect URL.
break;
}
},
});Bank-list and account-selection shortcuts
Pass bank_identifier on connect, pay, or checkout to skip the bank-selection screen. Pass account_id on pay to skip the payment-source-selection screen. Both accept values from the Lean Banks API — see Create your own bank list.
Customisation
Pass a customization object to any method to override the SDK's appearance. Full field reference in Customisation.
Lean.connect({
app_token: "<YOUR_APP_TOKEN>",
customer_id: "CUSTOMER_ID",
permissions: ["identity", "accounts"],
customization: {
theme_color: "#0080ff",
button_text_color: "#ffffff",
button_border_radius: "8",
},
});Language
Pass language: "ar" to run the SDK in Arabic with a full right-to-left layout. Omit or pass "en" for English (default).
Content Security Policy
If your site uses CSP, these hosts must be allowed or the SDK will fail to load. The safest option is to wildcard *.leantech.me and add the third-party analytics hosts separately.
Strict directives
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self' https://cdn.leantech.me data: blob:;
script-src 'self' https://cdn.leantech.me https://cdn.segment.com http://cdn.mxpnl.com;
style-src 'self' https://cdn.leantech.me https://fonts.googleapis.com https://cdn.segment.com;
connect-src 'self' blob:
https://apm.ae01.leantech.me https://apm.sa01.leantech.me
https://link.sandbox.leantech.me https://link.leantech.me
https://link.sandbox.sa.leantech.me https://link.sa.leantech.me
https://graphql.contentful.com
https://api.segment.io https://cdn.segment.com
https://api-js.mixpanel.com
https://cdn.growthbook.io;
img-src 'self' data:
https://cdn.leantech.me https://images.leantech.me
https://images.sandbox.leantech.me https://images.sa.leantech.me
https://images.sandbox.sa.leantech.me
https://images.ctfassets.net http://images.contentful.com
https://graphql.contentful.com;
font-src 'self' https://fonts.gstatic.com;
frame-src 'self' https://cdn.leantech.me data: blob:;
"
/>Relaxed directives (wildcard)
<meta
http-equiv="Content-Security-Policy"
content="
default-src 'self' https://*.leantech.me data: blob:;
script-src 'self' https://*.leantech.me https://cdn.segment.com http://cdn.mxpnl.com;
style-src 'self' https://*.leantech.me https://fonts.googleapis.com https://cdn.segment.com;
connect-src 'self' blob: https://*.leantech.me https://graphql.contentful.com https://api.segment.io https://cdn.segment.com https://api-js.mixpanel.com https://cdn.growthbook.io;
img-src 'self' data: https://*.leantech.me https://images.ctfassets.net http://images.contentful.com https://graphql.contentful.com;
font-src 'self' https://fonts.gstatic.com;
frame-src 'self' https://*.leantech.me data: blob:;
"
/>Resources the SDK loads
// Lean
https://*.leantech.me
https://apm.ae01.leantech.me
https://apm.sa01.leantech.me
https://cdn.leantech.me
https://images.leantech.me
https://images.sa.leantech.me
https://images.sandbox.leantech.me
https://images.sandbox.sa.leantech.me
https://link.leantech.me
https://link.sa.leantech.me
https://link.sandbox.leantech.me
https://link.sandbox.sa.leantech.me
// Third-party analytics and content
http://cdn.mxpnl.com
https://api-js.mixpanel.com
https://api.segment.io
https://cdn.segment.com
https://cdn.growthbook.io
https://fonts.googleapis.com
https://fonts.gstatic.com
https://graphql.contentful.com
http://images.contentful.com
https://images.ctfassets.net
The list may change without notice — wildcarding *.leantech.me is the simplest way to stay compatible.
Related
- Authentication — OAuth token flow.
- Creating a customer —
customer_idprerequisite. - Config reference — every config field, its type and purpose.
- Flows reference — per-method prerequisites and required-vs-optional fields.
- Open Finance — redirect handshake for
checkout/authorizeConsent. - Customisation — theming.
- LinkSDK statuses — callback status codes.
- Create your own bank list — custom bank selection UI.
Updated about 4 hours ago
