Billing Architecture & Technical Specs
Module license lifecycle, dunning automation, Stripe integration with SCA / 3D Secure, billing queue, and real-time usage-limit enforcement.
Capabilities & Performance
License lifecycle
create → validate → trial (optional) → active → expired / suspended → cancelled
License statuses
`active`, `expired`, `suspended`, `cancelled`, `trial`
Billing cycles
monthly, annual
Dunning retry schedule
1st (+1 day), 2nd (+3 days), 3rd (+7 days)
Dunning max retries
3 before auto-suspend
Billing queue
daily per-tenant cron — trial expiry, invoice auto-charge, nightly Stripe reconciliation
Stripe surface
customers, subscriptions, prices, webhooks, SCA-ready with 3D Secure
Limit enforcement
real-time hard block at 100% of the plan limit, configurable per module; currently wired for users (Auth) and products (Commerce)
Feature flags
per-license boolean map controlling module-level access
Trial periods
configurable per module, auto-convert or auto-cancel at expiry
1. License Engine (Full License Lifecycle)
The license engine manages the complete module license lifecycle from creation to cancellation.
What a license tracks:
- Which tenant and which module it applies to
- License type — perpetual, subscription, or trial
- Tier — free, starter, pro, or enterprise
- Status — active, expired, suspended, cancelled, or trial
- Key dates — created, activated, expires, cancelled
- Trial details, when applicable — trial length, start date, and conversion date
- The linked Stripe subscription, customer, and price, plus billing cycle (monthly or annual) and amount
- A feature-flag map and a usage-limits map, both scoped to that license
- Where the license originated — marketplace signup, admin action, or migration — and, on upgrade or downgrade, a reference back to the previous license so the lineage is never lost
Tenants and integrators can look up the active license for a module, or look one up by its linked Stripe subscription, at any time — see the Quick Start guide for the exact endpoints. A compact "license state" summary is also available for frontend use, covering whether a license exists, its type/tier/status, trial countdown (days remaining, start/expiry dates, whether it will auto-convert), enabled features and limits, and the next billing date and amount.
Trial management: Trial length is configurable per module (14 days by default). The trial start date is recorded when the trial begins, and the license automatically converts to a paid subscription once payment is added, or expires gracefully if it isn't.
Upgrades and downgrades: Changing tiers creates a new license record linked back to the previous one, migrates any data the new tier requires, and — where proration is enabled — charges or credits the price difference either immediately or at the next renewal.
Feature flags per license: Each license carries its own map of enabled features — for example API access, webhooks, multi-user support, SSO, advanced analytics, and custom integrations — alongside usage limits such as max users, max storage, and max API calls. Higher tiers unlock more of the map by default, and individual flags can be overridden per license.
2. Dunning Engine (Failed Payment Automation)
| Stage | Subject | Purpose |
|---|---|---|
| First notice | "Payment Failed - Action Required" | Prompts the customer to update their payment method |
| Second notice | "Second Payment Attempt Scheduled" | Warns that another retry is coming in a few days |
| Final notice | "Final Payment Notice" | Last warning before the account is suspended |
| Suspended | "Service Suspended" | Confirms suspension and explains how to reactivate |
3. Billing Queue (Automated Job Processing)
The billing job queue manages background jobs for all billing operations.
Job Types:
- Retry a failed payment on the dunning schedule
- Generate invoices on each subscription's billing cycle
- Reconcile subscriptions against Stripe on a nightly basis
- Clean up expired trials
A daily cron job walks every tenant, expiring trials and auto-charging any invoice that's open, due, and has a payment method on file — up to 100 due invoices per run. Reconciliation against Stripe runs on the same nightly cadence to catch any drift between Aeion and your provider.
4. Limit Enforcer (Usage Limits)
The limit enforcer monitors and enforces module usage limits.
Limit key shape: any maxX key on a license's limits map (e.g. maxUsers, maxProducts, maxContacts) — the mechanism is generic, so any module can call it for any count-based limit. Two call sites are wired in today: max users (Auth, on user creation) and max products (Commerce, on product creation). Other modules — CRM, BI, Marketing, Fleet — aren't wired to this enforcer yet.
How enforcement works: Usage is checked in real time against the tenant's plan limits on the relevant create operation. If a module has no limit configured for that key, usage is unrestricted. Once usage reaches the plan limit, the operation is hard-blocked with an upgrade message. There's no separate warning tier today — a limit either isn't reached (allowed) or is reached (blocked).
5. Subscription Lifecycle Management
Aeion Billing manages subscription lifecycle events end to end.
Subscription Status Flow:
`
active → [payment_failed] → past_due → cancelled ↓ ↓ ↓ ↓ ↓ ↓ [expired] → [trial] → [suspended] → cancelled
`
Status changes: Every status transition is timestamped and emits an event so other modules can react — no polling required.
Renewal processing: When a subscription's renewal date arrives, Aeion checks whether auto-renew is enabled. If it isn't, the subscription is cancelled. If it is, an invoice is generated for the upcoming period and a charge is attempted through the tenant's configured payment provider.
6. Stripe Integration
Aeion Billing integrates with Stripe for payment processing.
What Aeion manages in Stripe: Aeion creates and manages the corresponding Stripe customer, subscription, and price objects behind the scenes as part of the license lifecycle — you don't need to touch the Stripe dashboard for routine plan changes.
Webhook Handling: Stripe webhooks map directly to license and subscription events:
customer.subscription.created— activates the licensecustomer.subscription.updated— syncs subscription changescustomer.subscription.deleted— deactivates the licensecustomer.subscription.paused/resumed/trial_will_end— keeps the license status in step with the subscription's pause/resume/trial-ending stateinvoice.paid— marks the invoice paid and confirms the licenseinvoice.payment_failed— triggers the dunning flow
Linking a subscription: Once a Stripe subscription is created, Aeion links it to the license record and marks the license active.