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

# Subscriptions

> Manage purchases and entitlement state with subscription adapters

# @amisi/subscriptions

`@amisi/subscriptions` provides an adapter-based in-app subscription and purchase API for managing subscriptions across iOS, Android, and web platforms.

## Adapter model

* Adapters implement a shared `SubscriptionAdapter` contract
* The active adapter is selected at runtime via `initializeSubscriptions({ adapter, options })`
* Built-in adapters: `revenuecat`, `mock`

## Initialize

Initialize once at app startup:

```ts theme={null}
import { initializeSubscriptions } from '@amisi/subscriptions';

await initializeSubscriptions({
  adapter: 'revenuecat',
  options: {
    apiKey: 'your_revenuecat_api_key',
    // or platform-specific keys:
    // iosApiKey: 'ios_key',
    // androidApiKey: 'android_key',
    entitlementId: 'premium', // optional
    logLevel: 'DEBUG', // optional
  },
});
```

## SubscriptionsProvider

Wrap your app with the `SubscriptionsProvider` to provide subscription context throughout your app:

```tsx theme={null}
import { SubscriptionsProvider } from '@amisi/subscriptions';

export default function App() {
  return (
    <SubscriptionsProvider
      config={{
        adapter: 'revenuecat',
        options: {
          apiKey: 'your_revenuecat_api_key',
          entitlementId: 'premium',
        },
      }}
    >
      <YourApp />
    </SubscriptionsProvider>
  );
}
```

The provider automatically:

* Initializes the subscription adapter
* Fetches products and subscription status
* Provides subscription state to all child components
* Handles refresh and purchase operations

## Hook usage

### useSubscriptions

Access subscription state and operations from the provider:

```tsx theme={null}
import { useSubscriptions } from '@amisi/subscriptions';

export function SubscriptionScreen() {
  const { loading, status, products, purchase, restore, refresh } =
    useSubscriptions();

  if (loading) {
    return <LoadingSpinner />;
  }

  return (
    <View>
      <Text>Active: {status?.isActive ? 'Yes' : 'No'}</Text>
      {products.map((product) => (
        <ProductCard
          key={product.id}
          product={product}
          onPurchase={() => purchase(product.id)}
        />
      ))}
      <Button onPress={restore}>Restore Purchases</Button>
    </View>
  );
}
```

### useEntitlement

Check if a user has access to a specific product:

```tsx theme={null}
import { useEntitlement } from '@amisi/subscriptions';

export function PremiumFeature() {
  const hasAccess = useEntitlement('premium_monthly');

  if (!hasAccess) {
    return <UpgradePrompt />;
  }

  return <PremiumContent />;
}
```

### useHasActiveSubscription

Check if the user has any active subscription:

```tsx theme={null}
import { useHasActiveSubscription } from '@amisi/subscriptions';

export function Header() {
  const isSubscribed = useHasActiveSubscription();

  return <View>{isSubscribed ? <PremiumBadge /> : <UpgradeButton />}</View>;
}
```

### useSubscriptionProduct

Get the current active subscription product ID:

```tsx theme={null}
import { useSubscriptionProduct } from '@amisi/subscriptions';

export function SubscriptionInfo() {
  const productId = useSubscriptionProduct();

  return <Text>Current plan: {productId || 'Free'}</Text>;
}
```

## Hook alias usage

`useSubscription` is an alias of `useSubscriptions` and must be used inside `SubscriptionsProvider`:

```tsx theme={null}
import { useSubscription } from '@amisi/subscriptions';

export function SubscriptionScreen() {
  const { loading, status, products, purchase, restore, refresh } =
    useSubscription();

  if (loading) {
    return <LoadingSpinner />;
  }

  return (
    <View>
      <Text>Active: {status?.isActive ? 'Yes' : 'No'}</Text>
      {products.map((product) => (
        <ProductCard
          key={product.id}
          product={product}
          onPurchase={() => purchase(product.id)}
        />
      ))}
      <Button onPress={restore}>Restore Purchases</Button>
    </View>
  );
}
```

## Purchase a product

```ts theme={null}
const success = await purchase('monthly_subscription_id');
if (success) {
  console.log('Purchase successful!');
}
```

## Restore purchases

```ts theme={null}
const restored = await restore();
if (restored) {
  console.log('Purchases restored!');
}
```

## Check subscription status

The `status` object contains:

```ts theme={null}
interface SubscriptionStatus {
  isActive: boolean;
  productId?: string;
  expiresAt?: Date;
  willRenew?: boolean;
  platform?: 'ios' | 'android' | 'web';
}
```

## Available products

The `products` array contains:

```ts theme={null}
interface SubscriptionProduct {
  id: string;
  name: string;
  price: string;
  currency: string;
  period: 'monthly' | 'yearly' | 'lifetime';
  features?: string[];
}
```

## RevenueCat adapter

The RevenueCat adapter supports the following options:

```ts theme={null}
interface RevenueCatSubscriptionsOptions {
  apiKey?: string; // Universal API key
  iosApiKey?: string; // iOS-specific key
  androidApiKey?: string; // Android-specific key
  appUserId?: string; // Custom user ID
  useAmazon?: boolean; // Use Amazon App Store
  logLevel?: 'VERBOSE' | 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
  entitlementId?: string; // Specific entitlement to check
}
```

## Mock adapter

For testing and development:

```ts theme={null}
await initializeSubscriptions({
  adapter: 'mock',
  options: {
    // Mock adapter provides fake products and subscription status
  },
});
```

## Paywall component

Use the built-in `Paywall` component:

```tsx theme={null}
import { Paywall } from '@amisi/subscriptions';

export function App() {
  return (
    <Paywall
      onPurchase={(productId) => console.log('Purchased:', productId)}
      onRestore={() => console.log('Restored')}
      onClose={() => console.log('Closed')}
    />
  );
}
```

## Custom adapter

Create a custom adapter by implementing the `SubscriptionAdapter` interface:

```ts theme={null}
import { SubscriptionAdapter } from '@amisi/subscriptions';

export function createCustomAdapter(): SubscriptionAdapter {
  return {
    name: 'custom',

    async initialize(config) {
      // Initialize your subscription service
    },

    async getProducts() {
      // Return available products
      return [];
    },

    async getProduct(id) {
      // Return specific product
      return null;
    },

    async purchaseProduct(productId) {
      // Handle purchase
      return true;
    },

    async restorePurchases() {
      // Restore purchases
      return true;
    },

    async getSubscriptionStatus() {
      // Return subscription status
      return { isActive: false };
    },

    async cleanup() {
      // Cleanup resources
    },
  };
}
```

Then register and use it:

```ts theme={null}
import { registerSubscriptionAdapter } from '@amisi/subscriptions';

registerSubscriptionAdapter('custom', createCustomAdapter());

await initializeSubscriptions({
  adapter: 'custom',
  options: {},
});
```
