Billing & Subscriptions
Relevant source files
The following files were used as context for generating this wiki page:
- packages/farm-stripe/src/index.ts
- packages/farm-polar/src/index.ts
- packages/farm-autumn/src/index.ts
- examples/stripe-integrations/prisma-org/src/app/dashboard/page.tsx
- examples/stripe-integrations/prisma-org/README.md
- examples/autumn-integration/src/app/dashboard/page.tsx
- examples/polar-integration/src/app/home-client.tsx
- examples/stripe-integrations/prisma/src/app/home-client.tsx
Farm.js provides a unified, typed interface for product-integrated billing and subscriptions. It abstracts complex provider interactions from services like Stripe, Polar, and Autumn into a provider-neutral API. This system manages subscription lifecycles, metered usage reporting, seat-based limits, and hosted checkout flows.
The framework implements a typed integration model where billing data is exposed via centralized endpoints such as /billing/features, /billing/limits, and /billing/usage. This allows applications to resolve plan-specific capabilities and limits regardless of the underlying payment processor.
Sources: examples/stripe-integrations/prisma-org/README.md:1-12, ARCHITECTURE.md:46-52
API Architecture
The Billing API operates through the apiClient.billing namespace, providing methods for catalog discovery, checkout, and usage tracking.
Core Billing Endpoints
| Endpoint | Functionality |
|---|---|
billing.status() | Retrieves the current subscription plan, product ID, and status (e.g., trialing, active). |
billing.products() | Fetches the full product catalog from the provider, including intervals and pricing. |
billing.checkout() | Initiates a hosted checkout session for a specific product. |
billing.portal() | Generates a link to the provider-hosted customer billing portal. |
billing.usage() | Resolves app-side usage for specific keys (e.g., seats, projects). |
billing.check() | Performs a preflight check to see if a resource consumption is allowed under current limits. |
billing.reportUsage() | Reports metered usage events (e.g., API calls, tokens) to the provider. |
billing.meterUsage() | Retrieves summaries of metered usage for the current period from the provider. |
billing.upcomingInvoice() | Previews the next invoice, including recurring items and metered overages. |
Sources: examples/stripe-integrations/prisma-org/src/app/dashboard/page.tsx:298-348, examples/stripe-integrations/prisma-org/README.md:11-20
Checkout Flow
Checkout uses a hosted provider session to resolve the billing owner and handle payment information.
This diagram represents the typical flow for initiating a subscription via hosted checkout.
Sources: examples/stripe-integrations/prisma/src/app/home-client.tsx:117-142, examples/stripe-integrations/prisma-org/README.md:6-10
Metered Billing & Usage
Farm.js supports metered billing where usage is measured via meters and billed according to provider configurations.
Meter Reporting Mechanism
The reportUsage() method sends direct meter events to the provider using a configured eventName. The provider (e.g., Stripe) matches this name to a dashboard-defined meter.
- Aggregation: Meters can sum quantities (e.g., total tokens) or count events (e.g., number of API calls).
- Ingestion: Supports
rawingestion of usage data. - Idempotency: Requires an
idempotencyKeyto prevent duplicate reporting of the same event.
Sources: examples/stripe-integrations/prisma-org/README.md:83-100, examples/autumn-integration/src/app/dashboard/page.tsx:327-353
Usage Verification Sequence
Apps should perform a preflight check before allowing users to consume limited resources.
This sequence ensures consumption remains within defined plan boundaries.
Sources: examples/stripe-integrations/prisma-org/README.md:23-45, examples/stripe-integrations/prisma-org/src/app/dashboard/page.tsx:437-458
Seat Management
Farm handles seat-based billing through different modes, primarily subscription_quantity and plan_limit.
Seat Limit Resolution
The effective seat limit for an organization is resolved in a specific order of precedence:
- Manual Override: The
seatAllowanceOverridevalue stored in the billing snapshot. - Subscription Quantity: The quantity purchased via a real Stripe/Polar subscription (when
modeissubscription_quantity). - Plan Default: The hard limit defined for the plan in
plans.limits.seats.
Sources: examples/stripe-integrations/prisma-org/README.md:68-80, examples/stripe-integrations/prisma-org/src/app/dashboard/page.tsx:113-130
Seat Billing Config Snippet
// Example Configuration for bundled seat plans
products: {
proMonthly: {
planId: "pro",
seatBilling: "included_plus_add_on",
seatPriceId: process.env.STRIPE_PRO_EXTRA_SEAT_MONTHLY_PRICE_ID,
},
}
Sources: examples/stripe-integrations/prisma-org/README.md:73-81
Hybrid Pricing Model
Farm.js supports hybrid models combining fixed recurring prices with metered overage.
- Base Subscription: A fixed price for the plan.
- Bundled Seats: A set number of seats included in the base price.
- Paid Add-ons: Recurring prices for extra seats above the bundled limit.
- Metered Overage: Variable charges based on token or API usage reported to meters.
Sources: examples/stripe-integrations/prisma-org/README.md:126-140, examples/autumn-integration/src/app/dashboard/page.tsx:556-590
Data Structures
The framework uses typed results to ensure consistency across different providers.
Billing Status Result
| Field | Description |
|---|---|
planId | The slug of the current plan (e.g., "free", "pro"). |
productId | The provider-specific ID for the current product. |
status | The subscription state (e.g., "trialing", "active", "past_due"). |
seatQuantity | The number of purchased seats. |
seatLimitSource | Indicates if the limit comes from "override", "subscription_quantity", or "plan_limit". |
Sources: examples/stripe-integrations/prisma-org/src/app/dashboard/page.tsx:782-815, examples/autumn-integration/src/app/dashboard/page.tsx:490-505
Meter Usage Result
| Field | Description |
|---|---|
currentPeriodUsed | Total units consumed in the current billing cycle. |
includedLimit | The allowance included in the plan before overage applies. |
remainingHard | Units remaining before a hard cap blocks further usage. |
state | Current meter state (e.g., "ok", "soft_limit_reached", "hard_limit_reached"). |
Sources: examples/stripe-integrations/prisma-org/src/app/dashboard/page.tsx:160-178, examples/autumn-integration/src/app/dashboard/page.tsx:645-710
Billing and subscription management in Farm.js enables developers to implement complex SaaS pricing models with minimal boilerplate. By centralizing usage checks and usage reporting, the framework ensures that business logic remains decoupled from the specific implementation details of payment providers.