Skip to main content

Documentation Index

Fetch the complete documentation index at: https://grantmaster.dev/llms.txt

Use this file to discover all available pages before exploring further.

Engineering reference: For service contracts, EventBus events, and data-layer details see src/features/billing/billing.md.

Billing

Overview

The Billing feature manages the complete financial lifecycle of organizations on GrantMaster. It provides subscription tier selection (Potential/Professional/Ultimate), seat-based licensing, Stripe payment processing, event-based usage metering (API calls, AI generations, storage, agent operations), agent credit reservations with atomic consumption, module marketplace add-on billing, and threshold-based usage alerts. Revenue analytics track MRR, ARR, and platform-wide financial metrics. All sensitive Stripe operations are handled server-side via Cloud Functions.

Data Model

Firestore Collections

CollectionDocument TypeDescription
organizationsOrganizationCore tenant with subscription tier, billing cycle, feature entitlements, seat allocation, usage metrics, and agent credit balance
subscriptionPricingSubscriptionTierDefinitionPricing definitions per tier (monthly/yearly base price, per-seat price, included seats, feature set)
billingTransactionsBillingTransactionPayment history, refunds, chargebacks with Stripe references and amount tracking
refundRequestsRefundRequestRefund request workflows (pending → approved → processed) with review notes
billingAdjustmentsBillingAdjustmentAdmin-applied credits, debits, discounts with audit trail
organizations/{orgId}/creditReservationsCreditReservationHolds on agent credits before runs (active → consumed/released/expired after 1 hour TTL)
usage_eventsUsageEventEvent-based metering: API calls, AI generations, storage, agent steps, document processing
usage_alertsUsageAlertThreshold crossing records (80%/90%/95%/100%) to prevent duplicate notifications

Key TypeScript Types

TypePurpose
SubscriptionTierEnum: POTENTIAL | PROFESSIONAL | ULTIMATE
SubscriptionFeaturesFeature flags per tier: includedSeats, maxProjects, aiGenerationsPerMonth, agentCreditsPerMonth, customReports, etc.
SubscriptionSeats{ included, purchased, total, used, available } — seat allocation and usage
SubscriptionPricing{ basePriceMonthly, basePriceYearly, seatPriceMonthly, seatPriceYearly, currency, nextBillingAmount, nextBillingDate }
SubscriptionTierConfigFull tier definition: name, description, pricing, feature set, Stripe price IDs, display metadata
SubscriptionTierDefinitionTier pricing persisted in Firestore with isActive, effectiveFrom, quotas
CreditReservation{ id, organizationId, agentRunId, amount, consumedAmount, status: 'active'|'consumed'|'released'|'expired', createdAt, expiresAt }
CreditBalance{ total, used, reserved, available, purchasedExtra } — snapshot of org credit status
CreditConsumptionResultResult of consuming credits: { success, creditsConsumed, remainingInReservation, totalUsedThisMonth }
BillingTransactionPayment record: organizationId, amount, currency, transactionDate, stripeChargeId, status, type
RefundRequestRefund workflow: organizationId, transactionId, amount, status (PENDING|APPROVED|REJECTED|PROCESSED), reviewer details
UsageEventEvent record: organizationId, eventType, metadata, timestamp, billingPeriodKey
StripePaymentMethodCard/SEPA method: { id, type, card?, sepaDebit?, billingDetails, isDefault, createdAt }
StripeSubscriptionDetailsStripe subscription snapshot: status, tier, currentPeriodStart/End, cancelAtPeriodEnd, nextInvoiceDate

Key Behaviors

Subscription Lifecycle

Tier selection, upgrades/downgrades, seat enforcement, and period lifecycle. Upgrade/Downgrade: User initiates tier change, service calculates prorated cost via calculateTotalCost(), Stripe charges via Cloud Functions, subscription.tier and features updated on success. Cancellation: cancelAtPeriodEnd flag set; services continue through billing period; at period end, status → ‘canceled’, features revert to POTENTIAL tier. Seat Management: canAddUser() checks seats.available; user invitation blocked if exhausted; additional seats trigger per-seat Stripe charge (seatPriceMonthly × quantity).

Credit Reservation & Consumption

