> ## Documentation Index
> Fetch the complete documentation index at: https://docs.billingos.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Gate features

> Control access to features based on subscription plan.

Feature gating is how you turn your free users into paying customers. By restricting access to premium features based on plan, you create natural upgrade moments that drive revenue — without frustrating your users.

## Feature types

BillingOS supports three types of features:

| Type              | Example               | How it works                               |
| ----------------- | --------------------- | ------------------------------------------ |
| **Boolean**       | Custom branding       | On/off — user either has access or doesn't |
| **Usage quota**   | 1,000 API calls/month | Counted — resets each billing period       |
| **Numeric limit** | 5 team members        | Fixed cap — doesn't reset                  |

## Client-side gating

### Using the FeatureGate component

The simplest approach — wrap content with `<FeatureGate>`:

```tsx theme={null}
import { FeatureGate } from "@billingos/sdk";

<FeatureGate feature="custom_branding">
  <BrandingEditor />
</FeatureGate>
```

Content is only rendered if the user has access. Add a fallback for users who don't:

```tsx theme={null}
import { FeatureGate, UpgradePrompt } from "@billingos/sdk";

<FeatureGate
  feature="custom_branding"
  fallback={<UpgradePrompt feature="custom_branding" />}
>
  <BrandingEditor />
</FeatureGate>
```

<img src="https://mintlify.s3.us-west-1.amazonaws.com/billingos/images/feature-gate.png" alt="Feature gate" />

### Using the useFeature hook

For more control, check access programmatically:

```tsx theme={null}
import { useFeature } from "@billingos/sdk";

function ExportButton() {
  const { data } = useFeature("export_pdf");

  return (
    <button
      disabled={!data?.has_access}
      onClick={handleExport}
    >
      Export PDF
      {data?.limit && <span>({data.usage}/{data.limit})</span>}
    </button>
  );
}
```

### Using the useFeatureGate hook

Combines access checking with automatic callbacks:

```tsx theme={null}
import { useFeatureGate } from "@billingos/sdk";

function ApiCallButton() {
  const { hasAccess, remaining } = useFeatureGate("api_calls", {
    onAccessDenied: () => toast.error("Upgrade to access this feature"),
    onQuotaExceeded: (usage, limit) =>
      toast.warning(`${usage}/${limit} calls used — upgrade for more`),
  });

  return (
    <button disabled={!hasAccess}>
      Make API Call ({remaining} left)
    </button>
  );
}
```

## Server-side gating

For API routes and server actions, use the Node SDK:

```typescript theme={null}
import { BillingOS } from "@billingos/node";

const billing = new BillingOS({ secretKey: process.env.BILLINGOS_SECRET_KEY! });

export async function POST(request: Request) {
  const userId = getAuthenticatedUser(request);

  const entitlement = await billing.checkEntitlement(userId, "api_calls");

  if (!entitlement.has_access) {
    return Response.json({ error: "Upgrade required" }, { status: 403 });
  }

  // Process the request...

  // Track the usage
  await billing.trackUsage({
    customerId: userId,
    featureKey: "api_calls",
    quantity: 1,
  });

  return Response.json({ result: "success" });
}
```

<Warning>
  Always validate entitlements on the server for security-critical features. Client-side gates improve UX but can be bypassed.
</Warning>
