diff --git a/apps/api/src/controllers/Users.ts b/apps/api/src/controllers/Users.ts index 7a7d156..a248975 100644 --- a/apps/api/src/controllers/Users.ts +++ b/apps/api/src/controllers/Users.ts @@ -476,6 +476,25 @@ export class Users { // This is normal for new subscriptions or if there's no usage yet } + // Get customer to retrieve balance (credits) + const customer = await stripe.customers.retrieve(project.customer); + let credits = null; + + if (!customer.deleted) { + // Stripe stores balance in cents as a negative number (credit) or positive (debit) + // A negative balance means the customer has credits + const balance = customer.balance || 0; + const hasCredits = balance < 0; + const creditAmount = hasCredits ? Math.abs(balance) : 0; + + credits = { + balance, + hasCredits, + creditAmount, + currency: customer.currency || 'usd', + }; + } + return res.status(200).json({ period: { start: startOfMonth.toISOString(), @@ -485,6 +504,7 @@ export class Users { total: totalUsage, records: [], // Deprecated in favor of invoice line items }, + credits, upcomingInvoice: upcomingInvoice ? { amountDue: upcomingInvoice.amount_due, diff --git a/apps/api/src/controllers/Webhooks.ts b/apps/api/src/controllers/Webhooks.ts index cbcd2cd..1936450 100644 --- a/apps/api/src/controllers/Webhooks.ts +++ b/apps/api/src/controllers/Webhooks.ts @@ -276,6 +276,11 @@ export class Webhooks { }, }); + // add 1 eur/usd in credit in return for onboarding fee + await stripe.customers.update(customerId, { + balance: -100, + }); + signale.success(`[WEBHOOK] Checkout completed for project ${projectId}`); // Send notification about subscription started diff --git a/apps/web/src/components/BillingConsumption.tsx b/apps/web/src/components/BillingConsumption.tsx index 3c23eca..c5bc4d6 100644 --- a/apps/web/src/components/BillingConsumption.tsx +++ b/apps/web/src/components/BillingConsumption.tsx @@ -1,5 +1,5 @@ import {Card, CardContent, CardDescription, CardHeader, CardTitle, Alert} from '@plunk/ui'; -import {AlertCircle, TrendingUp} from 'lucide-react'; +import {AlertCircle, TrendingUp, Coins} from 'lucide-react'; import {useBillingConsumption} from '../lib/hooks/useBillingConsumption'; import {useConfig} from '../lib/hooks/useConfig'; import {useCallback} from 'react'; @@ -119,6 +119,26 @@ export function BillingConsumption({projectId, hasSubscription}: BillingConsumpt + {/* Account Credits */} + {consumptionData.credits && consumptionData.credits.hasCredits && ( +
Account Credits
++ {formatCurrency(consumptionData.credits.creditAmount, consumptionData.credits.currency)} +
++ Credits will be automatically applied to your upcoming invoices +
+