Skip to content

Insights · Finance · "Who the AI bill belongs to" (2026-09-21)

The Finance tab already showed the two big numbers: what Stripe collected and what OpenRouter charged. This card answers the question underneath them: whose usage is that bill, and are the people who pay carrying the people who do not?

What it shows

  • Four audiences. Free users, paying subscribers, the creator program, and internal accounts. For each: how many people played in the window, how many wallets exist, AI cost split into play and Studio, what they paid, and the difference. A fifth row holds receipts that could not be tied to an account (usually refunds or fees on charges we no longer have a user for).
  • The break-even sentence. "Each paying subscriber carries N active free users. The margin allows about M." N is active free users divided by paying wallets. M is the margin per payer (what paying users paid minus their own AI cost, over all paying wallets, whether they played or not) divided by the net cost of one active free user (free AI cost minus what free users bought in packs, over active free users). When paying users have no margin left, the sentence says so instead of printing a number.
  • The business without the creator program. Free plus paying (plus loose receipts): receipts, AI matched to requests, that AI scaled up to its share of the real OpenRouter bill, and the difference. This is the "are we profitable once we ignore the grants we hand out on purpose" line.
  • Old lineup vs new lineup. Per lineup: signups in the period, the share that paid within 7 and 30 days of signing up (only signups old enough to have had the whole window are in the denominator, so a fresh signup never reads as a non-payer), and payers among the people who played. Conversion uses the lineup a wallet was born on (the creation grant reads "Initial … plan grant (drop 1)" on lineup 2), so a wallet migrated later never counts as a new-lineup signup with an old signup date. Then, for free and paying on each lineup: wallets, people who played, AI per person, receipts per person. This is how the lineup migration is watched without a script.
  • AI cost per person who played, by lineup. A day series (hourly on the 1-day view) for free users, with a toggle to paying subscribers: the old lineup and the new lineup as two lines. When the new line sits under the old one, the migration is doing what it was designed to do.
  • Check-ins handed over to quests. Mushies paid per day by the retired check-in ladder and by the quest board.

How wallets are classified

The change feed only mirrors id, user_id, plan for wallets, so two things are read off the ledger instead:

  • Lineup 2 (piles paid in drops): the wallet has a plan grant whose description carries (drop 1), starts with Scheduled drop, or starts with Upgrade settlement. Those are written by credit-service.ts and plan-drops.ts.
  • Creator program: the internal plan, a plan grant matching Admin <Tier> membership activation grant (entitlement-allowance.ts), or an admin credit grant (ledger type admin) in the last 90 days.

audience-economics.test.ts fails the build if those descriptions disappear from the billing code, because the card would then quietly count comped creators as paying subscribers and every wallet as lineup 1.

Receipts are the Stripe cash ledger joined to payment_dimensions, exactly as the purchase table does it. WeChat Pay plans go through Stripe Checkout, so they are included.

Reading it honestly

  • Costs are the requests we could price, using the same priced view as the rest of the tab (observed provider cost, else the day's billed model rate, else the reference rate). The four rows add up to the matched cost, not to the full OpenRouter bill; the unmatched share is shown in the details below the chart.
  • "People who played" counts accounts with a priced, non-BYOK request in the window. BYOK usage costs us nothing and is left out.
  • A wallet's audience is its current state, not its state at the time of each request. A user who subscribed yesterday has all of the window's cost under "paying".
  • The 90-day admin-grant rule means a creator who last received a grant four months ago counts as free or paying from then on. That is intended: the program is what you are spending now.

Where the code is

  • packages/server/src/analytics/audience-economics.ts: the queries and the break-even math; called from the finance branch of reports.ts.
  • packages/shared/src/admin-analytics.ts: FinanceAudience, FinanceBreakEven, and the three optional fields on FinanceReport.
  • packages/app/src/features/admin/insights/audience-economics.tsx: the card, rendered in the Finance panel above the details toggle.

Build cost, measured against production: one grouped read of about 13 seconds for 30 days (the totals and the per-day series come out of the same pass via GROUPING SETS), a one-second conversion read, and two sub-second reads. A failure is caught and logged; the finance report still publishes without the card.

First readings on 2026-09-21: old-lineup signups over the last 30 days paid within 7 days at 1.18% (153 of 12,983); the new lineup had no signup old enough to count yet (it shipped on the 15th), so its cell reads "—" until the 22nd.