AUTH4D-33 billing contracts
These schemas live in packages/contracts/src/billing.ts and are re-exported from
@auth4/contracts. They describe wire shapes only; this fragment enables no routes. The owning
billing tickets choose route paths and implement them.
Money, plans and entitlements
Moneyis{ amountMinor, currency }: a non-negative safe integer in minor units (cents) and an ISO 4217 code from the closedCurrencyCodeenum (currentlyZAR). Floats are rejected.PlanIdis a closed enum:free,indie,studio.PaidPlanIdexcludesfree.Plancarriesprice,interval(monthoryear),trialDaysandPlanEntitlements(maxMonthlyActiveUsers,maxApplications,auditLogRetentionDays). Onlyfreemay cost zero. Catalog values live inpackages/billing, not in contracts.
Management DTOs
BillingPlanCatalogResponselists unique plans.ManagementBillingSubscriptionResponsereturns the effectiveplanId, itsentitlementsand theSubscriptionornull. Tenants without a subscription are onfree.Subscription.statusis a closed enum:trialing,active,past_due,canceledorincomplete.trialingrequirestrialEndsAt.canceledAtis present exactly when the status iscanceled.Invoicekeeps line items, total and invoice currency consistent.paidAtis present exactly when the status ispaid. Lists useManagementInvoiceListResponsewith an optionalnextCursor.Payment.statusis a closed enum:pending,completed,failed,canceledorexpired.completedAtis present exactly when the status iscompleted, and onlyfailedpayments carry afailureReason. Lists useManagementPaymentListResponse.CreateCheckoutRequestaccepts only{ planId }with a paid plan. Price and entitlement are always decided server-side.CheckoutSessionResponsereturnspaymentId,redirectUrlandexpiresAt. The redirect must use HTTPS, except for loopback HTTP.CancelSubscriptionRequestaccepts{ atPeriodEnd }, which defaults totrue.
Normalized webhook events
BillingWebhookEvent is the provider-agnostic, signature-verified event that provider adapters emit
and the billing state machine consumes. It is discriminated on type; the only current type is
payment.status_changed. Every event carries an internal eventId, a provider slug, a
providerEventId, the tenantId, and occurredAt/receivedAt. Processing is idempotent on
billingWebhookIdempotencyKey(event), which is provider:providerEventId. Raw provider payloads
and provider-specific field names are rejected.
Billing mutations emit tenant audit events named from BILLING_AUDIT_EVENTS.
Source: docs/api-spec/auth4d-33.md