Skip to main content

Billing & Monetization Documentation

๐Ÿ’ฐ Overviewโ€‹

The Billing Service (src/services/billingService.ts) manages subscriptions, usage tracking (Credit System), and invoicing. It is designed to support a Hybrid Pricing Model (Subscription + Usage-Based Overages).

๐Ÿท๏ธ Pricing Tiers (Hardcoded Configuration)โ€‹

TierBase Price (IDR)Token LimitOverage Rate
FREERp 0500-
PRORp 299.00050,000Rp 10 / 1k tokens
ENTERPRISERp 999.000500,000Rp 10 / 1k tokens

Configuration is located in billingService.ts constant PRICING.

๐Ÿ’ณ Credit System (AI Tokens)โ€‹

The system tracks AI usage via aiUsageCount on the teams table.

Usage Tracking Flowโ€‹

  1. Check Quota: Before any AI operation, BillingService.checkQuota(teamId, cost) is called.
  2. Execute Operation: If checking passes, the AI task runs.
  3. Deduct/Track: BillingService.trackUsage(teamId, tokensUsed) increments the counter.
    • Also updates/creates a usage_billings record for the current month.
    • Triggers "Upsell" notification if usage approaches the limit.

๐Ÿงพ Monthly Billing Cycleโ€‹

  • Background Job: processMonthlyBilling() (Usually triggered via Cron/Inngest).
  • Logic:
    1. Calculates overageTokens = usage - limit.
    2. usageAmount = overageTokens * rate.
    3. totalAmount = baseAmount + usageAmount.
    4. Generates a database record in usage_billings.
    5. Sends email notification to Team Admins.

๐Ÿ”Œ Stripe Integrationโ€‹

  • Webhooks: handleSubscriptionChange updates team.tier and team.subscriptionStatus.
  • Payment Failure: Automatically downgrades status to past_due and blocks AI access via checkQuota.

๐Ÿš€ Usage Exampleโ€‹

import { BillingService } from '@/services/billingService';

const teamId = "team_123";
const estimatedCost = 100;

// 1. Gatekeeping
const canProceed = await BillingService.checkQuota(teamId, estimatedCost);
if (!canProceed) throw new Error("Quota exceeded or Payment failed");

// 2. Perform Expensive Action...
// ...

// 3. Billing
await BillingService.trackUsage(teamId, estimatedCost);