Skip to content

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 migrate

Authenticate 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=usd

In 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/webhook

Use the listener's signing secret as the local STRIPE_WEBHOOK_SECRET, then clear config:

bash
php artisan config:clear

For 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.

References ​