This FRD ships @dmwd-io/billing as an optional package that re-exports stripe as the platform standard for subscription billing. The value is standards and drift prevention — not a custom abstraction. Platform conventions (env var names, event naming) are documented on top of the library’s own API.
Introduction
Overview
Per ADR-014 (Open Source First), the platform designates stripe as the community library for subscription billing. Rather than building a custom BillingProvider interface, @dmwd-io/billing re-exports stripe directly and documents the platform’s conventions: STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET as the standard env var names, and billing.{resource}.{action} as the internal event naming convention per ADR-065. Each consuming app gets a single, consistent import path and a documented baseline — without the maintenance burden of a custom abstraction layer.
Goals
Designate stripe as the platform standard for subscription billing per ADR-014.
Re-export stripe via @dmwd-io/billing to give apps a single, stable import path.
Document STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET as the platform env var conventions.
Normalize webhook event naming to billing.{resource}.{action} per ADR-065.
Include TypeScript examples showing package wiring, lifecycle flows, and widget integration.
Non-Goals
Building a custom provider interface or adapter layer — the library’s own API is the interface (per ADR-014).
Building a production vendor adapter from scratch (Stripe is the designated vendor).
Implementing payment method collection (see FRD: Payments Provider Wrapper).
Building billing-specific UI components beyond what already exists.
Supporting multi-currency conversion logic inside the package.
Acting as a tax calculation engine.
Scope
In Scope
Area
Description
Package re-export
@dmwd-io/billing re-exports stripe with stripe as a peer dependency
Env var conventions
Document STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET as platform standard names
Type re-exports
Re-export key stripe types (Stripe.Subscription, Stripe.Invoice, etc.) for consuming apps
Webhook event naming
Document billing.{resource}.{action} naming convention per ADR-065
Documentation
Storybook docs page with usage examples and integration guidance
Out of Scope
Area
Reason
Custom BillingProvider interface
ADR-014: library’s own API is the interface
Vendor adapter implementations
Not needed — stripe is the designated standard
Payment method CRUD
Covered by FRD: Payments Provider Wrapper
Tax calculation
Delegated to the billing vendor or a dedicated tax service
Billing UI components
Existing widgets are presentational; new widgets are a separate effort
Multi-tenant billing isolation
App-level concern, not a library contract responsibility
Users and Pain Points
User Groups
User
Description
Needs
App developers
Engineers building SaaS products on the design system
A single import for billing operations that works consistently across the platform
QA engineers
Testers validating subscription flows
Deterministic mock data for every subscription state
Design system maintainers
Contributors to the shared library
A clean, low-maintenance package that follows ADR-014
Pain Points
User
Pain Point
Impact
App developers
Each app imports stripe directly with inconsistent env var names and error handling
Duplicated effort; configuration drift across services
App developers
No shared entry point for billing operations
Difficult to apply platform-wide conventions (event naming, error handling)
QA engineers
Cannot reproduce specific subscription states (past-due, trialing, canceled) deterministically
Incomplete test coverage of billing edge cases
Definitions
Term
Definition
Plan
A product pricing tier with an ID, name, interval (monthly/yearly), and unit price
Subscription
A customer’s active relationship to a plan with a status lifecycle
Invoice
A billing document recording charges, discounts, tax, and payment status
Usage record
A metered event reported against a subscription for usage-based billing
Customer portal
A vendor-hosted page where customers manage payment methods and invoices
Billing event
A normalized internal event derived from a vendor webhook payload
Proration
Adjusting charges when a customer changes plans mid-cycle
Current State
Existing Behavior
The design system ships billing-history-table.tsx as a presentational pattern component. It accepts props for rendering invoice rows but has no data-fetching layer. Consuming apps import Stripe SDK directly in API routes, duplicating subscription CRUD, webhook verification, and invoice retrieval logic with inconsistent env var names.
Current Limitations
No shared entry point for billing — each app imports stripe independently.
No platform-standard env var names — apps use STRIPE_KEY, STRIPE_SECRET, STRIPE_SECRET_KEY interchangeably.
No webhook event naming convention — each app names internal events differently.
Storybook stories hard-code invoice data inline rather than using stripe’s own fixture patterns.
Existing Workarounds
Apps copy-paste Stripe integration code from a private template repo.
Storybook stories hard-code invoice data inline rather than using a shared fixture pattern.
Proposed Solution
Summary
Create packages/billing/ with a single src/index.ts that re-exports stripe. The package documents STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET as the platform env var names and billing.{resource}.{action} as the internal event naming convention. No custom interface is built — the library’s API is the interface.
import Stripe, { type Stripe as StripeTypes } from'@dmwd-io/billing';
Single import path (@dmwd-io/billing) for all stripe usage across the platform.
Platform-documented env var names: STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET.
Re-exported stripe types for consuming apps — no need to install stripe separately.
Webhook event naming convention aligned to ADR-065 (billing.subscription.created, billing.invoice.paid, etc.).
User Experience
End users are not directly affected. The package powers billing UI components and API routes behind the scenes.
Developer Experience
Developers import from @dmwd-io/billing instead of directly from stripe. They get the full stripe API with platform conventions documented in one place. The package guarantees a consistent stripe version across all services and eliminates per-app configuration guesswork.
Requirements
ID
Requirement
Priority
Notes
FR-001
@dmwd-io/billing re-exports stripe as its default and named exports
Must
Per ADR-014 — library API is the interface
FR-002
Re-export key stripe TypeScript types for consuming apps
Must
-
FR-003
Document STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET as platform env var names
Model subscription status as a closed union, not an enum
Aligns with TypeScript best practices used elsewhere in the design system
David Holmes
2026-05-26
Include usage methods in the base interface (not a separate provider)
Usage billing is tightly coupled to subscriptions; splitting would fragment the API
David Holmes
2026-06-02
Reframed per ADR-014 (Open Source First): adopt stripe as thin re-export rather than building a custom provider interface. Library API is the interface.
ADR-014 eliminates the need for a custom abstraction when a well-maintained community library exists
David Holmes
Document History
Date
Author
Change
2026-05-26
David Holmes
Initial draft
2026-06-02
David Holmes
Reframed per ADR-014: ship as thin re-export of stripe, drop custom interface.