asa install payments-basic

Billing that survives webhook storms and payment failures.

Stripe subscription management with Postgres inbox pattern, entitlement engine, dunning-safe access, and automatic reconciliation. Not a Stripe wrapper — a production billing system.

See What You Get →
$ asa install payments-basic

Auto-installs dependencies: db-basic (auto), auth-basic (auto)

What You Get

Fully functional slices — not TODO skeletons.

S

subscribe

Stripe Checkout session creation with customer management. Handles new and returning customers, redirects to Checkout.

C

cancel

Cancel subscription at period end. User keeps access until billing period expires. Reactivation supported.

W

webhook

Enqueue-only Stripe webhook handler. Verifies signature, stores event in webhook_events table, returns 200 immediately. No inline processing.

C

check-limits

Entitlement checks based on current subscription. Plan-aware feature gating with dunning-safe access during grace periods.

Generated File Map

Every file is real, functional code you own.

domains/billing/subscribe/
domains/billing/cancel/
domains/billing/webhook/
domains/billing/check-limits/
shared/billing/stripe-client.ts
shared/billing/plans.ts
shared/billing/entitlements.ts
shared/billing/guards.ts
shared/billing/webhook-processor.ts
shared/billing/reconciliation.ts
shared/db/migrations/002_subscriptions.sql
shared/db/migrations/003_entitlements.sql
shared/db/migrations/003b_webhook_events.sql

Security Guarantees

Built-in protection — not an afterthought.

Webhook signature verification

Every webhook event is verified against Stripe's signature before processing. Raw body is read before JSON parsing.

Postgres inbox pattern

Webhook handler stores events and returns 200 immediately. Processing happens asynchronously with locking, retries, and idempotency.

Idempotent event processing

Events are deduplicated by stripe_event_id. Duplicate delivery is safely ignored. Always-fetch-current-state pattern.

Entitlement separation

Access checks use the entitlement engine, not raw Stripe subscription status. Supports dunning-safe grace periods.

Reconciliation job

Periodic job compares Stripe subscription state with local DB. Detects and repairs drift automatically.

No inline plan checks

Lint rule ENT-001 blocks direct plan comparisons (plan === 'pro'). Must use requireEntitlement() or canAccess().

What This Prevents in Production

Real problems this module eliminates before they cost you customers.

Lost webhook events

Inline webhook processing times out at 10s. Stripe retries, your DB gets inconsistent. Customers lose access or get double-charged.

Stripe/DB drift

Manual Stripe changes, missed webhooks, or server downtime cause subscription status to diverge. Users pay but can't access features.

Hardcoded plan checks

AI tools generate plan === 'pro' everywhere. One plan rename breaks all access control. No grace periods, no trial logic.

No dunning grace period

Payment fails → instant lockout. Customer loses work-in-progress. Churn spikes instead of retry recovery.

Duplicate event processing

Stripe sends duplicate webhooks. Without idempotency, users get double-charged or subscriptions get corrupted.

Extension Points

Your code. Your rules. Extend when ready.

  • Add usage-based metering by extending the entitlements engine with usage counters
  • Add multiple Stripe products by extending plans.ts with additional price mappings
  • Add billing portal by extending the subscribe handler with Stripe Customer Portal
  • Add invoice history by querying Stripe API from a new slice
  • Add payment method management by extending the billing domain
  • Swap processor scheduling: Supabase Cron, Vercel Cron, or custom

Protected by 22 Lint Rules

Every module is enforced by ASA CLI's tiered lint engine. 8 blockers catch critical security issues. 8 warnings flag architectural risks. 6 info rules guide best practices.

8
Blockers
8
Warnings
6
Info

Run asa lint anytime. Runs in CI too.

Production billing in one command.

Install payments-basic and stop worrying about webhook reliability.

New app? Start with Build Right. Existing app? Start with a Quick Scan before stabilization.

View All Foundation Modules →