Docs / wallet / useAppAccess

useAppAccess

hooksince 0.2.4

Check whether the authenticated end-user has access to a monetized built app, and open Stripe Checkout to unlock it. Use directly only for custom gate UI — AppPaywall wraps this with a default overlay.

import { useAppAccess } from 'flowstack-sdk/paywall'

Polls GET /billing/app-access/status every 60 seconds and exposes the access state plus a checkout() function that opens a Stripe Checkout session for a one-time unlock. 0.3.0 adds per-app subscriptions (P0-162): a subscription status block plus subscribe() / cancelSubscription() for the builder's monthly plan. Fails open on non-200 responses so a billing outage never locks users out client-side — the backend gate remains the enforcement boundary regardless of what this hook reports.

Most apps should render <AppPaywall siteId={config.appScope}> instead of consuming this hook directly; reach for useAppAccess when you need a custom paywall surface (pricing copy, metered-usage meter, custom CTA).

Signature

const { hasAccess, queriesUsed, queriesRemaining, paymentMode, unlockPriceCents, unlockPriceLabel, isLoading, error, checkout, refetch } = useAppAccess(siteId, opts?)

Parameters

ParamTypeNotesDescription
siteIdstringrequiredSite ID of the built app (typically config.appScope).
opts.builderTenantIdstringBuilder's tenant ID — needed to load app config when the viewer belongs to a different tenant.

Returns

FieldTypeDescription
hasAccessbooleanWhether the end-user has access to this built app (optimistic true until the first check resolves).
queriesUsednumberFree queries used this month.
queriesRemainingnumber | nullRemaining free queries this month (null = unlimited / paid access).
paymentMode'stripe' | 'agent' | 'both' | nullPayment mode configured by the builder.
unlockPriceCentsnumber | nullOne-time unlock price in USD cents (null = free or not configured).
unlockPriceLabelstring | nullHuman-readable unlock price label.
subscriptionAppSubscriptionStatus | nullThe end-user's subscription to this app (state, currentPeriodEnd, cancelAtPeriodEnd, label) — status-only since 0.3.3/P0-167, no allowance fields. null when the builder has no subscription plan configured.
isLoadingbooleanAccess check in flight.
errorstring | nullError message if the status check failed.
checkout(opts?: { successUrl?: string; cancelUrl?: string }) => Promise<void>Open Stripe Checkout to unlock this app.
subscribe(opts?: { successUrl?: string; cancelUrl?: string }) => Promise<void>Open Stripe Checkout (mode=subscription) for the builder's monthly plan. 409s if already subscribed or the user owns a lifetime unlock.
cancelSubscription() => Promise<void>Cancel at period end — access and allowance continue until currentPeriodEnd.
refetch() => Promise<void>Manually refresh the access status.

Examples

Custom gate UI
import { useAppAccess } from 'flowstack-sdk/paywall';

function Gate({ children }: { children: React.ReactNode }) {
  const { hasAccess, queriesRemaining, unlockPriceLabel, isLoading, checkout } = useAppAccess(config.appScope);

  if (isLoading) return <p>Checking access…</p>;
  if (hasAccess) return <>{children}</>;
  return (
    <div>
      <p>{queriesRemaining === 0 ? 'Free queries used up.' : 'This app is premium.'}</p>
      <button onClick={() => checkout()}>Unlock for {unlockPriceLabel}</button>
    </div>
  );
}
WarningImport from flowstack-sdk/paywall (0.3.2+), not flowstack-sdk/wallet — the wallet entry statically requires the wagmi optional peer and breaks built-app builds.
CriticalThe backend AppAccessGate enforces access regardless — this hook (and AppPaywall) is UI, never the security boundary.
NoteTo monetize an app, the owner configures pricing via setMonetization (or the Casino Monetization panel); this hook only reads the resulting access state.

See also

AppPaywall · setMonetization · getMonetization · PaymentRequired · AppSubscriptionStatus · subscribeToApp · cancelAppSubscription

Source: wallet/useAppAccess.ts · Also available in llms-full.txt and registry.json.