Documentation Index
Fetch the complete documentation index at: https://docs.onlyautomator.com/llms.txt
Use this file to discover all available pages before exploring further.
The OnlyAutomator subscription system manages user access to premium features through a flexible, tiered pricing model powered by Stripe.
Subscription Flow
The subscription process is designed to be seamless and secure, following industry best practices for payment processing:
- Plan Selection: Users choose from multiple subscription tiers
- Payment Processing: Secure credit card processing through Stripe
- Access Provisioning: Immediate activation of premium features
- Recurring Billing: Automated rebilling on the subscriber’s cycle
- Subscription Management: Self-service tools for upgrading, downgrading, or canceling
Subscription flow with Stripe
Subscription Tiers
OnlyAutomator offers multiple subscription tiers to accommodate different user needs:
Free Tier
- Price: $0/month
- Features:
- Basic analytics dashboard
- Limited data collection (1 OnlyFans account)
- 7-day data retention
- Standard support
Pro Tier
- Price: $19.99/month
- Features:
- Advanced analytics dashboard
- Enhanced data collection (up to 3 OnlyFans accounts)
- 30-day data retention
- Priority support
- Basic automation tools
Business Tier
- Price: $49.99/month
- Features:
- Comprehensive analytics suite
- Full data collection (up to 10 OnlyFans accounts)
- 90-day data retention
- Priority support with dedicated contact
- Advanced automation tools
- Custom reporting
Technical Implementation
Database Schema
The subscription data is stored in the following database schema:
-- Products table
CREATE TABLE products (
id TEXT PRIMARY KEY,
active BOOLEAN,
name TEXT,
description TEXT,
image TEXT,
metadata JSONB
);
-- Prices table
CREATE TABLE prices (
id TEXT PRIMARY KEY,
product_id TEXT REFERENCES products(id),
active BOOLEAN,
description TEXT,
unit_amount INTEGER,
currency TEXT,
type TEXT,
interval TEXT,
interval_count INTEGER,
trial_period_days INTEGER,
metadata JSONB
);
-- Subscriptions table
CREATE TABLE subscriptions (
id TEXT PRIMARY KEY,
user_id UUID REFERENCES auth.users(id) NOT NULL,
status TEXT,
metadata JSONB,
price_id TEXT REFERENCES prices(id),
quantity INTEGER,
cancel_at_period_end BOOLEAN,
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
current_period_start TIMESTAMP WITH TIME ZONE,
current_period_end TIMESTAMP WITH TIME ZONE,
ended_at TIMESTAMP WITH TIME ZONE,
cancel_at TIMESTAMP WITH TIME ZONE,
canceled_at TIMESTAMP WITH TIME ZONE,
trial_start TIMESTAMP WITH TIME ZONE,
trial_end TIMESTAMP WITH TIME ZONE
);
API Endpoints
The subscription system exposes the following API endpoints:
| Endpoint | Method | Description |
|---|
/api/create-checkout-session | POST | Creates a Stripe checkout session |
/api/create-portal-link | POST | Creates a link to the Stripe customer portal |
/api/webhooks | POST | Handles Stripe webhook events |
Stripe Integration
Integration with Stripe is handled through a dedicated service:
// Service for managing Stripe interactions
import Stripe from 'stripe';
import { createClient } from '@supabase/supabase-js';
import { Database } from '../types_db';
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, {
apiVersion: '2022-11-15',
typescript: true
});
export const supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL as string,
process.env.SUPABASE_SERVICE_ROLE_KEY as string
);
// Example: Create a checkout session
export async function createCheckoutSession(
userId: string,
priceId: string,
redirectTo: string
) {
try {
const customer = await getOrCreateCustomer(userId);
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
billing_address_collection: 'required',
customer: customer.id,
line_items: [
{
price: priceId,
quantity: 1
}
],
mode: 'subscription',
allow_promotion_codes: true,
subscription_data: {
trial_from_plan: true,
metadata: {}
},
success_url: `${redirectTo}/dashboard?session_id={CHECKOUT_SESSION_ID}`,
cancel_url: `${redirectTo}/pricing`
});
return { sessionId: session.id };
} catch (error) {
console.log(error);
throw error;
}
}
// Helper: Get or create a Stripe customer for a user
async function getOrCreateCustomer(userId: string) {
const { data: customerData } = await supabase
.from('customers')
.select('stripe_customer_id')
.eq('id', userId)
.single();
if (customerData?.stripe_customer_id) {
return { id: customerData.stripe_customer_id };
}
// Retrieve user data from Supabase
const { data: userData } = await supabase
.from('users')
.select('email')
.eq('id', userId)
.single();
// Create a new customer in Stripe
const customer = await stripe.customers.create({
email: userData?.email,
metadata: {
supabaseUUID: userId
}
});
// Store the customer ID in Supabase
await supabase
.from('customers')
.insert([{ id: userId, stripe_customer_id: customer.id }]);
return customer;
}
Webhook Processing
Stripe webhooks are used to keep subscription status in sync:
export async function processStripeWebhook(event: Stripe.Event) {
switch (event.type) {
case 'customer.subscription.created':
case 'customer.subscription.updated':
const subscription = event.data.object as Stripe.Subscription;
await updateSubscriptionInDatabase(subscription);
break;
case 'customer.subscription.deleted':
const deletedSubscription = event.data.object as Stripe.Subscription;
await markSubscriptionAsDeleted(deletedSubscription);
break;
case 'invoice.paid':
const invoice = event.data.object as Stripe.Invoice;
await handleSuccessfulPayment(invoice);
break;
case 'invoice.payment_failed':
const failedInvoice = event.data.object as Stripe.Invoice;
await handleFailedPayment(failedInvoice);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
}
User Subscription Management
Users can manage their subscriptions through a dedicated portal:
export async function createPortalLink(customerId: string, returnUrl: string) {
try {
const portalSession = await stripe.billingPortal.sessions.create({
customer: customerId,
return_url: returnUrl
});
return { url: portalSession.url };
} catch (error) {
console.log(error);
throw error;
}
}
Subscription Status Checking
A custom hook provides easy access to subscription status:
// Custom hook for subscription status
import { useEffect, useState } from 'react';
import { useUser } from '@/utils/useUser';
export const useSubscriptionStatus = () => {
const { user } = useUser();
const [subscription, setSubscription] = useState<any>(null);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
if (!user) {
setLoading(false);
return;
}
async function fetchSubscription() {
try {
const res = await fetch('/api/subscription-status');
const data = await res.json();
setSubscription(data);
} catch (error) {
console.error('Error fetching subscription:', error);
} finally {
setLoading(false);
}
}
fetchSubscription();
}, [user]);
return {
subscription,
loading,
isPro: subscription?.plan === 'pro',
isBusiness: subscription?.plan === 'business',
isActive: subscription?.status === 'active' || subscription?.status === 'trialing'
};
};
Trial Periods
The subscription system supports trial periods to allow users to experience premium features:
- Trial Duration: 7 days for all paid plans
- Credit Card Required: Credit card is collected upfront but not charged until the trial ends
- Automatic Conversion: Trial automatically converts to a paid subscription unless canceled
- Full Access: Trial users receive full access to all plan features
Handling Subscription Changes
The system includes logic for handling various subscription events:
- Upgrades: Immediate upgrade with prorated charges
- Downgrades: Applied at the end of the billing cycle
- Cancellations: Access continues until the end of the paid period
- Reactivation: Simple process to restore a canceled subscription
Configuration Settings
The subscription system is configured through environment variables:
# Stripe API configuration
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxxxx
# Product and price IDs
NEXT_PUBLIC_STRIPE_PRO_PRICE_ID=price_xxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_STRIPE_BUSINESS_PRICE_ID=price_xxxxxxxxxxxxxxxxxx
Troubleshooting
Common subscription issues and their resolutions:
| Issue | Possible Causes | Resolution |
|---|
| Failed payment | Expired card, insufficient funds | Prompt user to update payment method |
| Webhook errors | Misconfigured webhook, server issues | Check Stripe dashboard, verify endpoint URL |
| Access discrepancy | Database sync issues | Force sync subscription status from Stripe |
| Unexpected cancellation | Failed payment, user action | Check Stripe logs for cancellation reason |