Overview
Add a Stripe plugin that handles subscription lifecycle events via webhooks and exposes subscription status to the rest of the system through the plugin hook system.
Core Features (v1)
1. Stripe Webhook Endpoint
- POST
/api/stripe/webhook — receives Stripe events, verifies signatures using STRIPE_WEBHOOK_SECRET
- Handles these subscription events:
customer.subscription.created
customer.subscription.updated
customer.subscription.deleted
checkout.session.completed
invoice.payment_succeeded
invoice.payment_failed
2. Subscriptions Database Table
id — primary key
userId — FK to users table
stripeCustomerId
stripeSubscriptionId
stripePriceId
status — (active, canceled, past_due, trialing, unpaid, paused)
currentPeriodStart / currentPeriodEnd
cancelAtPeriodEnd — boolean
createdAt / updatedAt
3. Stripe Customer Linking
- API endpoint POST
/api/stripe/create-checkout-session — creates a Stripe Checkout session for the authenticated user
- Automatically links Stripe customer ID to SonicJS user on first checkout
- API endpoint GET
/api/stripe/subscription — returns the current user's subscription status
4. Plugin Configuration
STRIPE_SECRET_KEY — Stripe API key (env binding)
STRIPE_WEBHOOK_SECRET — webhook signature verification secret (env binding)
STRIPE_PRICE_ID — default price ID for checkout (env binding or plugin config)
5. Hook Integration
- Emits
stripe:subscription.created, stripe:subscription.updated, stripe:subscription.deleted hooks so other plugins can react to subscription changes
- Emits
stripe:payment.succeeded and stripe:payment.failed hooks
6. Admin UI
- Admin page listing all subscriptions with status, user, and dates
- Filter by status (active, canceled, past_due, etc.)
- Link to Stripe Dashboard for each subscription
7. Auth Middleware Helper
requireSubscription() middleware that plugins/routes can use to gate access to subscribers only
- Checks subscription status is
active or trialing
Out of Scope for v1
- Multiple plan/tier management
- Usage-based billing / metering
- Stripe Customer Portal embedding
- Coupon / promotion code support
- Team/org subscriptions
- Invoicing UI within admin
Technical Notes
- Uses the plugin builder SDK (
createPluginBuilder)
- Webhook signature verification must use raw request body (not parsed JSON)
- All Stripe API calls use the
stripe npm package
- Routes requiring auth use existing
requireAuth() middleware
- Database model defined via Drizzle schema + Zod validation
Acceptance Criteria
Overview
Add a Stripe plugin that handles subscription lifecycle events via webhooks and exposes subscription status to the rest of the system through the plugin hook system.
Core Features (v1)
1. Stripe Webhook Endpoint
/api/stripe/webhook— receives Stripe events, verifies signatures usingSTRIPE_WEBHOOK_SECRETcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deletedcheckout.session.completedinvoice.payment_succeededinvoice.payment_failed2. Subscriptions Database Table
id— primary keyuserId— FK to users tablestripeCustomerIdstripeSubscriptionIdstripePriceIdstatus— (active, canceled, past_due, trialing, unpaid, paused)currentPeriodStart/currentPeriodEndcancelAtPeriodEnd— booleancreatedAt/updatedAt3. Stripe Customer Linking
/api/stripe/create-checkout-session— creates a Stripe Checkout session for the authenticated user/api/stripe/subscription— returns the current user's subscription status4. Plugin Configuration
STRIPE_SECRET_KEY— Stripe API key (env binding)STRIPE_WEBHOOK_SECRET— webhook signature verification secret (env binding)STRIPE_PRICE_ID— default price ID for checkout (env binding or plugin config)5. Hook Integration
stripe:subscription.created,stripe:subscription.updated,stripe:subscription.deletedhooks so other plugins can react to subscription changesstripe:payment.succeededandstripe:payment.failedhooks6. Admin UI
7. Auth Middleware Helper
requireSubscription()middleware that plugins/routes can use to gate access to subscribers onlyactiveortrialingOut of Scope for v1
Technical Notes
createPluginBuilder)stripenpm packagerequireAuth()middlewareAcceptance Criteria
requireSubscription()middleware correctly gates routes