Plans, entitlements, subscriptions, invoices and metered usage. Holds no card data — only a provider token, brand and last four.
govdeets_billing · BILLING_DATABASE_URL · prisma/billing/schema.prisma
BillingAccountThe billing side of an organization. One per organization, created lazily
the first time the org needs a plan (which includes being put on free).
Properties as follows:
id:organizationIdOpaque pointer to Organization in the
coredatastore. Unique because an organization has exactly one billing account; not a foreign key because that table is in a different database.
provider:providerCustomerIdThe provider's customer identifier (
cus_…at Stripe). Null while the account has never needed a payment method — a free plan never does.
billingEmailThe one address invoices go to. Deliberately not joined to any user: finance contacts leave, and billing should not break when they do.
currency:taxId: Tax identifier as supplied by the customer, for invoice rendering.status:delinquentSince: Set when a delinquent account has been locked out of paid features.createdAt:updatedAt:PaymentMethodRefA stored payment instrument, by reference. Everything sensitive stays at the provider; these columns exist only so the settings page can show which card is on file without a round trip.
Properties as follows:
id:billingAccountId:providerPaymentMethodId:kind: card, us_bank_account, link, …brand:last4:expMonth:expYear:isDefault:createdAt:detachedAt:PlanA purchasable plan. Plans are seeded and version-controlled rather than created at runtime, so the entitlement matrix is reviewable in a diff.
Properties as follows:
id:keyStable machine key used in code and in the cached
planKeyon Organization:free,team,business,enterprise.
name:description:priceCents:currency:interval:providerPriceIdThe provider's price object (
price_…at Stripe). Null for plans that are never charged, and for the mock provider.
isPublicWhether the plan appears on the public pricing page. Enterprise deals are real Plans that simply aren't listed.
sortOrder:createdAt:updatedAt:PlanEntitlementOne capability granted by a plan. This is the whole authorization vocabulary on the billing side: a feature key, whether it is on, and an optional numeric ceiling.
limit semantics: null means unlimited, and any non-null value is the
inclusive maximum. enabled = false denies the feature outright
regardless of limit.
Properties as follows:
id:planId:featureDotted feature key —
seats,watch.max,watch.triggers.max,api.v1.read,api.v1.history,api.v1.aggregate,api.rate.perMinute,integration.slack,export.bulk.
enabled:limit:SubscriptionAn organization's current (or past) subscription to a plan.
Properties as follows:
id:billingAccountId:planId:status:providerSubscriptionId:seatsPurchased seat count. Enforcement happens in
core, which is the only database that knows how many memberships actually exist.
currentPeriodStart:currentPeriodEnd:cancelAtPeriodEnd:trialEndsAt:canceledAt:createdAt:updatedAt:EntitlementOverrideA negotiated exception layered on top of the plan's entitlements — the "we'll throw in the history API" that sales agreed to. Kept separate from PlanEntitlement so the plan definition stays canonical and the exception stays visible and expirable.
Properties as follows:
id:subscriptionId:feature:enabled:limit:note: Why this exists, so the next person to read it isn't guessing.expiresAt:createdAt:InvoiceA mirror of an invoice held at the provider, kept locally so billing history renders without an API call and survives the provider being unreachable or replaced.
Properties as follows:
id:billingAccountId:providerInvoiceId:number: Human-facing invoice number.status:amountDueCents:amountPaidCents:currency:periodStart:periodEnd:issuedAt:paidAt:dueAt:hostedInvoiceUrl:pdfUrl:createdAt:UsageRecordMetered usage, pre-aggregated into windows rather than stored per request.
The per-request detail lives in core as ApiRequestLog, where it belongs
with the rest of the operational data; only the billable rollup crosses
into this database.
Properties as follows:
id:billingAccountId:featureMatches a PlanEntitlement feature key, so a limit can be checked against the same vocabulary that granted it.
quantity:windowStart:windowEnd:reportedAt: Set once the rollup has been reported to the provider for metered billing.createdAt:updatedAt:BillingEventRaw provider webhook events, recorded before they are acted on. Keeping
them makes payment state reconstructible after a bug, and providerEventId
being unique is what makes webhook delivery idempotent.
Properties as follows:
id:billingAccountId:provider:providerEventId:kind:payload:receivedAt:processedAt:error: