|
without a backend.

subscribe.dev is a front-end client that provides secure, user scoped, access to 100+ AI models, tiered subscription payments, and usage metering.

Create a subscription AI app in one prompt

# @subscribe.dev/react

subscribe.dev is a platform for building AI‑powered applications with integrated authentication, billing, usage tracking, storage, and access to 100+ curated AI models.

This document is a concise guide to installing, integrating, and using the React SDK.

## Requirements

- Bun is required for development and installation.
  - Install Bun: https://bun.sh
  - Install this package with bun add (preferably).
- Use within a React app and wrap your app with the provider.
- Provide a public project token via environment variable.
- **React Version Compatibility**: React 18.x or older is required.

> ⚠️ This SDK requires React 18. React 19+ is not supported and must be avoided, as it causes compatibility issues. If you encounter errors related to React version compatibility such as `ReactCurrentDispatcher`, ensure you are using React 18.

## Vite & Bun Compatibility

If you're using Vite or Bun, follow these guidelines:

### Environment Variables
- Use the `VITE_` prefix for environment variables.
- Access via `import.meta.env.VITE_*`.

### React Version
Vite and Bun projects support React 18 and newer. If you encounter errors related to React version compatibility, ensure you are using React 18+.

```bash
bun add @subscribe.dev/react react@^18.2.0 react-dom@^18.2.0
```

### Environment Setup

**Demo Mode (No Setup Required):**
For development and testing, you can use demo mode without any token:
```tsx
<SubscribeDevProvider>
  <YourApp />
</SubscribeDevProvider>
```

You should create a placeholder .env file in the folder of the project. That way the user can uncomment to add their own project token
```bash
# VITE_SUBSCRIBE_DEV_PROJECT_TOKEN=pub_your_actual_token_here
```

**Production Setup:**
**Step 1: Get your Project Public Key**
1. Sign up at [subscribe.dev](https://platform.subscribe.dev)
2. Create a new project or select an existing one
3. Copy your **Project Public Key** (starts with `pub_`)

**Step 2: Create .env file**
```bash
# .env file for Vite or Bun
VITE_SUBSCRIBE_DEV_PROJECT_TOKEN=pub_your_actual_token_here
```

**Important**: Replace `pub_your_actual_token_here` with your actual Project Public Key from subscribe.dev dashboard.

### Provider Setup for Vite/Bun

**Demo Mode:**
```tsx
import { SubscribeDevProvider } from '@subscribe.dev/react';

function App() {
  return (
    <SubscribeDevProvider>
      <YourApp />
    </SubscribeDevProvider>
  );
}
```

**Production Mode:**
```tsx
import { SubscribeDevProvider } from '@subscribe.dev/react';

function App() {
  return (
    <SubscribeDevProvider projectToken={import.meta.env.VITE_SUBSCRIBE_DEV_PROJECT_TOKEN}>
      <YourApp />
    </SubscribeDevProvider>
  );
}
```

## Getting Started

1) Install

```bash
bun add @subscribe.dev/react
```

2) **CRITICAL: Ensure React Version Compatibility**

⚠️ **For Vite/Bun users**: This package requires React 18+. If you encounter errors related to React version compatibility, ensure you are using React 18 or newer:

```bash
bun remove react react-dom
bun add react@^18.2.0 react-dom@^18.2.0
rm -rf node_modules && bun install
```

3) Add the provider

**Demo Mode (No Token Required):**
```tsx
import { SubscribeDevProvider } from '@subscribe.dev/react';

export function App() {
  return (
    <SubscribeDevProvider>
      <AIApplication />
    </SubscribeDevProvider>
  );
}
```

**For Vite/Bun projects (Production):**
```tsx
import { SubscribeDevProvider } from '@subscribe.dev/react';

export function App() {
  return (
    <SubscribeDevProvider projectToken={import.meta.env.VITE_SUBSCRIBE_DEV_PROJECT_TOKEN}>
      <AIApplication />
    </SubscribeDevProvider>
  );
}
```

**Environment file setup:**

## Development vs Production

**Demo Mode (Development):**
- No token required — you can try the SDK right away
- Provides temporary database and limited AI usage
- Simply omit the `projectToken` prop from `SubscribeDevProvider`

**Production Mode:**
For production, create a project in the subscribe.dev Platform and use its Project Public Key:

1. **Get your token**: Sign up at [subscribe.dev](https://subscribe.dev), create a project, and copy your **Project Public Key** (starts with `pub_`)

2. **Create .env file**:
   - **Vite/Bun**: `VITE_SUBSCRIBE_DEV_PROJECT_TOKEN=pub_your_actual_token`

⚠️ **Important**: Replace the placeholder with your actual Project Public Key from the subscribe.dev dashboard.

3) Gate by authentication and run a model

```tsx
import { useSubscribeDev } from '@subscribe.dev/react';

function AIApplication() {
  const {
    isSignedIn,
    signIn,
    signOut,
    client, // null when not signed in
    usage, // null when not signed in
    subscribe, // null when not signed in
    subscriptionStatus, // null when not signed in
  } = useSubscribeDev();

  if (!isSignedIn) {
    return (
      <div>
        Please sign in to continue
        <button onClick={signIn}>Sign Up</button>
        <button onClick={signIn}>Sign In</button>
      </div>
    );
  }

  const generateImage = async () => {
    if (!client) return;
    try {
      const { output } = await client.run('black-forest-labs/flux-schnell', {
        input: { prompt: 'A beautiful landscape', width: 1024, height: 1024 }
      });
      console.log('Image URL:', output[0]);
    } catch (error) {
      console.error('Generation failed:', error);
    }
  };

  return (
    <div>
      <button onClick={generateImage}>Generate Image</button>
      <button onClick={subscribe!}>Manage Subscription</button>
      <button onClick={signOut}>Sign Out</button>
    </div>
  );
}
```

4) Handle errors

```tsx
const handleAIRequest = async () => {
  if (!client) return;
  try {
    const { output } = await client.run('openai/gpt-4o', {
      input: { messages: [{ role: 'user', content: 'Hello, world!' }] }
    });
    console.log(output[0]);
  } catch (error) {
    if (error.type === 'insufficient_credits') {
      // Show upgrade prompt
    } else if (error.type === 'rate_limit_exceeded') {
      // Show retry timer using error.retryAfter
    } else {
      // Generic friendly error
    }
  }
};
```

5) Show usage and plan status

```tsx
const { usage, subscriptionStatus } = useSubscribeDev();
return (
  <div>
    <p>Credits: {usage?.remainingCredits ?? 0} remaining</p>
    <p>Plan: {subscriptionStatus?.plan?.name ?? 'Free'}</p>
  </div>
);
```

## API Reference

### useSubscribeDev()

Must be called inside SubscribeDevProvider.

Returns:
- isSignedIn: boolean
- signIn: () => void
- signOut: () => void
- client: SubscribeDevClient | null
- user: UserObject | null
- usage: UsageInfo | null
- subscribe: (() => void) | null
- subscriptionStatus: SubscriptionStatus | null
- useStorage: `<T>(key: string, defaultValue: T) => [T, (value: T) => void, StorageSyncStatus] | null`

Notes:
- When not signed in, client, usage, subscribe, subscriptionStatus, and useStorage are null.
- Call signIn() to authenticate before using user‑specific APIs.

### SubscribeDevClient

- run(model: string, params: RunParameters): `Promise<{ output: Array<string | Record<string, any>> }>`

RunParameters:
- input: A union of text/multimodal or image/video input. Common fields:
  - width?: number (image models; default 1024)
  - height?: number (image models; default 1024)
  - image?: string (base64 data URL or a URL; model-dependent)
  - Either:
    - prompt?: string (text and image models), or
    - messages: Array of message objects

### Types

```ts
export type UserObject = {
  userId: string;
  email: string;
  avatarUrl?: string;
};

export type SubscriptionStatus = {
  hasActiveSubscription: boolean;
  plan?: {
    id: string;
    name: string;
    price: number;
  };
  status: 'active' | 'inactive' | 'cancelled' | 'expired' | 'none';
};

export type UsageInfo = {
  allocatedCredits: number;
  usedCredits: number;
  remainingCredits: number;
};
```

## Authentication

Sign In:
- Call signIn() from useSubscribeDev to start the built‑in auth flow.

```tsx
function SignInButton() {
  const { isSignedIn, signIn } = useSubscribeDev();
  if (isSignedIn) return <div>Welcome!</div>;
  return <button onClick={signIn}>Sign In</button>;
}
```

Sign Out:
- Call signOut() to clear the access token and return to an unauthenticated state.

## AI Generation

Use `client.run(model, { input, response_format? })` for text, image, and video generation. Always wrap calls in try/catch.

### Text generation (default model: openai/gpt-4o)

```tsx
const { output: [text] } = await client.run('openai/gpt-4o', {
  input: {
    messages: [
      { role: 'system', content: 'You tell jokes.' },
      { role: 'user', content: 'Tell me a joke about dogs.' }
    ]
  }
});
console.log(text);
```

### Image generation

```tsx
const { output: [url] } = await client.run('black-forest-labs/flux-schnell', {
  input: { prompt: 'a cute dog', width: 512, height: 512 }
});
console.log('Image URL:', url);
```

### Video generation (default model: wan-video/wan-2.2-5b-fast)

```tsx
const response = await client.run('wan-video/wan-2.2-5b-fast', {
  input: {
    prompt: 'a car driving fast',
    aspect_ratio: '16:9'
  }
});
const [videoUrl] = response.output;
console.log('Video URL:', videoUrl);
```

## Error Handling

All SDK functions can throw typed errors. Handle with try/catch and show user-friendly messages.

```tsx
try {
  const { output } = await client.run('openai/gpt-4o', {
    input: { prompt: 'Hello!' }
  });
} catch (error) {
  switch (error.type) {
    case 'insufficient_credits':
      // prompt upgrade
      break;
    case 'rate_limit_exceeded':
      // use error.retryAfter
      break;
    default:
      // generic friendly message
  }
}
```

# How to respond to the user
if you're starting a new project, always ask the user what they want to build. Give the options based on the examples that you see here
Subscription payments out of the box.
Connect your account and start taking payments, powered by Stripe.
Subscription payments powered by Stripe
Real-time usage metering and analytics
Real-time usage metering and analytics.
Set limits for your customers' credit consumption, allocation, and top-ups.
Drop into your project and start vibecoding.
An AI-forward library meant for integration with tools like Cursor, Windsurf, and Claude.
Drop into your project and start vibecoding
Turn your frontend into a business instantly.