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 */ },
});
OptionTypeNotes
publicKeystringFrom onboarding / Settings. Safe to ship in the browser.
customerIdstringYour gateway customer id.
subscriptionIdstringThe Dodo or Stripe subscription being cancelled.
mrrCentsnumber?Monthly value in cents. Shown as saved MRR in your dashboard.
planPriceCentsnumber?Price used for “Pay $24.50 instead of $49”. Defaults to mrrCents.
currencystring?ISO code for price formatting. Default USD.
onOfferAccepted(offer) => PromiseRequired. Resolve when applied; reject to let the customer retry or cancel.
onCancel(details) => voidRequired. Called on the cancel link and on fail-open.
onDismiss() => voidOptional. Close button, Escape or backdrop.

What you receive

FieldMeaning
offer.offerJwtSigned HS256 token, valid 5 minutes, single-use. Verify it on your server.
offer.offerType"discount" or "pause".
offer.offerValueDiscount in basis points (5000 = 50%) or pause length in days.
details.reasonIdtoo_expensive · unused · missing_features · switched_service · customer_service · low_quality · too_complex · other — the same values Dodo and Stripe accept as cancellation feedback.
details.failedOpentrue 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.