CLIENT SDK
Client SDK reference
~9 kB gzipped, no dependencies, renders in a Shadow DOM so your CSS and ours never collide. Load it from
https://boolbul.com/v1/boolbul.js or npm install @boolbul/sdk.BoolBul.open(options)
import { open } from "@boolbul/sdk"; // or window.BoolBul.open
await open({
publicKey: "bb_pub_…",
customerId: "cus_123",
subscriptionId: "sub_456",
mrrCents: 4900,
onOfferAccepted: async (offer) => { /* apply on your server; throw to show a retry */ },
onCancel: ({ reasonId, comment, failedOpen }) => { /* run your normal cancellation */ },
onDismiss: () => { /* customer closed it and keeps their plan */ },
});| Option | Type | Notes |
|---|---|---|
publicKey | string | From onboarding / Settings. Safe to ship in the browser. |
customerId | string | Your gateway customer id. |
subscriptionId | string | The Dodo or Stripe subscription being cancelled. |
mrrCents | number? | Monthly value in cents. Shown as saved MRR in your dashboard. |
planPriceCents | number? | Price used for “Pay $24.50 instead of $49”. Defaults to mrrCents. |
currency | string? | ISO code for price formatting. Default USD. |
onOfferAccepted | (offer) => Promise | Required. Resolve when applied; reject to let the customer retry or cancel. |
onCancel | (details) => void | Required. Called on the cancel link and on fail-open. |
onDismiss | () => void | Optional. Close button, Escape or backdrop. |
What you receive
| Field | Meaning |
|---|---|
offer.offerJwt | Signed HS256 token, valid 5 minutes, single-use. Verify it on your server. |
offer.offerType | "discount" or "pause". |
offer.offerValue | Discount in basis points (5000 = 50%) or pause length in days. |
details.reasonId | too_expensive · unused · missing_features · switched_service · customer_service · low_quality · too_complex · other — the same values Dodo and Stripe accept as cancellation feedback. |
details.failedOpen | true when BoolBul was unreachable and stepped aside. |
Fail-open guarantee
Config and session load in parallel with a hard 1500 ms deadline. Timeout, network error, invalid key or exhausted quota → the widget closes and onCancel runs immediately. Your customers can always cancel, even if BoolBul is down.
React
import { useBoolBul, BoolBulPreview } from "@boolbul/sdk/react";
const openRetention = useBoolBul({ publicKey: "bb_pub_…" });
// Network-free preview (what the dashboard customizer uses):
<BoolBulPreview config={{ themePreset: "midnight_oled" }} viewport="mobile" style={{ height: 640 }} />Accessibility & compliance
- Focus is trapped in the dialog and restored afterwards; Escape closes it.
- The cancel link is on every screen, one click, never disabled, WCAG AA contrast in every theme.
- Labels that hide or shame the cancellation are replaced with the plain default.
- Phones get a bottom sheet (or a centered modal, your choice) with safe-area padding; motion respects reduced-motion settings.
Want to see it first? The live demo runs this exact SDK.