Billing & Plans
Configure Stripe billing, subscription plans, plan limits, and handle upgrades and downgrades in ShopySeed.
Billing & Plans
ShopySeed includes a complete Stripe billing integration with subscription management, checkout, customer portal, and webhook handling.
Plans Configuration
Plans are defined in apps/api/src/billing/config/plans.ts:
export const PLANS: Plans = {
free: {
name: 'Free',
stripePriceId: null,
limits: { members: 3, storage: '100MB' },
features: ['Up to 3 members', '100MB storage', 'Basic support'],
},
pro: {
name: 'Pro',
stripePriceId: null, // Loaded from STRIPE_PRO_PRICE_ID env var
price: 29,
limits: { members: 10, storage: '10GB' },
features: ['Up to 10 members', '10GB storage', 'Priority support', 'API access'],
},
enterprise: {
name: 'Enterprise',
stripePriceId: null, // Loaded from STRIPE_ENTERPRISE_PRICE_ID env var
price: 99,
limits: { members: -1, storage: '100GB' }, // -1 = unlimited
features: ['Unlimited members', '100GB storage', 'Dedicated support', 'API access', 'SSO', 'Custom integrations'],
},
};Customizing Plans
To modify plans, edit the PLANS object. Each plan needs:
- name: Display name
- stripePriceId: Stripe Price ID (set via env var for paid plans)
- price: Monthly price in USD (null for free)
- limits: Resource limits (
members: -1for unlimited) - features: Feature list displayed on the pricing page
Stripe Setup
1. Create Products & Prices in Stripe
In your Stripe Dashboard:
- Create a product for each paid plan (Pro, Enterprise)
- Add a recurring price to each product
- Copy the Price IDs
2. Configure Environment Variables
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRO_PRICE_ID=price_...
STRIPE_ENTERPRISE_PRICE_ID=price_...
FRONTEND_URL=http://localhost:30103. Set Up Webhooks
Create a webhook endpoint in Stripe pointing to: {API_URL}/billing/webhooks
Subscribe to these events:
checkout.session.completedinvoice.paidinvoice.payment_failedcustomer.subscription.updatedcustomer.subscription.deleted
For local development, use the Stripe CLI:
stripe listen --forward-to localhost:3011/api/billing/webhooksSubscription Flow
Upgrade (Free → Pro/Enterprise)
- User clicks "Choose This Plan" on the pricing page or "Upgrade" in billing settings
- Backend creates a Stripe Checkout Session with the plan's price ID
- User completes payment on Stripe's hosted checkout page
- Stripe fires
checkout.session.completedwebhook - Backend updates the subscription in the database via
syncSubscription()
Downgrade
Downgrades are handled through the Stripe Customer Portal:
- User clicks "Manage Billing" in dashboard
- Backend creates a Stripe Billing Portal session
- User changes their plan in the portal
- Stripe fires
customer.subscription.updatedwebhook - Backend syncs the new plan and limits
Downgrade behavior (Option B):
- Existing members are not removed
- If the org exceeds the new plan's member limit, new invitations are blocked
- A warning banner appears on the Team page
- The org works normally until they reduce members or upgrade
Cancellation
When a subscription is canceled:
- Stripe fires
customer.subscription.deletedwebhook - Backend sets the plan back to
freeand status toCANCELED - Member limits revert to free plan limits (3 members)
Plan Limits Enforcement
The LimitsService enforces plan limits:
- Member invitations: Checked before sending an invitation and before accepting one
- Guard-based: Use
@CheckLimits({ type: 'members' })decorator on any endpoint - Programmatic: Call
limitsService.enforceMemberLimit(orgId)in service logic
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /billing/plans | Get available plans (public) |
GET | /billing/subscription | Get current subscription |
POST | /billing/checkout | Create Stripe checkout session |
POST | /billing/portal | Create Stripe billing portal session |
POST | /billing/webhooks | Stripe webhook handler |
Pricing Page
The pricing page (/pricing) dynamically loads plans from the API. All plans display their price (€0/month for Free) with a consistent "Get Started" CTA that redirects to registration (or dashboard for logged-in users).