Window Bridge API
The Window Bridge API provides a bidirectional communication channel between the widget and your page — unlike events (one-way notifications), bridge handlers let the widget request data and await a typed response.
Handler registration
Section titled “Handler registration”Handlers must be registered after the Fluid script loads — before that, window.fluid.bridge is undefined. The method name is the shared key — names must match exactly or requests reject with BRIDGE_HANDLER_NOT_FOUND.
window.fluid.bridge.handleRequest('methodName', async (request) => { return response;});Calling handleRequest again with the same method name silently replaces the previous handler.
Registration patterns
Section titled “Registration patterns”Inline script tag (synchronous):
Use a plain <script> tag — not type="module", async or defer — so that window.fluid.bridge exists in the next script block:
<script src="https://get.fluidpayments.io/index.js"></script><script> window.fluid.bridge.handleRequest('verifyBonusCode', async ({ code }) => { // ... });</script>Dynamic script loading:
When you inject the script yourself (common in SPAs), register handlers in the onload callback:
const script = document.createElement('script');script.src = 'https://get.fluidpayments.io/index.js';script.onload = () => { window.fluid.bridge.handleRequest('verifyBonusCode', async ({ code }) => { // ... });};document.head.appendChild(script);Don’t set script.async = true here. For framework-specific patterns, see Loading the script.
Queue-drain shim (defensive fallback):
If you can’t guarantee registration happens after the script loads (for example, handlers registered at module scope in a bundled app), install this shim before loading the Fluid script:
<script> window.fluid = window.fluid || {}; window.fluid.bridge = window.fluid.bridge || { __queue: [], handleRequest(method, handler) { this.__queue.push([method, handler]); } };</script>When the Fluid script initialises, it replays every queued handleRequest call into the real handler registry. Prefer the inline tag or the onload callback; use the shim only when neither fits.
Defining the typed contract
Section titled “Defining the typed contract”In TypeScript, type your handlers by augmenting the FluidBridgeContract interface from the @fluidpayments/types package. handleRequest then infers the request and response types from the method name:
import type { FluidBridgeVerifyBonusCodeResponse } from '@fluidpayments/types';
type FluidBridgeVerify2FAResponse = | { status: 'valid' } | { status: 'invalid' } | { status: 'rate_limited'; retryAfterMs?: number };
declare module '@fluidpayments/types' { interface FluidBridgeContract { verifyBonusCode: { request: { code: string }; response: FluidBridgeVerifyBonusCodeResponse; }; verify2FA: { request: { code: string }; response: FluidBridgeVerify2FAResponse; }; }}Available methods
Section titled “Available methods”You only need to register handlers for the methods your integration uses.
verifyBonusCode
Section titled “verifyBonusCode”Validates manual bonus codes entered by users. The widget calls it when the user clicks Apply in the bonus code input. Required when the Manual Bonus Codes Enabled setting is on — see Manual Bonus Codes.
Request: { code: string }
| Field | Type | Description |
|---|---|---|
code |
string |
The code the user entered, trimmed |
Response:
type FluidBridgeVerifyBonusCodeResponse = | { status: 'valid'; bonus: FluidBonusData; autoOptedIn?: boolean } | { status: 'invalid' };| Field | Type | Required | Description |
|---|---|---|---|
status |
'valid' | 'invalid' |
Yes | Whether the code is valid |
bonus |
FluidBonusData |
When status is 'valid' |
The bonus to display, in the same shape as the bonuses attribute. See Bonus Data |
autoOptedIn |
boolean |
No | Opt the user into the bonus automatically. Defaults to false |
autoOptedIn behaviour:
| Flow | autoOptedIn |
Behaviour |
|---|---|---|
| First-time depositor (no stored methods) | false / omitted |
Bonus is shown on the bonus selection step; the user confirms it before continuing |
| First-time depositor (no stored methods) | true |
Bonus card is shown on the first step and the bonus step is skipped |
| Stored methods | true |
The user is opted in straight away |
| Stored methods | false / omitted |
The bonus list opens after validation so the user can confirm |
Example:
window.fluid.bridge.handleRequest('verifyBonusCode', async ({ code }) => { const result = await myApi.verifyBonusCode(code); if (!result.valid) { return { status: 'invalid' }; } return { status: 'valid', bonus: { code: result.code, title: result.title, description: result.description, logoUrl: result.logoUrl, termsAndConditions: result.termsAndConditions, minDeposit: result.minDeposit, maxBonus: result.maxBonus, maxBonusPercentage: result.maxBonusPercentage, paymentMethodFilter: result.paymentMethodFilter, }, autoOptedIn: result.autoOptedIn, };});verify2FA
Section titled “verify2FA”Validates 6-digit authenticator codes during withdrawals. The widget calls it when the user clicks Verify code on the 2FA step. Required when two-factor-auth-enabled is "true" — see Two-Factor Authentication.
Request: { code: string }
| Field | Type | Description |
|---|---|---|
code |
string |
The 6-digit code the user entered |
Response:
type FluidBridgeVerify2FAResponse = | { status: 'valid' } | { status: 'invalid' } | { status: 'rate_limited'; retryAfterMs?: number };| Field | Type | Required | Description |
|---|---|---|---|
status |
'valid' | 'invalid' | 'rate_limited' |
Yes | The verification result |
retryAfterMs |
number |
No | Only for rate_limited. Milliseconds before the user can retry: the widget shows a countdown, re-enables the input when it ends, and fills the {seconds} placeholder in the rate-limit message from this value. Defaults to 30 seconds when omitted |
Example:
window.fluid.bridge.handleRequest('verify2FA', async ({ code }) => { const result = await myApi.verify2FA(code); if (result.valid) { return { status: 'valid' }; } if (result.rateLimited) { return { status: 'rate_limited', retryAfterMs: result.retryAfterMs }; } return { status: 'invalid' };});Error handling
Section titled “Error handling”All requests time out at 10,000ms. When a request fails, the widget’s promise rejects with a FluidBridgeError:
type FluidBridgeError = { code: 'BRIDGE_HANDLER_NOT_FOUND' | 'BRIDGE_TIMEOUT' | 'BRIDGE_HANDLER_ERROR'; message: string; details?: unknown; // BRIDGE_HANDLER_ERROR only: the value your handler threw};| Error code | Meaning |
|---|---|
BRIDGE_HANDLER_NOT_FOUND |
No handler registered for the method name. The request rejects immediately |
BRIDGE_TIMEOUT |
Handler didn’t respond within 10 seconds |
BRIDGE_HANDLER_ERROR |
Handler threw or returned a rejected promise |
For both built-in methods, the widget treats any of these errors as a failed verification and shows the code as invalid.
Limitations
Section titled “Limitations”- The 10,000ms timeout is fixed and applies to every method; it can’t be configured per request.
- The handler registry is shared by every Fluid widget on the page. If several widget elements are mounted at once, they all use the same handlers.