Skip to content

Commit 0f9caa5

Browse files
committed
update: reduce free credits for launch
1 parent 9f3c9cf commit 0f9caa5

File tree

12 files changed

+82
-154
lines changed

12 files changed

+82
-154
lines changed

backend/services/dodopayments.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ def create_subscription_checkout(self,
8888

8989
# Product mapping for plans
9090
product_mapping = {
91-
'pro': 'pdt_1Jnk8U6d33BpgIHvLZRf4', # Pro: $25/month
92-
'premium': 'pdt_GAjFoFJyPVseIT8MrbLFL', # Premium: $50/month
93-
'byok': 'pdt_MdtvInruKkrwu5AjzP0ah' # BYOK: $250/year
91+
'pro': 'pdt_1Jnk8U6d33BpgIHvLZRf4', # Pro: $18 one-time purchase
92+
'premium': 'pdt_GAjFoFJyPVseIT8MrbLFL', # Premium: $30 one-time purchase
93+
'byok': 'pdt_MdtvInruKkrwu5AjzP0ah' # BYOK: $9/month subscription
9494
}
9595

9696
if plan_id not in product_mapping:

backend/utils/constants.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,39 @@
88
'name': 'Free',
99
'price_inr': 0,
1010
'price_usd': 0,
11-
'token_quota': 100000, # ~20 typical conversations
12-
'display_credits': 20, # User sees "20 credits/month"
13-
'daily_refills_max': 4, # Maximum 4 refills per month
14-
'credits_per_refill': 5, # 5 credits per daily refill
15-
'features': ['5 credits daily (up to 20/month)', '1 deployed website', 'Community support'],
16-
'description': '5 credits daily (up to 20 credits/month) - Perfect for getting started'
11+
'token_quota': 25000, # ~5 typical conversations
12+
'display_credits': 5, # User sees "5 credits"
13+
'daily_refills_max': 0, # No daily refills - all credits available at once
14+
'credits_per_refill': 0, # No refills
15+
'features': ['5 credits/month', '1 deployed website', 'Community support'],
16+
'description': '5 credits/month - Perfect for getting started'
1717
},
1818
'pro': {
1919
'name': 'Pro',
2020
'price_inr': 149900, # ₹1499 (in paisa)
2121
'price_usd': 1800, # $18 (in cents)
2222
'token_quota': 750000, # ~150 typical conversations
23-
'display_credits': 150, # User sees "150 credits/month"
23+
'display_credits': 150, # User sees "150 credits"
2424
'features': ['Priority Support', 'All Models', 'Advanced Features'],
25-
'description': '150 credits/month - Great for regular users'
25+
'description': '150 credits included - Great for regular users'
2626
},
2727
'premium': {
2828
'name': 'Premium',
2929
'price_inr': 259900, # ₹2599 (in paisa)
3030
'price_usd': 3000, # $30 (in cents)
3131
'token_quota': 1250000, # ~250 typical conversations
32-
'display_credits': 250, # User sees "250 credits/month"
32+
'display_credits': 250, # User sees "250 credits"
3333
'features': ['Priority Support', 'All Models + Beta', 'Advanced Analytics'],
34-
'description': '250 credits/month - Perfect for power users'
34+
'description': '250 credits included - Perfect for power users'
3535
},
3636
'byok': {
3737
'name': 'BYOK',
38-
'price_inr': 1299500, # ₹12995 (in paisa) - Annual pricing
39-
'price_usd': 10800, # $108 (in cents) - Annual pricing
38+
'price_inr': 109900, # ₹1099 (in paisa) - Monthly pricing
39+
'price_usd': 900, # $9 (in cents) - Monthly pricing
4040
'token_quota': -1, # Unlimited
4141
'display_credits': -1, # "Unlimited"
4242
'features': ['Bring Your Own OpenRouter Key', 'Unlimited Usage', 'Real Cost Pricing', 'Dedicated Support'],
43-
'description': 'Bring your own OpenRouter API key - $9/month billed annually ($108/year)'
43+
'description': 'Bring your own OpenRouter API key - $9/month subscription'
4444
}
4545
}
4646

