Spark
Add Spark's Stripe billing portal at /billing. These notes bill individual users from the setup guide, not teams.
Have a Spark license, a Stripe account, and the Stripe CLI available. Run commands in the Laravel application; check the installed Spark/Cashier requirements before changing dependencies.
Composer Repository
File: composer.json (merge with existing repositories)
json
"repositories": [
{
"type": "composer",
"url": "https://spark.laravel.com"
}
]Install
bash
composer require laravel/spark-stripe
php artisan spark:install
php artisan migrateAuthenticate Composer with the Spark account email and a Spark API token when prompted. Keep auth.json out of Git; supply Composer credentials through CI secrets too.
Review the installer's changes to config/spark.php, SparkServiceProvider, the model, and migrations. Keep existing provider registrations and auth features.
Billable Model
File: app/Models/User.php (additions)
Use Spark's trait, not Laravel\Spark\Billable or a second Cashier trait:
php
use Spark\Billable;
// Inside the existing User class:
use Billable;
public function stripeName(): ?string
{
return $this->fullName();
}Merge 'trial_ends_at' => 'datetime' into the existing casts() return array. Keep the password, verification, and two-factor casts, plus the passkey and role traits.
stripeName() supplies the split name to Cashier instead of reading the removed name field. Check the billing portal and Stripe customer details after changing either name field.
Stripe Configuration
File: .env (real values only here; placeholders in .env.example)
dotenv
STRIPE_KEY=pk_test_replace-me
STRIPE_SECRET=sk_test_replace-me
STRIPE_WEBHOOK_SECRET=whsec_replace-me
CASHIER_CURRENCY=usdIn config/spark.php, keep App\Models\User as the billable. Set each plan's monthly_id / yearly_id to Stripe Price IDs, using prices from the same test/live mode as the API keys.
Keep the generated billable resolver and authorization callback in app/Providers/SparkServiceProvider.php; a user must only manage their own billing.
Webhooks
Webhooks are required locally too. Forward Stripe test events to the local application's /spark/webhook endpoint; adjust the Herd URL as needed:
bash
stripe listen --forward-to https://vehub-app.test/spark/webhookUse the listener's signing secret as the local STRIPE_WEBHOOK_SECRET, then clear config:
bash
php artisan config:clearFor production, create the endpoint with the required events using the production application's live keys:
bash
php artisan cashier:webhook --url="https://example.com/spark/webhook"Replace the domain and set that endpoint's signing secret in production. The CLI listener and production endpoint have different secrets. Keep webhook signature verification enabled.
Verify
- In Stripe test mode, open
/billing, subscribe, change plans, and cancel. - Confirm webhooks reach the application and update local subscription records.
- Check name/email synchronization and invoice details in Stripe.
- Confirm guests cannot enter billing and users cannot manage another user's billable.
- Keep a queue worker running when using an asynchronous queue for customer synchronization.
The billing portal does not protect paid application features by itself; enforce subscription access on those routes/actions before launch.