Lemon Squeezy for Laravel

repository·main·Indexed 20 days ago

https://github.com/lmsqueezy/laravel

A Laravel package to simplify the integration of Lemon Squeezy's payment and subscription services. It provides a 'Billable' trait for models, handles webhook data storage, includes CLI tools for managing products and licenses, and offers a Blade component for the checkout overlay widget.

Tokens
13.1K
Snippets
54
Records
62
Agent score
69%

What's inside lmsqueezy-laravel

  1. Create a new subscription checkout

    main

    To initiate a subscription, use the subscribe method on your billable model, passing the Lemon Squeezy variant ID.

    Once the customer completes the checkout, a SubscriptionCreated webhook will automatically link the subscription to your billable model in the database. You can then access the subscription via the subscription() method.

    use Illuminate
    
    Route::get('/subscribe', function (Request $request) {
        return $request->user()->subscribe('variant-id');
    });
    
    // After checkout, retrieve it:
    $subscription = $user->subscription();
  2. Upgrade to v1.3: Implement the new Order model

    main

    Lemon Squeezy for Laravel v1.3 introduces a new Order model. To enable webhooks to automatically populate this model with new order data, you must run the database migrations.

    Note: Orders created before this upgrade will not be automatically migrated to the new model; they must be handled manually. A sync command is planned for a future release.

    php artisan migrate
  3. Handle Lemon Squeezy webhooks

    main

    The package automatically listens to incoming Lemon Squeezy webhooks and updates your database. To react to these webhooks in your application, you can listen to two general events that contain the full webhook payload:

    1. LemonSqueezy\Laravel\Events\WebhookReceived: Fired immediately when a webhook arrives, before it is processed by the package's WebhookController.
    2. LemonSqueezy\Laravel\Events\WebhookHandled: Fired after the package has successfully processed the webhook.

    Implementation

    Laravel 11+: Listeners are detected automatically.

    Laravel 10 and below: You must register your listener in your EventServiceProvider.

    namespace App\Listeners;
    
    use LemonSqueezy\Laravel\Events\WebhookHandled;
    
    class LemonSqueezyEventListener
    {
        public function handle(WebhookHandled $event): void
        {
            if ($event->payload['meta']['event_name'] === 'subscription_updated') {
                // Handle the incoming event...
            }
        }
    }
  4. Include Lemon JS in your Blade templates

    main
    To use the Lemon Squeezy checkout widget, load the Lemon JS library using the @lemonJS Blade directive inside the <head> section of your application, just before the closing </head> tag.
    <head>
        ...
     
        @lemonJS
    </head>
  5. Register webhook listeners in EventServiceProvider (Laravel 10 and below)

    main

    If you are using Laravel 10 or lower, you must manually map the webhook events to your listeners in the EventServiceProvider.

    namespace App\Providers;
    
    use App\Listeners\LemonSqueezyEventListener;
    use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
    use LemonSqueezy\Laravel\Events\WebhookHandled;
    
    class EventServiceProvider extends ServiceProvider
    {
        protected $listen = [
            WebhookHandled::class => [
                LemonSqueezyEventListener::class,
            ],
        ];
    }
  6. Set up subscription products for plans and intervals

    main

    To manage subscriptions effectively, it is recommended to create a separate Lemon Squeezy product for each plan type (e.g., 'Basic' and 'Pro'). For each product, add multiple variants to represent different billing intervals (e.g., a monthly variant and a yearly variant).

    This structure allows you to use the hasProduct method to check if a user is on a specific plan type regardless of their billing cycle (monthly vs. yearly).

  7. Handle subscription trials

    main

    There are two ways to handle trials:

    1. Generic Trials (No payment required upfront)

    Create a customer and set a trial_ends_at timestamp. This is not attached to a specific subscription.

    • $user->onTrial(): Checks if the user is in a generic trial period.
    • $user->onGenericTrial(): Specifically checks for a generic trial.
    • $user->trialEndsAt(): Returns the trial end date.

    2. Payment-Required Trials

    Configure the trial period within your Lemon Squeezy product settings. When a user subscribes, they enter the trial period and are only charged after it expires.

    • $user->onTrial(): Works on both the billable model and individual subscriptions.
    • $user->hasExpiredTrial(): Checks if a trial has ended.

    Ending Trials Early

    To end a trial immediately and charge the customer upfront, use endTrial() on the subscription. This moves the billing anchor to the current day.

    // Create a generic trial
    $user->createAsCustomer([
        'trial_ends_at' => now()->addDays(10)
    ]);
    
    // Check trial status
    if ($user->onTrial()) {
        $end = $user->trialEndsAt();
    }
    
    // End trial early and charge now
    $user->subscription()->endTrial();
  8. Use the Lemon Squeezy Overlay Widget

    main

    Instead of a full page redirect, you can render a checkout overlay on your current page using the provided Blade component.

    1. Pass the $checkout object to your view.
    2. Use the <x-lemon-button> component with the :href attribute set to the checkout object.

    You can also:

    • Use the dark attribute to render the button in dark mode.
    • Use the withButtonColor('#HEX') method on the checkout object to customize the button color.
    • Use withoutSubscriptionPreview() on the checkout object to hide the "You will be charged..." text for subscriptions.
    {{-- Standard button --}}
    <x-lemon-button :href="$checkout" class="px-8 py-4">
        Buy Product
    </x-lemon-button>
    
    {{-- Dark mode button --}}
    <x-lemon-button :href="$checkout" class="px-8 py-4" dark>
        Buy Product
    </x-lemon-button>
  9. Update customer payment information

    main

    To allow customers to update their credit card or billing details, use the updatePaymentMethodUrl() method to generate a URL.

    Redirecting the user

    You can redirect the user directly to the URL:

    $subscription = $request->user()->subscription();
    return redirect($subscription->updatePaymentMethodUrl());

    Using Lemon.js for an overlay

    For a seamless experience, use Lemon.js to open the URL in an overlay. Pass the URL to your view and trigger it via JavaScript:

    <script defer>
        function updatePM() {
            LemonSqueezy.Url.Open('{!! $paymentMethodUrl !!}');
        }
    </script>
    
    <button onclick="updatePM()">Update payment method</button>
    // In your controller
    $subscription = $request->user()->subscription();
    return view('billing', [
        'paymentMethodUrl' => $subscription->updatePaymentMethodUrl(),
    ]);