frontend/src/app/(home)/projects/[projectId]/thread/_contexts/ThreadActionsContext.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ export function ThreadActionsProvider({ children }: ThreadActionsProviderProps)
245245
setBillingData({
246246
currentUsage: err.detail.currentUsage as number | undefined,
247247
limit: err.detail.limit as number | undefined,
248-
message: err.detail.message || 'Monthly usage limit reached. Please upgrade.',
248+
message: err.detail.message || 'Credit limit reached. Please buy more credits.',
249249
accountId: project?.account_id || null
250250
});
251251
setShowBillingAlert(true);

frontend/src/components/billing/DailyRefillsMeter.tsx

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,21 @@ export function DailyRefillsMeter({
2121
}: DailyRefillsMeterProps) {
2222
const { planName, rawCreditsTotal, rawCreditsRemaining } = useBilling();
2323

24-
// Only show for free users
24+
// Don't show daily refills meter for free users anymore since they get credits upfront
25+
// This component is now only for paid plans with actual daily refill systems (if any)
2526
const isFreeUser = planName?.toLowerCase() === 'free' || !planName;
2627

27-
if (!isFreeUser) {
28+
if (isFreeUser) {
2829
return null;
2930
}
3031

3132
// Calculate refills used this month
32-
// Each refill = 5 credits, max 4 refills = 20 credits total
33-
const maxRefills = 4;
34-
const creditsPerRefill = 5;
33+
// Each refill = 1 credit, max 5 refills = 5 credits total
34+
const maxRefills = 5;
35+
const creditsPerRefill = 1;
3536

3637
// Calculate how many refills have been used based on total credits given vs remaining
37-
const creditsUsed = (rawCreditsTotal || 20) - (rawCreditsRemaining || 20);
38+
const creditsUsed = (rawCreditsTotal || 5) - (rawCreditsRemaining || 5);
3839
const refillsUsed = Math.min(Math.ceil(creditsUsed / creditsPerRefill), maxRefills);
3940
const refillsRemaining = maxRefills - refillsUsed;
4041

@@ -55,10 +56,10 @@ export function DailyRefillsMeter({
5556
<span>Daily Refills</span>
5657
</div>
5758
<ul className="text-sm space-y-1 text-foreground/90">
58-
<li className="flex items-start gap-2"><CheckCircle className="h-4 w-4 text-emerald-400 mt-0.5" /> <span>5 credits added each day (up to 4×/month)</span></li>
59+
<li className="flex items-start gap-2"><CheckCircle className="h-4 w-4 text-emerald-400 mt-0.5" /> <span>1 credit added each day (up to 5×/month)</span></li>
5960
<li className="flex items-start gap-2"><CheckCircle className="h-4 w-4 text-emerald-400 mt-0.5" /> <span>Refills reset at midnight</span></li>
60-
<li className="flex items-start gap-2"><CheckCircle className="h-4 w-4 text-emerald-400 mt-0.5" /> <span>Unused refills dont carry over</span></li>
61-
<li className="flex items-start gap-2"><CheckCircle className="h-4 w-4 text-emerald-400 mt-0.5" /> <span>Maximum 20 credits per month</span></li>
61+
<li className="flex items-start gap-2"><CheckCircle className="h-4 w-4 text-emerald-400 mt-0.5" /> <span>Unused refills don't carry over</span></li>
62+
<li className="flex items-start gap-2"><CheckCircle className="h-4 w-4 text-emerald-400 mt-0.5" /> <span>Maximum 5 credits per month</span></li>
6263
</ul>
6364
{refillsRemaining > 0 ? (
6465
<div className="text-sm bg-blue-600/15 border border-blue-400/30 text-blue-100 p-3 rounded-md">
@@ -68,7 +69,7 @@ export function DailyRefillsMeter({
6869
) : (
6970
<div className="text-sm bg-amber-600/15 border border-amber-400/30 text-amber-100 p-3 rounded-md">
7071
<div className="font-medium">Monthly limit reached</div>
71-
<div>You've used all 4 daily refills this month. Upgrade for more credits.</div>
72+
<div>You've used all 5 daily refills this month. Buy credits for unlimited usage.</div>
7273
</div>
7374
)}
7475
</div>

frontend/src/components/billing/UpgradePrompt.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,9 @@ export function UpgradePrompt({ trigger, autoOpen = false, onClose }: UpgradePro
153153
</div>
154154
<div className="text-sm text-muted-foreground">
155155
<Zap className="h-4 w-4 inline mr-1" />
156-
{plan.display_credits} credits/month
156+
{plan.name.toLowerCase() === 'free' ? `${plan.display_credits} credits/month` :
157+
plan.name.toLowerCase().includes('byok') ? 'Unlimited credits' :
158+
`${plan.display_credits} credits included`}
157159
</div>
158160
</CardHeader>
159161

@@ -195,7 +197,7 @@ export function UpgradePrompt({ trigger, autoOpen = false, onClose }: UpgradePro
195197

196198
<div className="text-center text-xs text-muted-foreground mt-4">
197199
<p>All plans include a 30-day money-back guarantee.</p>
198-
<p>Credits reset monthly on your billing date.</p>
200+
<p>Pro/Premium credits never expire. Free credits reset monthly.</p>
199201
</div>
200202
</div>
201203
</DialogContent>

frontend/src/components/billing/billing-modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export function BillingModal({ open, onOpenChange, returnUrl = window?.location?
5858
<div className="rounded-lg border bg-background p-4">
5959
<div className="flex justify-between items-center">
6060
<span className="text-sm font-medium text-foreground/90">
61-
Agent Usage This Month
61+
Agent Usage
6262
</span>
6363
<span className="text-sm font-medium">
6464
${subscriptionData.current_usage?.toFixed(2) || '0'} /{' '}

frontend/src/components/billing/billing-pricing-section.tsx

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,27 @@ import { Badge } from '@/components/ui/badge';
2020
import { PlanDetails } from '@/lib/api';
2121
import { LocalizedPrice } from 'react-currency-localizer';
2222

23-
type FREQUENCY = 'monthly' | 'yearly';
24-
25-
interface BillingPlan {
23+
interface RawPlan {
2624
name: string;
2725
info: string;
28-
price: {
29-
monthly: number;
30-
yearly: number;
31-
};
26+
price: number | { monthly: number };
3227
features: {
3328
text: string;
3429
tooltip?: string;
3530
}[];
31+
credits: number;
32+
planId: string;
33+
highlighted?: boolean;
34+
}
35+
36+
interface BillingPlan extends RawPlan {
3637
btn: {
3738
text: string;
3839
href?: string;
3940
onClick?: () => void;
4041
};
41-
highlighted?: boolean;
4242
isCurrentPlan?: boolean;
4343
isUpgrading?: boolean;
44-
credits: number;
4544
}
4645

4746
interface BillingPricingSectionProps extends React.ComponentProps<'div'> {
@@ -62,7 +61,7 @@ export function BillingPricingSection({
6261
description,
6362
...props
6463
}: BillingPricingSectionProps) {
65-
const [frequency, setFrequency] = React.useState<'monthly' | 'yearly'>('monthly');
64+
6665
const [upgradingPlan, setUpgradingPlan] = useState<string | null>(null);
6766

6867
const { getToken, isSignedIn } = useAuth();
@@ -115,26 +114,26 @@ export function BillingPricingSection({
115114
const getStaticPricingPlans = (): BillingPlan[] => {
116115
const currentPlan = planName?.toLowerCase();
117116

118-
const plans = [
117+
const plans: RawPlan[] = [
119118
{
120119
name: 'Free',
121120
info: 'Perfect for getting started',
122-
price: { monthly: 0, yearly: 0 },
121+
price: 0,
123122
features: [
124-
{ text: '5 credits daily (up to 20 credits/month)', tooltip: 'Daily credit allocation with monthly cap' },
123+
{ text: '5 credits/month', tooltip: 'Monthly credit allocation - use anytime' },
125124
{ text: '1 deployed website', tooltip: 'Host one website for free' },
126125
{ text: 'Community support', tooltip: 'Access to community forums and documentation' },
127126
],
128-
credits: 20,
127+
credits: 5,
129128
planId: 'free'
130129
},
131130
{
132131
name: 'Pro',
133132
info: 'Best for growing developers',
134-
price: { monthly: 18, yearly: 180 }, // USD prices
133+
price: 18, // USD price - one-time purchase
135134
features: [
136135
{ text: 'Everything in Free' },
137-
{ text: '150 credits/month', tooltip: 'Monthly credit allocation for AI operations' },
136+
{ text: '150 credits included', tooltip: 'One-time credit purchase - credits never expire' },
138137
{ text: '10 deployed websites', tooltip: 'Host up to 10 websites' },
139138
{ text: 'Custom domains', tooltip: 'Use your own domain names' },
140139
{ text: 'Codebase download', tooltip: 'Download your generated code' },
@@ -146,10 +145,10 @@ export function BillingPricingSection({
146145
{
147146
name: 'Premium',
148147
info: 'For professional developers',
149-
price: { monthly: 30, yearly: 300 }, // USD prices
148+
price: 30, // USD price - one-time purchase
150149
features: [
151150
{ text: 'Everything in Pro' },
152-
{ text: '250 credits/month', tooltip: 'Monthly credit allocation for AI operations' },
151+
{ text: '250 credits included', tooltip: 'One-time credit purchase - credits never expire' },
153152
{ text: '25 deployed websites', tooltip: 'Host up to 25 websites' },
154153
{ text: 'Priority support', tooltip: '24/7 email and chat support' },
155154
],
@@ -159,7 +158,7 @@ export function BillingPricingSection({
159158
{
160159
name: 'Bring Your Own Key (BYOK)',
161160
info: 'Ultimate flexibility',
162-
price: { monthly: 9, yearly: 108 }, // USD prices
161+
price: { monthly: 9 }, // USD price - monthly subscription only
163162
features: [
164163
{ text: 'API cost paid directly to LLM provider', tooltip: 'Pay OpenAI/Anthropic directly, no markup' },
165164
{ text: '100 deployed websites', tooltip: 'Host up to 100 websites' },
@@ -182,8 +181,9 @@ export function BillingPricingSection({
182181
const getButtonText = () => {
183182
if (isCurrentPlan) return 'Current Plan';
184183
if (isUpgrading) return 'Processing...';
185-
if (plan.price.monthly === 0) return 'Get Started';
186-
return 'Upgrade';
184+
if (typeof plan.price === 'number' && plan.price === 0) return 'Get Started';
185+
if (plan.planId === 'byok') return 'Subscribe';
186+
return 'Buy Credits';
187187
};
188188

189189
return {
@@ -199,6 +199,7 @@ export function BillingPricingSection({
199199
isCurrentPlan,
200200
isUpgrading,
201201
credits: plan.credits,
202+
planId: plan.planId,
202203
};
203204
});
204205
};
@@ -237,7 +238,6 @@ export function BillingPricingSection({
237238
{plans.filter(plan => !plan.name.includes('BYOK')).map((plan) => (
238239
<BillingPricingCard
239240
plan={plan}
240-
frequency={frequency}
241241
insideDialog={insideDialog}
242242
isByokPlan={false}
243243
key={plan.name}
@@ -249,7 +249,6 @@ export function BillingPricingSection({
249249
<div key={plan.name} className="mx-auto w-full max-w-6xl mt-4 md:mt-6 grid grid-cols-1 lg:grid-cols-2 gap-4">
250250
<BillingPricingCard
251251
plan={plan}
252-
frequency={frequency}
253252
insideDialog={insideDialog}
254253
isByokPlan={true}
255254
/>
@@ -282,7 +281,6 @@ export function BillingPricingSection({
282281
{plans.filter(plan => !plan.name.includes('BYOK')).map((plan) => (
283282
<BillingPricingCard
284283
plan={plan}
285-
frequency={frequency}
286284
insideDialog={insideDialog}
287285
isByokPlan={false}
288286
key={plan.name}
@@ -294,7 +292,6 @@ export function BillingPricingSection({
294292
{plans.filter(plan => plan.name.includes('BYOK')).map((plan) => (
295293
<BillingPricingCard
296294
plan={plan}
297-
frequency={frequency}
298295
insideDialog={insideDialog}
299296
isByokPlan={true}
300297
key={plan.name}
@@ -310,7 +307,6 @@ export function BillingPricingSection({
310307

311308
type BillingPricingCardProps = React.ComponentProps<'div'> & {
312309
plan: BillingPlan;
313-
frequency?: FREQUENCY;
314310
insideDialog?: boolean;
315311
isByokPlan?: boolean;
316312
};
@@ -330,7 +326,6 @@ const Step = ({ number, children }: { number: number; children: React.ReactNode
330326
export function BillingPricingCard({
331327
plan,
332328
className,
333-
frequency = 'monthly',
334329
insideDialog = false,
335330
isByokPlan = false,
336331
...props
@@ -378,12 +373,12 @@ export function BillingPricingCard({
378373
<p className="text-muted-foreground text-sm font-normal">{plan.info}</p>
379374

380375
<div className="mt-2 flex items-end gap-1">
381-
{plan.price[frequency] === 0 ? (
376+
{(typeof plan.price === 'number' && plan.price === 0) ? (
382377
<span className="text-3xl font-bold">Free</span>
383378
) : (
384379
<>
385380
<LocalizedPrice
386-
basePrice={isByokPlan ? plan.price.monthly : plan.price[frequency]}
381+
basePrice={typeof plan.price === 'number' ? plan.price : plan.price.monthly}
387382
baseCurrency="USD"
388383
apiKey={process.env.NEXT_PUBLIC_EXCHANGE_API_KEY || ''}
389384
formatPrice={(price, currency) => (
@@ -395,31 +390,30 @@ export function BillingPricingCard({
395390
</span>
396391
)}
397392
/>
398-
<span className={cn('text-muted-foreground', insideDialog && 'text-sm')}>
399-
{isByokPlan
400-
? '/month'
401-
: `/${frequency === 'monthly' ? 'month' : 'year'}`
402-
}
403-
</span>
393+
{isByokPlan && (
394+
<span className={cn('text-muted-foreground', insideDialog && 'text-sm')}>
395+
/month
396+
</span>
397+
)}
404398
</>
405399
)}
406400
</div>
407401

408402
{isByokPlan && (
409403
<div className="mt-1">
410404
<Badge variant="secondary" className="text-xs">
411-
Paid Annually
405+
Monthly Subscription
412406
</Badge>
413407
</div>
414408
)}
415409

416410
{plan.credits !== 0 && (
417411
<div className="mt-2 flex items-center gap-2 text-sm text-muted-foreground">
418412
<Zap className="h-4 w-4 text-blue-500" />
419-
<span>
420-
{plan.credits === -1 ? 'Unlimited' : plan.credits}
421-
{plan.credits === -1 ? ' credits' : ' credits/month'}
422-
</span>
413+
<span>
414+
{plan.credits === -1 ? 'Unlimited' : plan.credits}
415+
{plan.planId === 'free' ? ' credits/month' : plan.credits === -1 ? ' credits' : ' credits'}
416+
</span>
423417
</div>
424418
)}
425419
</div>
@@ -474,7 +468,7 @@ export function BillingPricingCard({
474468
>
475469
<span className="flex items-center justify-center space-x-2">
476470
<span>{plan.btn.text}</span>
477-
{!plan.isCurrentPlan && !plan.isUpgrading && plan.price.monthly > 0 && (
471+
{!plan.isCurrentPlan && !plan.isUpgrading && ((typeof plan.price === 'number' && plan.price > 0) || (typeof plan.price === 'object' && plan.price.monthly > 0)) && (
478472
<ArrowRight className="h-4 w-4" />
479473
)}
480474
</span>

0 commit comments

Comments
 (0)