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

# useFeatureAccess

> Access feature access state and use it in your React app.

The `useFeatureAccess` hook lets you read a customer's feature access and usage from your backend routes and use it directly in your UI.

<Tip>
  Setup first: see the [React integration guide](/react-integration).
</Tip>

<Tabs>
  <Tab title="Single feature access">
    ```tsx theme={null}
    const result = useFeatureAccess<MyFeatures>("priority_support", options?)
    ```

    ## Parameters

    <ParamField path="featureKey" type="keyof MyFeatures" required>
      Feature key to read. Returns flattened fields for that feature plus `isLoading`, `error`, and `refetch`.
    </ParamField>

    <ParamField path="options.enabled" type="boolean">
      Enable or disable fetching. Defaults to `true`.
    </ParamField>

    <ParamField path="options.errorOnNotFound" type="boolean">
      When `true`, a `404` is surfaced as an error instead of returning `null`. Defaults to `false`.
    </ParamField>

    <ParamField path="options.swr" type="SWRConfiguration<MyFeatures | null, Error>">
      Optional [SWR config](https://swr.vercel.app/docs/api#options) for caching/revalidation behavior.
    </ParamField>

    ## Returns

    <Tabs>
      <Tab title="Boolean feature">
        <ParamField path="type" type="boolean (literal)">
          Feature type.
        </ParamField>

        <ParamField path="hasAccess" type="boolean">
          Whether the customer has access to the selected boolean feature.
        </ParamField>

        <ParamField path="isLoading" type="boolean">
          Whether data is currently loading.
        </ParamField>

        <ParamField path="error" type="Error | null">
          Error from the latest request.
        </ParamField>

        <ParamField path="refetch" type="() => Promise<void>">
          Manually revalidate feature access.
        </ParamField>
      </Tab>

      <Tab title="Limit feature">
        <ParamField path="type" type="limit (literal)">
          Feature type.
        </ParamField>

        <ParamField path="hasAccess" type="boolean">
          Whether the customer has access to the selected limit feature.

          <Warning>
            `hasAccess` indicates whether the customer has access to the feature in general. It does not indicate remaining usage. Use `usage.hasReachedLimit` to determine if usage limit has been reached.
          </Warning>
        </ParamField>

        <ParamField path="isUnlimited" type="boolean">
          Whether usage is unlimited.
        </ParamField>

        <ParamField path="limit" type="number | null">
          Configured limit. `null` when unlimited.
        </ParamField>

        <ParamField path="usage" type="object | undefined">
          Usage for tracked limit features. Omitted for untracked limit features.
        </ParamField>

        <ParamField path="usage.used" type="number">
          Current usage amount in the active period.
        </ParamField>

        <ParamField path="usage.remaining" type="number | null">
          Remaining usage in the active period. `null` when unlimited.
        </ParamField>

        <ParamField path="usage.bonusRemaining" type="number">
          Remaining bonus usage available.
        </ParamField>

        <ParamField path="usage.bonusUsed" type="number">
          Bonus usage already consumed.
        </ParamField>

        <ParamField path="usage.hasReachedLimit" type="boolean">
          Whether usage has reached the limit.
        </ParamField>

        <ParamField path="usage.nextReset" type="number | null">
          Unix timestamp (ms) for next reset.
        </ParamField>

        <ParamField path="usage.lastReset" type="number | null">
          Unix timestamp (ms) for previous reset.
        </ParamField>

        <ParamField path="isLoading" type="boolean">
          Whether data is currently loading.
        </ParamField>

        <ParamField path="error" type="Error | null">
          Error from the latest request.
        </ParamField>

        <ParamField path="refetch" type="() => Promise<void>">
          Manually revalidate feature access.
        </ParamField>
      </Tab>
    </Tabs>
  </Tab>

  <Tab title="All feature access">
    ```tsx theme={null}
    const result = useFeatureAccess<MyFeatures>(options?)
    ```

    ## Parameters

    <ParamField path="options.enabled" type="boolean">
      Enable or disable fetching. Defaults to `true`.
    </ParamField>

    <ParamField path="options.errorOnNotFound" type="boolean">
      When `true`, a `404` is surfaced as an error instead of returning `null`. Defaults to `false`.
    </ParamField>

    <ParamField path="options.swr" type="SWRConfiguration<MyFeatures | null, Error>">
      Optional [SWR config](https://swr.vercel.app/docs/api#options) for caching/revalidation behavior.
    </ParamField>

    ## Returns

    <ParamField path="featureAccess" type="MyFeatures | null">
      Feature access map keyed by your feature keys.
    </ParamField>

    <Tabs>
      <Tab title="Boolean entries">
        <ParamField path="featureAccess[key].type" type="boolean (literal)">
          Feature type for boolean entries.
        </ParamField>

        <ParamField path="featureAccess[key].hasAccess" type="boolean">
          Whether the customer has access to that boolean feature.
        </ParamField>
      </Tab>

      <Tab title="Limit entries">
        <ParamField path="featureAccess[key].type" type="limit (literal)">
          Feature type for limit entries.
        </ParamField>

        <ParamField path="featureAccess[key].hasAccess" type="boolean">
          Whether the customer has access to that limit feature.

          <Warning>
            `hasAccess` indicates whether the customer has access to the feature in general. It does not indicate remaining usage. Use `usage.hasReachedLimit` to determine if usage limit has been reached.
          </Warning>
        </ParamField>

        <ParamField path="featureAccess[key].isUnlimited" type="boolean">
          Whether the feature is unlimited.
        </ParamField>

        <ParamField path="featureAccess[key].limit" type="number | null">
          Configured limit for that feature.
        </ParamField>

        <ParamField path="featureAccess[key].usage" type="object | undefined">
          Usage for tracked limit features.
        </ParamField>

        <ParamField path="featureAccess[key].usage.remaining" type="number | null">
          Remaining usage for that feature in the active period.
        </ParamField>

        <ParamField path="featureAccess[key].usage.bonusRemaining" type="number">
          Remaining bonus usage for that feature.
        </ParamField>

        <ParamField path="featureAccess[key].usage.hasReachedLimit" type="boolean">
          Whether usage has reached the limit for that feature.
        </ParamField>
      </Tab>
    </Tabs>

    <ParamField path="isLoading" type="boolean">
      Whether data is currently loading.
    </ParamField>

    <ParamField path="error" type="Error | null">
      Error from the latest request.
    </ParamField>

    <ParamField path="refetch" type="() => Promise<void>">
      Manually revalidate feature access.
    </ParamField>
  </Tab>
</Tabs>

## Examples

### Single feature access

<Tabs>
  <Tab title="Boolean Example">
    ```tsx theme={null}
    import { useFeatureAccess } from "priceos/react";
    import type { MyFeatures } from "./priceos.types";

    export function PrioritySupportButton() {
      const { hasAccess, isLoading } = useFeatureAccess<MyFeatures>("priority_support");

      const onClick = () => {
        if (!hasAccess) {
          // Show upgrade flow
          return;
        }
        // Open support flow
      };

      if (isLoading) return <div>Loading...</div>;
      return <button onClick={onClick}>Contact support</button>;
    }
    ```
  </Tab>

  <Tab title="Limit Example">
    ```tsx theme={null}
    import { useFeatureAccess } from "priceos/react";
    import type { MyFeatures } from "./priceos.types";

    export function CreateReportButton() {
      const { hasAccess, usage, isUnlimited, limit, isLoading } = useFeatureAccess<MyFeatures>("api_calls");

      const remaining = usage?.remaining;
      const bonusRemaining = usage?.bonusRemaining ?? 0;

      const onClick = () => {
        if (!hasAccess) {
          // Show upgrade flow
          return;
        }
        if (usage?.hasReachedLimit) {
          // Show usage limit message
          return;
        }
        // Create report
      };

      if (isLoading) return <div>Loading...</div>;

      return (
        <div>
          <p>{isUnlimited ? "Unlimited" : `${remaining ?? 0} / ${limit ?? 0} remaining`}</p>
          <p>Bonus remaining: {bonusRemaining}</p>
          <button onClick={onClick}>Create report</button>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### All feature access

<Tabs>
  <Tab title="Boolean Example">
    ```tsx theme={null}
    import { useFeatureAccess } from "priceos/react";
    import type { MyFeatures } from "./priceos.types";

    export function PrioritySupportButton() {
      const { featureAccess, isLoading } = useFeatureAccess<MyFeatures>();
      const hasAccess = featureAccess?.priority_support?.hasAccess;

      const onClick = () => {
        if (!hasAccess) {
          // Show upgrade flow
          return;
        }
        // Open support flow
      };

      if (isLoading) return <div>Loading...</div>;
      return <button onClick={onClick}>Contact support</button>;
    }
    ```
  </Tab>

  <Tab title="Limit Example">
    ```tsx theme={null}
    import { useFeatureAccess } from "priceos/react";
    import type { MyFeatures } from "./priceos.types";

    export function CreateReportButton() {
      const { featureAccess, isLoading } = useFeatureAccess<MyFeatures>();
      const apiCalls = featureAccess?.api_calls;
      const remaining = apiCalls?.usage?.remaining;
      const bonusRemaining = apiCalls?.usage?.bonusRemaining ?? 0;

      const onClick = () => {
        if (!apiCalls?.hasAccess) {
          // Show upgrade flow
          return;
        }
        if (apiCalls?.usage?.hasReachedLimit) {
          // Show usage limit message
          return;
        }
        // Create report
      };

      if (isLoading) return <div>Loading...</div>;

      return (
        <div>
          <p>API calls remaining: {remaining ?? "Unlimited"}</p>
          <p>Bonus remaining: {bonusRemaining}</p>
          <button onClick={onClick}>Create report</button>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

### Displaying usage to user

```tsx theme={null}
import { useFeatureAccess } from "priceos/react";
import type { MyFeatures } from "./priceos.types";

export function UsageBadge() {
  const { hasAccess, usage, isUnlimited, limit } = useFeatureAccess<MyFeatures>("api_calls");

  if (!hasAccess) return <div>Upgrade required</div>;
  if (!usage) return <div>Usage tracking unavailable</div>;

  const label = isUnlimited ? `${usage.used} used` : `${usage.used} / ${limit}`;
  return <div>{label}</div>;
}
```

### Determine if limit has been hit using PriceOS

```tsx theme={null}
import { useFeatureAccess } from "priceos/react";
import type { MyFeatures } from "./priceos.types";

export function CreateReportButton() {
  const { hasAccess, usage } = useFeatureAccess<MyFeatures>("api_calls");

  const onClick = () => {
    if (!hasAccess) return;
    if (usage?.hasReachedLimit) {
      // Block action: limit reached
      return;
    }
    // Continue action
  };

  return <button onClick={onClick}>Create report</button>;
}
```

### Determine if limit has been hit using your own tracking

```tsx theme={null}
import { useFeatureAccess } from "priceos/react";
import type { MyFeatures } from "./priceos.types";

export function CreateReportButton({ currentUsage }: { currentUsage: number }) {
  const { hasAccess, limit, isUnlimited } = useFeatureAccess<MyFeatures>("api_calls");

  const onClick = () => {
    if (!hasAccess) return;
    if (!isUnlimited && typeof limit === "number" && currentUsage >= limit) {
      // Block action: limit reached (your own tracking)
      return;
    }
    // Continue action
  };

  return <button onClick={onClick}>Create report</button>;
}
```

### Displaying bonuses to users

```tsx theme={null}
import { useFeatureAccess } from "priceos/react";
import type { MyFeatures } from "./priceos.types";

export function BonusUsageSummary() {
  const { usage } = useFeatureAccess<MyFeatures>("api_calls");

  if (!usage) return null;

  return (
    <div>
      <p>Bonus remaining: {usage.bonusRemaining}</p>
      <p>Bonus used: {usage.bonusUsed}</p>
    </div>
  );
}
```
