Skip to content

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.

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.

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.

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;
};
}
}

You only need to register handlers for the methods your integration uses.

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,
};
});

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' };
});

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.

  • 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.