Agent credit lifecycle: reserve → consume per step → release on completion. Reserve: Before agent run, reserveCredits(orgId, amount, agentRunId) atomically checks available = (monthlyLimit + purchased) - used - reserved. If sufficient, creates CreditReservation (active, expires in 1 hour TTL). Emits CREDITS_RESERVED event. Consume: After each step, consumeCredits(orgId, reservationId, actualAmount) moves credits from reserved to used (decrements both counters). Throws if reservation inactive or amount exceeds remaining. Idempotent within Firestore transaction. Release: On run completion/cancellation, releaseCredits() marks reservation as ‘released’ and refunds unused amount back to available pool. Query Balance: getCreditBalance() returns snapshot with total, used, reserved, available, purchasedExtra.

Usage Tracking

Event-based metering records feature usage in usage_events with billingPeriodKey (YYYY-MM) for aggregation. Events tracked: api_call, ai_generation, rag_query, rag_document_process, rag_embedding, agent_run, agent_step, storage_upload, storage_delete, credit_consumed, credit_purchased, module_install. Each includes organizationId, timestamp, eventType, and type-specific metadata. Query via trackUsageEvent() or convenience trackers (trackApiCall(), trackAgentRun(), etc.). Aggregate by period with getUsageEvents(orgId, billingPeriodKey) and getRAGUsageStats().

Usage Alerts

Threshold-based monitoring: checkUsageAlerts(orgId) compares current usage vs tier feature limits. For thresholds 80%/90%/95%/100% crossed on metrics (API calls, AI generations, storage), emits alert if not already sent this period. Prevents duplicate notifications. Emails admins with “Approaching limit” (80-95%) or “Limit reached” (100%) messages. Alerts recorded in usage_alerts to track history and avoid re-notification within same period.

Refund Workflow

Request: User/admin submits refund with reason; status: PENDING. Approval: SuperAdmin reviews, approves or rejects, records notes and decision; status: APPROVED. Processing: processRefund() calls Cloud Functions to issue Stripe refund, marks related BillingTransaction as REFUNDED, updates status: PROCESSED.

Module Marketplace Billing

Add-on modules as optional Stripe SubscriptionItems. Free in Tier: installModule(moduleId) checks if module included in current subscription features. If yes, activates directly without Stripe charge. Response: { activatedDirectly: true }. Paid Module: Module not included → redirect to createCheckoutSession() for Stripe Checkout. On success, adds SubscriptionItem with module price to existing subscription. Monthly charge applies on next billing date. Operations: installModule() (activate or redirect), uninstallModule() (remove SubscriptionItem, trigger prorated refund), getModuleStatus() (check activation, pricing, billing state).

Service Contract

ServiceOwnsKey Methods
CreditServiceAgent credit reservation, consumption, balance trackingreserveCredits(orgId, amount, agentRunId), consumeCredits(orgId, reservationId, amount), releaseCredits(orgId, reservationId), getCreditBalance(orgId), addPurchasedCredits(orgId, packSize, stripePaymentIntentId?)
BillingServiceSubscription pricing, billing transactions, revenue metrics, refundsgetAllSubscriptionPricing(), getSubscriptionPricing(tier), getOrganizationBillingHistory(orgId), createBillingTransaction(), calculateRevenueMetrics(), getAllBillingTransactions(), getPendingRefunds(), processRefund(), createBillingAdjustment()
SubscriptionServiceSubscription tier config, seat allocation, cost calculationgetSubscriptionTierConfig(tier), calculateSeatsNeeded(userCount), calculateTotalCost(tier, totalSeats, billingCycle), canAddUser(orgId), calculateSeatUsage(orgId)
StripePaymentServiceStripe API integration: checkout, payment methods, customer portalcreateCheckoutSession(), createCustomer(), fetchPaymentMethods(orgId), getCustomerPortalUrl(orgId), getUpcomingInvoice(orgId), attachPaymentMethod(), detachPaymentMethod()
StripeModuleBillingModule marketplace Stripe billinginstallModule(orgId, moduleId), uninstallModule(orgId, moduleId), previewModuleCheckout(), getModuleStatus()
UsageTrackingServiceUsage metering: event recording and queryingtrackUsageEvent(), trackApiCall(), trackAiGeneration(), trackRAGQuery(), trackAgentRun(), trackAgentStep(), trackStorageUpload(), trackStorageDelete(), getUsageEvents(orgId, billingPeriodKey), getRAGUsageStats()
UsageAlertsServiceThreshold monitoring and notificationscheckUsageAlerts(orgId), getOrganizationAlerts(orgId)

Events

Emitted

