AUTH4D-38 billing domain (@auth4/billing)
This ticket adds the provider-agnostic billing domain and no public HTTP routes. Management billing routes and the Stitch webhook handler are specified by their owning tickets.
- Plan catalog (
PLAN_CATALOG):free(R0),indie(R199.00 = 19900 cents/month),studio(R999.00 = 99900 cents/month), each withPlanEntitlements. Prices and limits are placeholders pending product confirmation. Tenants without anactiveorpast_duesubscription are onfreeand need no billing account. - State machines use the stored 0005 statuses. Illegal transitions throw
IllegalTransitionError.- Subscription:
pending → active | canceled | expired;active → active | past_due | canceled | expired(active → activeis a renewal);past_due → active | canceled | expired;expired → active(reactivation by payment);canceledis terminal. - Payment:
pending → succeeded | failed | canceled | expired; all other states are terminal. - Invoice:
draft → open | void;open → paid | void | uncollectible;uncollectible → paid | void. - Contract mapping: payment
succeededmaps tocompleted; subscriptionpendingmaps toincomplete, andexpiredmaps tocanceled.
- Subscription:
- Repository (
createD1BillingRepository(db)): every read and write requires a customer tenant id and filters on it.recordProviderEventreturnsduplicatefor a repeated(provider, providerEventId).applyPaymentOutcomerecords the event, then commits the payment, invoice, subscription and event updates in one guarded D1 batch. A completed payment activates the subscription, or extends it by one interval, exactly once. Repeats and concurrent deliveries returnduplicateorignored, and a reported amount that differs from the stored amount is rejected. - External reference sent to the provider:
{tenantId}.{paymentId}(createExternalReference/parseExternalReference). - Mutations return
BillingAuditRecords (names fromBILLING_AUDIT_EVENTS) for the caller to append to the audit log.
Source: docs/api-spec/auth4d-38.md