Offer free trials
Section titled “Offer free trials”A plan can include a trial. While a workspace (called a tenant in the API)
is trialing, its subscription status is "trial" and endsAt holds the
trial end date, both live on the bridge object (see
How billing works).
Surfacing trial state
Section titled “Surfacing trial state”The drop-in components already understand trials: <BridgeSubscriptionStatus />
shows the trialing status and <BridgeBillingNotice /> surfaces an
end-of-trial prompt as the date approaches. You can also read it yourself.
Note that endsAt is optional on the snapshot, so guard it before formatting:
import { bridge, useBridgeReadable } from '@nebulr-group/bridge-react';
function TrialBanner() {
const subscription = useBridgeReadable(bridge.tenant.subscription);
if (subscription?.status !== 'trial') return null;
return subscription.endsAt ? (
<p>Trial ends {new Date(subscription.endsAt).toLocaleDateString()}</p>
) : (
<p>Trial active</p>
);
}
Reacting to the trial lifecycle
Section titled “Reacting to the trial lifecycle”For side effects (emails, analytics, nudges), handle the trial events on the unified dispatcher; see React to billing changes:
import { bridge } from '@nebulr-group/bridge-react';
bridge.events.handle({
'subscription.trial_started': (m) => analytics.track('trial_started', m),
'subscription.trial_ending_soon': (m) => sendReminder(m),
'subscription.trial_converted': (m) => analytics.track('trial_converted', m),
'subscription.trial_expired': (m) => analytics.track('trial_expired', m),
});
When a trial expires without converting, the workspace becomes billing-locked:
the server sets gateEngaged: true on the subscription snapshot, the same lock
mechanism described in How billing works.
Gate your app with Require a plan so the
workspace can pick a paid plan and get back in.