Amba
SDKsFeatures

Entitlements

Check if a user has access to a feature — `has()` for one, `list()` for all. Safe for paywall gating.

Entitlements are named permissions a user holds — typically tied to a subscription or one-time purchase. The SDK exposes two operations: has(name) to gate a specific feature, and list() to enumerate everything the user has.

Entitlement state is sourced from your billing system (RevenueCat, Stripe, App Store, Play Store) via webhooks; the SDK reads the resolved state for the signed-in user.

Quick start

import { Amba } from '@layers/amba-web';
 
if (await Amba.entitlements.has('pro')) {
  showProFeature();
} else {
  showUpgradePrompt();
}

Operations

has(name) — single check

Returns true if the user has the named entitlement and it's currently active. Defaults to false during loading or on error — safe for paywall gating (no flash-of-pro-content).

const isPro = await Amba.entitlements.has('pro');

list() — all entitlements

Returns every entitlement the user holds, with metadata (expiration, source, status).

const all = await Amba.entitlements.list();
// [
//   {
//     name: 'pro',
//     active: true,
//     expires_at: '2026-12-31T00:00:00Z',
//     source: 'stripe',
//     ...
//   },
//   ...
// ]

React hook

import { useEntitlement } from '@layers/amba-react';
 
function ProGate({ children }: { children: ReactNode }) {
  const isPro = useEntitlement('pro');
  return isPro ? <>{children}</> : <Paywall />;
}

The hook defaults to false while the initial fetch is in flight. Safe to use in render without an explicit loading guard for paywall logic.

Patterns

Paywall gating

function NewFeature() {
  const isPro = useEntitlement('pro');
  if (!isPro) {
    return <UpgradePrompt feature="new-feature" />;
  }
  return <FullFeature />;
}

Hybrid client + server check

For revenue-critical actions, double-check on the server. Client-side checks are great UX (instant gating) but the server is source-of-truth:

// Client gates the UI
if (await Amba.entitlements.has('pro')) {
  await callProOnlyFunction();
}
 
// Server function also checks — defense in depth
export default defineFunction(async (req, ctx) => {
  if (!(await ctx.entitlements.asUser(ctx.auth.userId).has('pro'))) {
    return Response.json({ error: 'pro_required' }, { status: 403 });
  }
  // ... do the pro-only thing
});

Multi-tier products

Many apps ship pro / team / enterprise tiers. Model each as its own entitlement and check the highest-applicable:

const list = await Amba.entitlements.list();
const tier = list.find((e) => e.active)?.name; // 'enterprise' | 'team' | 'pro' | undefined

Limits

  • Entitlement names: lowercase, alphanumeric + underscore + dash, up to 64 characters.
  • Refresh cadence: the SDK caches results for ~60 seconds per user; subsequent has() calls within that window are served from cache. Force-refresh via list() (which always hits the server).
  • Source-of-truth: entitlement state is set by your billing webhooks. The SDK reads it; it cannot grant or revoke.
  • Paywall safety: has() returns false on network failure or unknown entitlement name. Plan UI to fail-closed.

Reference

On this page