diff --git a/frontend/src/billing/billingApi.ts b/frontend/src/billing/billingApi.ts
index 74241622..26bb287c 100644
--- a/frontend/src/billing/billingApi.ts
+++ b/frontend/src/billing/billingApi.ts
@@ -18,6 +18,7 @@ export type BillingStatus = {
total_tokens: number | null;
used_tokens: number | null;
usage_reset_date: string | null;
+ api_credit_balance?: number;
};
type BillingRecurringInfo = {
diff --git a/frontend/src/components/BillingStatus.tsx b/frontend/src/components/BillingStatus.tsx
index 9ff291df..6f208fdf 100644
--- a/frontend/src/components/BillingStatus.tsx
+++ b/frontend/src/components/BillingStatus.tsx
@@ -50,6 +50,9 @@ export function BillingStatus() {
const isFree = billingStatus.product_name.toLowerCase().includes("free");
const isMax = billingStatus.product_name.toLowerCase().includes("max");
+ const hasApiAccess =
+ billingStatus.product_name?.toLowerCase().includes("pro") || isMax || isTeamPlan;
+
const getChatsText = () => {
if (isFree) {
if (billingStatus.chats_remaining === null || billingStatus.chats_remaining <= 0) {
@@ -59,9 +62,13 @@ export function BillingStatus() {
}
if (!billingStatus.can_chat) {
if (isMax) {
- return "Contact us to increase your limits";
+ return hasApiAccess
+ ? "Purchase API credits or contact us to increase limits"
+ : "Contact us to increase your limits";
}
- return "You've run out of messages, upgrade to keep chatting!";
+ return hasApiAccess
+ ? "Upgrade your plan or purchase API credits to keep chatting!"
+ : "You've run out of messages, upgrade to keep chatting!";
}
// Show team name for team plans
diff --git a/frontend/src/components/CreditUsage.tsx b/frontend/src/components/CreditUsage.tsx
index 17eb8882..63c9c5fc 100644
--- a/frontend/src/components/CreditUsage.tsx
+++ b/frontend/src/components/CreditUsage.tsx
@@ -22,6 +22,10 @@ export function CreditUsage() {
return null;
}
+ // Check if user has API credits - always show if they have any
+ const hasApiCredits =
+ billingStatus.api_credit_balance !== undefined && billingStatus.api_credit_balance > 0;
+
// Set bar color based on usage
const getBarColor = () => {
if (percentUsed >= 90) return "rgb(239, 68, 68)"; // Tailwind red-500
@@ -29,10 +33,14 @@ export function CreditUsage() {
return "rgb(16, 185, 129)"; // Tailwind emerald-500
};
+ const formatCredits = (credits: number) => {
+ return new Intl.NumberFormat("en-US").format(credits);
+ };
+
return (
- Credit Usage
+ Plan Credits
{roundedPercent}%
@@ -44,8 +52,13 @@ export function CreditUsage() {
}}
/>
-
- {formatResetDate(billingStatus.usage_reset_date)}
+
+ {hasApiCredits && (
+ + {formatCredits(billingStatus.api_credit_balance ?? 0)} API credits
+ )}
+
+ {formatResetDate(billingStatus.usage_reset_date)}
+
);
diff --git a/frontend/src/components/UpgradePromptDialog.tsx b/frontend/src/components/UpgradePromptDialog.tsx
index 71941017..5e9ea804 100644
--- a/frontend/src/components/UpgradePromptDialog.tsx
+++ b/frontend/src/components/UpgradePromptDialog.tsx
@@ -16,7 +16,8 @@ import {
FileText,
Gauge,
MessageCircle,
- Globe
+ Globe,
+ Coins
} from "lucide-react";
import { useNavigate } from "@tanstack/react-router";
import { useLocalState } from "@/state/useLocalState";
@@ -42,6 +43,11 @@ export function UpgradePromptDialog({
navigate({ to: "/pricing" });
};
+ const handleBuyCredits = () => {
+ onOpenChange(false);
+ navigate({ to: "/", search: { api_settings: true } });
+ };
+
const handleNewChat = () => {
onOpenChange(false);
// Trigger new chat event
@@ -57,6 +63,7 @@ export function UpgradePromptDialog({
const isFreeTier = !localState.billingStatus?.product_name || currentPlan === "free";
const isPro = currentPlan.includes("pro") && !currentPlan.includes("max");
const isMax = currentPlan.includes("max");
+ const hasApiAccess = isPro || isMax || currentPlan.includes("team");
const getNextPlan = () => {
if (isFreeTier) return "Pro";
@@ -130,8 +137,8 @@ export function UpgradePromptDialog({
description: isFreeTier
? "You've reached your daily free tier limit. Upgrade to Pro for unlimited daily usage."
: isPro
- ? "You've reached your Pro plan's monthly limit. Upgrade to Max for 10x more usage."
- : "You've reached your monthly usage limit. Please wait for the next billing cycle.",
+ ? "You've reached your Pro plan's monthly limit. Upgrade to Max for 10x more usage, or purchase API credits to continue chatting."
+ : "You've reached your monthly usage limit. Purchase API credits to continue chatting, or wait for the next billing cycle.",
requiredPlan: nextPlan,
benefits: isFreeTier
? [
@@ -147,11 +154,12 @@ export function UpgradePromptDialog({
"10x more monthly messages with Max plan",
"Access to all premium models including DeepSeek R1",
"Highest priority during peak times",
- "Maximum rate limits for power users"
+ "Maximum rate limits for power users",
+ "Or purchase API credits to keep chatting now"
]
: [
"You're already on our highest individual plan",
- "Consider Team plans for shared usage",
+ "Purchase API credits to extend your usage",
"Monthly usage automatically refreshes",
"Contact support for custom enterprise plans"
]
@@ -230,23 +238,30 @@ export function UpgradePromptDialog({
) : null}
-
+
+ {(info.requiredPlan !== "Max" || !isMax) && (
+
+
+ {isFreeTier ? "Upgrade to Pro" : isPro ? "Upgrade to Max" : "View Plans"}
+
+ )}
+ {/* Show Buy Credits button for paid users hitting usage limits */}
+ {feature === "usage" && hasApiAccess && (
+
+
+ Buy API Credits
+
+ )}
{/* Show "Start New Chat" for free tier conversation limit, "Maybe Later" for others */}
{feature === "tokens" && isFreeTier ? (
-
+
Start New Chat
) : (
- onOpenChange(false)}>
+ onOpenChange(false)} className="w-full">
Maybe Later
)}
- {(info.requiredPlan !== "Max" || !isMax) && (
-
-
- {isFreeTier ? "Upgrade to Pro" : isPro ? "Upgrade to Max" : "View Plans"}
-
- )}
diff --git a/frontend/src/components/apikeys/ApiCreditsSection.tsx b/frontend/src/components/apikeys/ApiCreditsSection.tsx
index a5438931..7b2c22bd 100644
--- a/frontend/src/components/apikeys/ApiCreditsSection.tsx
+++ b/frontend/src/components/apikeys/ApiCreditsSection.tsx
@@ -193,7 +193,7 @@ export function ApiCreditsSection({ showSuccessMessage = false }: ApiCreditsSect
{formatCredits(creditBalance?.balance || 0)}
- $1 per 1,000 credits • Use for API requests
+ $1 per 1,000 credits • Extends your subscription when plan credits run out
diff --git a/frontend/src/components/apikeys/ApiKeyDashboard.tsx b/frontend/src/components/apikeys/ApiKeyDashboard.tsx
index be7d18d5..66a8e2e3 100644
--- a/frontend/src/components/apikeys/ApiKeyDashboard.tsx
+++ b/frontend/src/components/apikeys/ApiKeyDashboard.tsx
@@ -162,9 +162,9 @@ export function ApiKeyDashboard({ showCreditSuccessMessage = false }: ApiKeyDash
-
Pay-As-You-Go Credits
+
Extend Your Subscription
- Purchase credits for API usage at just $1 per 1,000 credits
+ Purchase API credits to extend your usage when plan credits run out
@@ -183,7 +183,7 @@ export function ApiKeyDashboard({ showCreditSuccessMessage = false }: ApiKeyDash
- Unlock API access, increased limits, and premium features
+ Use your plan credits via API, and purchase extra credits to extend your usage
diff --git a/frontend/src/config/pricingConfig.tsx b/frontend/src/config/pricingConfig.tsx
index 942e9dc5..783a0696 100644
--- a/frontend/src/config/pricingConfig.tsx
+++ b/frontend/src/config/pricingConfig.tsx
@@ -139,7 +139,7 @@ export const PRICING_PLANS: PricingPlan[] = [
icon:
},
{
- text: "API Access",
+ text: "API Access (use plan credits via API)",
included: true,
icon:
}
@@ -189,7 +189,7 @@ export const PRICING_PLANS: PricingPlan[] = [
icon:
},
{
- text: "API Access",
+ text: "API Access (use plan credits via API)",
included: true,
icon:
}
@@ -248,7 +248,7 @@ export const PRICING_PLANS: PricingPlan[] = [
icon:
},
{
- text: "API Access",
+ text: "API Access (use plan credits via API)",
included: true,
icon:
}
diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx
index 013dbe39..4e388742 100644
--- a/frontend/src/routes/index.tsx
+++ b/frontend/src/routes/index.tsx
@@ -20,6 +20,7 @@ type IndexSearchOptions = {
next?: string;
team_setup?: boolean;
credits_success?: boolean;
+ api_settings?: boolean;
};
function validateSearch(search: Record): IndexSearchOptions {
@@ -28,7 +29,9 @@ function validateSearch(search: Record): IndexSearchOptions {
next: search.next ? (search.next as string) : undefined,
team_setup: search?.team_setup === true || search?.team_setup === "true" ? true : undefined,
credits_success:
- search?.credits_success === true || search?.credits_success === "true" ? true : undefined
+ search?.credits_success === true || search?.credits_success === "true" ? true : undefined,
+ api_settings:
+ search?.api_settings === true || search?.api_settings === "true" ? true : undefined
};
}
@@ -43,7 +46,7 @@ function Index() {
const queryClient = useQueryClient();
const { setBillingStatus, billingStatus } = useLocalState();
- const { login, next, team_setup, credits_success } = Route.useSearch();
+ const { login, next, team_setup, credits_success, api_settings } = Route.useSearch();
// Modal states
const [teamDialogOpen, setTeamDialogOpen] = useState(false);
@@ -119,6 +122,15 @@ function Index() {
}
}, [credits_success, os.auth.user, navigate, queryClient]);
+ // Handle api_settings - open API key dialog directly
+ useEffect(() => {
+ if (api_settings && os.auth.user) {
+ setApiKeyDialogOpen(true);
+ // Clear the query param to prevent re-opening on refresh
+ navigate({ to: "/", replace: true });
+ }
+ }, [api_settings, os.auth.user, navigate]);
+
// Check if guest user needs to pay
const isGuestUser = os.auth.user?.user.login_method?.toLowerCase() === "guest";
const isOnFreePlan = billingStatus?.product_name?.toLowerCase().includes("free") ?? false;
diff --git a/frontend/src/routes/pricing.tsx b/frontend/src/routes/pricing.tsx
index cfd562f0..5efd4ea1 100644
--- a/frontend/src/routes/pricing.tsx
+++ b/frontend/src/routes/pricing.tsx
@@ -156,6 +156,23 @@ function PricingFAQ() {
+
+
+ Can I use my subscription for API access?
+
+
+
+ Yes! Pro, Max, and Team plans include API access. Your subscription credits work
+ seamlessly with the API.
+
+
+ Use your plan credits via the API
+ When plan credits run out, API credits kick in automatically
+ Purchase additional API credits to extend your usage anytime
+
+
+
+
How did you build this?