Credits System
Credits System
The credits system is particularly helpful for building AI applications where you want to charge users based on usage (e.g., image generation, video generation, API calls). It provides a flexible pay-as-you-go model alongside your subscription plans. 🚀
Enabling Credits
To enable the credits system in your application:
- Open
src/lib/credits/config.ts
- Set
enableCredits
totrue
export const enableCredits = true; // Enable or disable credits
- The system will now be active and ready to configure
Adding New Credit Types
Credit types define what users can purchase and use (e.g., "image_generation", "video_generation").
Where to configure: src/lib/credits/config.ts
Example:
import { z } from "zod";
// 1. Define your credit types in the schema
export const creditTypeSchema = z.enum([
"image_generation",
"video_generation",
// Add more types here
]);
// 2. Configure pricing for each type
export const creditsConfig: CreditsConfig = {
image_generation: {
name: "Image Generation Credits",
currency: "USD",
minimumAmount: 1,
slabs: [
{ from: 0, to: 1000, pricePerUnit: 0.01 },
{ from: 1001, to: 5000, pricePerUnit: 0.008 }, // Volume discount
],
},
video_generation: {
name: "Video Generation Credits",
currency: "USD",
minimumAmount: 1,
priceCalculator: (amount, userPlan) => {
// Custom pricing based on user's plan
return amount * 0.05;
},
},
};
Pricing Models:
- Use slabs for simple tiered pricing
- Use priceCalculator for dynamic pricing based on user's plan
Auto Adding Credits on Signup
Reward new users with free credits when they register! 🎁
Where to configure: onRegisterCredits
in src/lib/credits/config.ts
What to specify:
- Credit type
- Amount of credits to give
- Expiry duration (optional - credits won't expire if not set)
This is perfect for letting users try your AI features before purchasing.
Adding Credits on Plan Change
Automatically grant credits when users upgrade or change their subscription plan.
Where to configure: onPlanChangeCredits
in src/lib/credits/config.ts
How it works:
- Map plan codenames to credit grants
- Each plan can give different amounts of different credit types
- Set expiry periods per credit type
- Credits are added automatically when the plan change is detected
Great for incentivizing upgrades or rewarding loyal customers! 💎
Expiring Credits
Credits can automatically expire after a set duration (e.g., 30 days from grant).
Configuration:
Set expiryAfter
(in days) when defining credits in:
onRegisterCredits
(signup bonuses)onPlanChangeCredits
(plan upgrade bonuses)
Cron Job Setup (if not using Inngest):
-
Add to your
.env
:CRON_USERNAME
- Secure username for authenticationCRON_PASSWORD
- Secure password for authentication
-
Setup on cron-job.org:
- URL:
https://yourdomain.com/api/cron/expire-credits
- Add HTTP Basic Authentication with your credentials
- Schedule: Daily at midnight (recommended)
- URL:
The cron job will automatically expire credits based on your configuration. ⏰
Usage in Frontend
Two powerful hooks make it easy to work with credits:
useCredits
Hook
Fetch and display user's current credit balances.
Returns:
credits
- Object with all credit types and amountsisLoading
- Loading stateerror
- Any errorsmutate
- Function to refresh credits
Example:
import useCredits from "@/lib/credits/useCredits";
function CreditBalance() {
const { credits, isLoading } = useCredits();
if (isLoading) return <div>Loading...</div>;
return (
<div>
<p>Image Credits: {credits?.image_generation || 0}</p>
<p>Video Credits: {credits?.video_generation || 0}</p>
</div>
);
}
useBuyCredits
Hook
Handle credit purchasing with automatic price calculation.
Parameters:
- Credit type
- Amount to purchase
Returns:
price
- Calculated price (considers user's plan for personalized pricing)currency
- Currency for transactionisLoading
- Loading stateerror
- Any errorsgetBuyCreditsUrl(provider)
- Generate payment URL
Example:
import useBuyCredits from "@/lib/credits/useBuyCredits";
import { PlanProvider } from "@/lib/plans/getSubscribeUrl";
import { Button } from "@/components/ui/button";
function BuyCreditButton() {
const { price, isLoading, getBuyCreditsUrl } = useBuyCredits(
"image_generation",
100 // Buy 100 credits
);
const handlePurchase = () => {
const url = getBuyCreditsUrl(PlanProvider.STRIPE);
window.location.href = url;
};
return (
<Button onClick={handlePurchase} disabled={isLoading}>
{isLoading ? "Loading..." : `Buy 100 Credits - $${price?.toFixed(2)}`}
</Button>
);
}
Benefits:
- Automatic price calculation based on user's plan
- Support for multiple payment providers
- Real-time pricing updates
Backend Functions
On the server side, you have access to powerful functions for managing credits programmatically.
deductCredits
Function
Deducts credits from a user's account with automatic balance checking.
Parameters:
userId
- User IDcreditType
- Type of credit to deductamount
- Amount to deductmetadata
- Optional metadata for tracking
Throws: Error if user has insufficient credits
Example:
import { deductCredits } from "@/lib/credits/credits";
// In your API route or server action
async function generateImage(userId: string) {
try {
// Deduct credits before processing
await deductCredits(userId, "image_generation", 1, {
action: "generate_image",
prompt: "A beautiful sunset",
});
// Process the image generation
const image = await aiService.generateImage();
return { success: true, image };
} catch (error) {
// Handle insufficient credits
return { success: false, error: "Insufficient credits" };
}
}
addCredits
Function
Adds credits to a user's account with duplicate prevention.
Parameters:
userId
- User IDcreditType
- Type of credit to addamount
- Amount to addpaymentId
- Payment ID (prevents duplicate credits)metadata
- Optional metadataexpirationDate
- Optional expiration date
Example:
import { addCredits } from "@/lib/credits/credits";
// Grant bonus credits to a user
async function grantBonusCredits(userId: string) {
const result = await addCredits(
userId,
"image_generation",
50,
`bonus-${userId}-${Date.now()}`, // Unique payment ID
{ reason: "promotional_bonus" },
new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) // Expires in 30 days
);
return result;
}
Use these functions for:
- 🎨 Deducting credits when users consume AI services
- 🎁 Granting bonus or promotional credits
- 🔄 Refunding credits after failed operations
- 📊 Implementing custom credit workflows
Payment Providers
⚠️ Important: Credits are only available for these payment providers:
- ✅ Stripe - Full support
- ✅ PayPal - Full support
- ✅ DodoPayments - Full support
DodoPayments Setup
For DodoPayments credit purchases:
- Create a product in DodoPayments dashboard
- Set pricing model to "Pay as you go"
- Add to
.env
:DODO_CREDITS_PRODUCT_ID="pdt_xxxxxxxxxxxxx"
Super Admin
Administrators have full control over user credits from the admin panel.
Features:
- ➕ Add credits to any user
- ➖ Remove/deduct credits from users
- 📊 View credit transaction history
- 🔍 Monitor credit usage patterns
Access: Navigate to user detail page in the super admin section to manage credits.
This is useful for:
- Customer support (issuing refunds or bonuses)
- Fixing issues
- Running promotions
- Testing features
Quick Recap 🎯
With the credits system enabled, you can:
- Create multiple credit types for different features
- Auto-grant credits on signup and plan changes
- Set credit expiry periods
- Offer personalized pricing based on subscription tiers
- Use frontend hooks (
useCredits
,useBuyCredits
) for UI - Use backend functions (
deductCredits
,addCredits
) for server-side logic - Manage credits via admin panel
- Accept payments through Stripe, PayPal, or DodoPayments
Perfect for AI SaaS where you want usage-based pricing! 💡