Billing
Customer, Product, Plan, Price, Subscription, Invoice, Payment — revenue powered by Stripe.
All Billing entities are Stripe-backed. Creating a Subscription in headless.ly creates a Stripe subscription. Stripe webhooks flow back as events.
Customer
Stripe Customer — the billing identity. Links an Organization to Stripe.
import { Noun } from 'digital-objects'
export const Customer = Noun('Customer', {
name: 'string!',
email: 'string!#',
organization: '-> Organization',
stripeCustomerId: 'string##',
subscriptions: '<- Subscription.customer[]',
invoices: '<- Invoice.customer[]',
payments: '<- Payment.customer[]',
paymentMethod: 'string',
currency: 'string',
taxExempt: 'string',
})Product
What you sell — software, services, addons, bundles.
export const Product = Noun('Product', {
name: 'string!',
slug: 'string##',
description: 'string',
tagline: 'string',
type: 'Software | Service | Addon | Bundle',
icon: 'string',
image: 'string',
features: 'string',
highlights: 'string',
status: 'Draft | Active | Archived',
visibility: 'Public | Private | Hidden',
featured: 'string',
plans: '<- Plan.product[]',
stripeProductId: 'string##',
})Plan
Pricing tiers with trial configuration and feature limits.
export const Plan = Noun('Plan', {
name: 'string!',
slug: 'string##',
description: 'string',
product: '-> Product.plans',
prices: '<- Price.plan[]',
trialDays: 'number',
features: 'string',
limits: 'string',
status: 'Draft | Active | Grandfathered | Archived',
isDefault: 'string',
isFree: 'string',
isEnterprise: 'string',
badge: 'string',
order: 'number',
})Price
Pricing configuration — maps to Stripe Prices.
export const Price = Noun('Price', {
amount: 'number!',
currency: 'string',
interval: 'Monthly | Quarterly | Yearly | OneTime',
intervalCount: 'number',
originalAmount: 'number',
discountPercent: 'number',
active: 'string',
plan: '-> Plan.prices',
stripeId: 'string##',
})| Interval | Description |
|---|---|
Monthly | Recurring monthly charge |
Quarterly | Recurring quarterly charge |
Yearly | Recurring yearly charge |
OneTime | Single purchase |
Subscription
Active paying relationships.
export const Subscription = Noun('Subscription', {
status: 'Active | PastDue | Canceled | Trialing | Paused | Incomplete',
organization: '-> Organization.subscriptions',
customer: '-> Customer.subscriptions',
plan: '-> Plan',
currentPeriodStart: 'datetime!',
currentPeriodEnd: 'datetime!',
cancelAtPeriodEnd: 'string',
trialStart: 'datetime',
trialEnd: 'datetime',
startedAt: 'datetime!',
canceledAt: 'datetime',
pausedAt: 'datetime',
resumesAt: 'datetime',
endedAt: 'datetime',
cancelReason: 'string',
cancelFeedback: 'string',
quantity: 'number',
paymentMethod: 'string',
collectionMethod: 'string',
stripeSubscriptionId: 'string##',
stripeCustomerId: 'string',
pause: 'Paused',
cancel: 'Cancelled',
reactivate: 'Reactivated',
upgrade: 'Upgraded',
downgrade: 'Downgraded',
})| Verb | Event | Description |
|---|---|---|
pause | Paused | Temporarily suspend billing |
cancel | Cancelled | End the subscription |
reactivate | Reactivated | Restart a cancelled subscription |
upgrade | Upgraded | Move to a higher-value plan |
downgrade | Downgraded | Move to a lower-value plan |
Invoice
Bills — monthly/annual.
export const Invoice = Noun('Invoice', {
number: 'string!##',
organization: '-> Organization',
customer: '-> Customer.invoices',
subscription: '-> Subscription',
subtotal: 'number!',
tax: 'number',
discount: 'number',
total: 'number!',
amountPaid: 'number',
amountDue: 'number!',
currency: 'string',
status: 'Draft | Open | Paid | Void | Uncollectible',
periodStart: 'datetime',
periodEnd: 'datetime',
issuedAt: 'datetime',
dueAt: 'datetime',
paidAt: 'datetime',
voidedAt: 'datetime',
lineItems: 'string',
receiptUrl: 'string',
pdfUrl: 'string',
hostedUrl: 'string',
stripeInvoiceId: 'string##',
pay: 'Paid',
void: 'Voided',
})| Verb | Event | Description |
|---|---|---|
pay | Paid | Mark invoice as paid |
void | Voided | Void the invoice |
Payment
Money movement — charges, refunds.
export const Payment = Noun('Payment', {
amount: 'number!',
currency: 'string',
status: 'Pending | Succeeded | Failed | Refunded',
method: 'string',
customer: '-> Customer.payments',
invoice: '-> Invoice',
stripePaymentId: 'string##',
refund: 'Refunded',
})| Verb | Event | Description |
|---|---|---|
refund | Refunded | Refund the payment |