Billing (Stripe)
Stripe via Laravel Cashier 16. Three plans (Free, Pro, Enterprise), monthly/yearly.
Good to know
The billing module is fully optional. If you don't need subscriptions, remove it via npx stacktura init and Stripe will be completely stripped from the codebase.
Stripe Setup Guide
Connect Stripe to your Stacktura project in five steps.
Create a Stripe account
Go to dashboard.stripe.com and sign up. You'll start in test mode by default.
Get your API keys
In the Stripe Dashboard, go to Developers > API keys. Copy both keys into backend/.env:
STRIPE_KEY=pk_test_xxxxxxxxxxxxx
STRIPE_SECRET=sk_test_xxxxxxxxxxxxx Create your Products and Prices
In the Stripe Dashboard, go to Product catalog > Add product. Create one product per plan (Pro, Enterprise) with both monthly and yearly prices.
Copy each Price ID (price_xxx) into backend/.env:
STRIPE_PRICE_PRO_MONTHLY=price_xxxxxxxxxxxxx
STRIPE_PRICE_PRO_YEARLY=price_xxxxxxxxxxxxx
STRIPE_PRICE_ENTERPRISE_MONTHLY=price_xxxxxxxxxxxxx
STRIPE_PRICE_ENTERPRISE_YEARLY=price_xxxxxxxxxxxxx Plan names and features are defined in backend/config/plans.php.
Set up webhooks (local development)
Install the Stripe CLI, then forward events to your local backend:
stripe listen --forward-to localhost:8000/api/stripe/webhook The CLI outputs a whsec_xxx signing secret. Copy it to your .env:
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx Set up webhooks (production)
In the Stripe Dashboard, go to Developers > Webhooks > Add endpoint:
- URL:
https://api.yourdomain.com/api/stripe/webhook - Events to listen:
customer.subscription.created,updated,deleted,customer.updated,customer.deleted,invoice.payment_action_required,invoice.payment_succeeded,invoice.payment_failed,payment_method.automatically_updated
Copy the Signing secret from the webhook details into your production STRIPE_WEBHOOK_SECRET.
Test Cards
Use these cards in Stripe test mode. Any future date and any 3-digit CVC.
| Scenario | Card Number | Result |
|---|---|---|
| Successful payment | 4242 4242 4242 4242 | Succeeds |
| 3D Secure required | 4000 0025 0003 1228 | Requires authentication |
| Declined | 4000 0000 0000 0002 | Card declined |
| Insufficient funds | 4000 0000 0000 9995 | Insufficient funds |
| Expired card | 4000 0000 0000 0069 | Expired card |
Going Live
Before you go live
Live and test mode use different API keys, Price IDs, and webhook secrets. You need to re-create everything in live mode.
- In the Stripe Dashboard, toggle Test mode off (top right)
- Copy your live API keys (
pk_live_,sk_live_) into your production.env - Re-create your products/prices in live mode and update the
STRIPE_PRICE_*values - Create a live webhook endpoint and update
STRIPE_WEBHOOK_SECRET - Make sure your site runs over HTTPS (required by Stripe)
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/billing/plans | List plans |
| GET | /api/billing/subscription | Current subscription |
| POST | /api/billing/checkout | Create Checkout session |
| POST | /api/billing/portal | Customer Portal session |
| POST | /api/billing/subscription/swap | Switch plan |
| POST | /api/billing/subscription/cancel | Cancel subscription |
| POST | /api/billing/subscription/resume | Resume subscription |
| POST | /api/stripe/webhook | Webhook handler |
Webhook Events (9)
customer.subscription.created, updated, deleted,
customer.updated, customer.deleted,
payment_method.automatically_updated,
invoice.payment_action_required, succeeded, failed.