EventTriggerSeverityPersisted
CREDITS_PURCHASEDaddPurchasedCredits() succeedsINFOYes
SUBSCRIPTION_TIER_UPDATEDTier change confirmedINFOYes
SUBSCRIPTION_PRICING_UPDATEDSuperAdmin updates pricingINFOYes
SEAT_LIMIT_REACHEDcanAddUser() returns falseERRORYes
USAGE_ALERT_SENTThreshold 80%/90%/95%/100% crossedWARNINGYes

Consumed

Currently minimal; future integrations with agents and other features will consume credit and subscription events.
EventExpected Handler
(Agent execution events)Credit reservation/consumption hooks

Dependencies

  • Depends on: Firebase (Firestore, Cloud Functions, Auth), Stripe API, EventBus, BaseService, logger, timeProvider
  • Depended on by: Agents (credit reservation), Users (seat checking), Documents (storage tracking), Reports (AI metering), Integrations (API call tracking), Dashboard (usage display)

File Structure

src/features/billing/
├── services/
│   ├── creditService.ts              # CreditService: reserve/consume/release, balance tracking
│   ├── billingService.ts             # BillingService: pricing, transactions, revenue, refunds
│   ├── subscriptionService.ts        # SubscriptionService: tier config, seats, cost calc
│   ├── stripePaymentService.ts       # StripePaymentService: checkout, portal, payment methods
│   ├── stripeModuleBilling.ts        # StripeModuleBilling: module add-on subscriptions
│   ├── usageTracking.ts              # UsageTrackingService public barrel
│   ├── usageTrackingCore.ts          # trackUsageEvent() core implementation
│   ├── usageTrackingTypes.ts         # UsageEvent type definitions
│   ├── usageTrackingQueries.ts       # getUsageEvents(), getRAGUsageStats()
│   ├── usageTrackingTrackers.ts      # trackApiCall(), trackAgentRun(), etc.
│   ├── usageAggregation.ts           # Aggregate usage by billing period (YYYY-MM)
│   ├── usageAlerts.ts                # UsageAlertsService: checkUsageAlerts()
│   ├── billingPeriod.ts              # getBillingPeriodKey(), getCurrentBillingPeriod()
│   ├── billingPeriod.test.ts         # Tests for billing period utilities
│   └── subscriptionService.test.ts   # Tests for subscription calculations
├── components/
│   ├── Billing.tsx                   # Main page container
│   ├── billing-page/
│   │   ├── SubscriptionTab.tsx        # Tier selection, upgrade/downgrade UI
│   │   ├── SubscriptionStatusBanner.tsx
│   │   ├── PaymentMethodsTab.tsx      # Payment methods, customer portal
│   │   ├── InvoicesTab.tsx            # Billing history, invoices
│   │   ├── UsageTab.tsx               # Usage metrics, limits, alerts
│   │   ├── ModuleExtensionsTab.tsx    # Module marketplace UI
│   │   ├── BillingInfoTab.tsx         # Billing details
│   │   ├── CancelDialog.tsx           # Cancellation workflow
│   │   └── types.ts
│   └── pages/
│       └── FinancialsManagement.tsx   # Admin: revenue metrics, refunds, adjustments
├── hooks/
│   ├── useBilling.ts                 # tRPC billing queries
│   ├── useBillingState.ts            # Local state (activeTab, billingCycle, dialogs)
│   ├── useBillingActions.ts          # Mutation wrappers
│   └── useBillingState.test.ts
├── index.ts                          # Public API barrel (services, components)
└── README.md                         # This file

Architecture Notes

Firestore Transactions: CreditService uses runTransaction() to atomically check balance and reserve credits, preventing overdraft from concurrent agent runs. Reservation and consumption both read current org state, validate, and update in a single transaction. Cloud Functions: Sensitive Stripe operations (checkout, refunds, subscriptions) are server-side via Cloud Functions. Frontend calls via httpsCallable() with safe publishable keys only; secret keys never exposed. Usage Metering: Events recorded in usage_events with billingPeriodKey (YYYY-MM) for efficient querying by period. Aggregation queries sum events within period; alerts compare aggregates against tier limits. Module Billing: Modules as optional Stripe SubscriptionItems on org subscription. Install check: if included in tier, activate directly; else redirect to Stripe Checkout. Uninstall removes SubscriptionItem and triggers prorated refund. Seat Enforcement: Checked at user invitation time via canAddUser(). Blocks invitation if seats.available == 0. Extra seats purchased via Stripe add per-seat charges to subscription.