Subscription & Payments
Stripe integration, plan tiers, webhooks, and feature gating
Subscription & Payments
For full endpoint details (request/response schemas, examples), see the interactive API docs at
/api/doc.
What's Included
- Three plan tiers (Free, Starter, Pro) with configurable features
- Stripe Checkout for both recurring and one-time payments
- Webhook handling for 5 Stripe events
- Feature gating via
FeatureAccessChecker - Guest and authenticated checkout support
Plan Tiers
| Plan | Features |
|---|---|
| Free | BasicAccess |
| Starter | BasicAccess, AdvancedReports, ApiAccess |
| Pro | BasicAccess, AdvancedReports, ApiAccess, PrioritySupport, CustomIntegrations |
Every user starts on the Free plan. Paid plans are activated after Stripe checkout completion.
Feature Access
Use FeatureAccessChecker to gate features in your code:
// Check if user has a feature
$checker->hasFeature($userId, Feature::AdvancedReports); // bool
// Throw if feature not available
$checker->requireFeature($userId, Feature::ApiAccess); // throws if denied
// Get the user's effective plan
$checker->getEffectivePlanType($userId); // PlanType::Free if inactive
// Get all available features
$checker->getAvailableFeatures($userId); // Feature[]
Stripe Setup
1. Create a Stripe Account
Sign up at stripe.com and get your API keys from the Developers section.
2. Set Environment Variables
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_SUCCESS_URL=https://yourapp.com/payment/success
STRIPE_CANCEL_URL=https://yourapp.com/payment/cancel
3. Configure Plans
Edit config/packages/stripe.yaml to define your plan tiers and prices. See Configuration.
4. Sync Plans to Stripe
docker compose exec php bin/console app:stripe:sync-plans
This creates or updates Stripe Products and Prices to match your config. Use --dry-run to preview changes.
5. Set Up Webhook (Production)
In the Stripe Dashboard > Developers > Webhooks:
- Add endpoint:
https://yourdomain.com/api/v1/webhooks/stripe - Select events:
checkout.session.completed,customer.subscription.updated,customer.subscription.deleted,invoice.payment_failed,invoice.paid - Copy the signing secret to
STRIPE_WEBHOOK_SECRET
6. Local Testing with Stripe CLI
# Install Stripe CLI, then:
stripe listen --forward-to localhost/api/v1/webhooks/stripe
# Copy the webhook signing secret printed by the CLI to your .env.local
STRIPE_WEBHOOK_SECRET=whsec_...
Webhook Events
| Stripe Event | Action |
|---|---|
checkout.session.completed | Creates subscription (free → paid upgrade) |
customer.subscription.updated | Updates plan/status |
customer.subscription.deleted | Cancels subscription |
invoice.payment_failed | Marks subscription as past due |
invoice.paid | Reactivates subscription after successful payment |
Plans are fetched from Stripe and cached for 1 hour. Checkout supports both authenticated users (email pre-filled, user_id in metadata) and guest users (Stripe collects email).
Subscription Lifecycle
User signs up → Free plan (automatic)
|
v
Checkout → Stripe payment → Webhook → Paid plan (Starter/Pro)
|
+----------+----------+
v v v
Recurring One-time Cancel
| | |
Invoice cycle Lifetime Downgrade
| access to Free
+----+----+
v v
Paid Failed
| |
Active Past Due → Expired → Free